Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 31 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
| CloudflareFeaturesManager | |
0.00% |
0 / 31 |
|
0.00% |
0 / 5 |
156 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
| on_image_optimization_change | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| on_fonts_optimization_change | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| on_site_capabilities_change | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
| update_htaccess_header | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
56 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * CloudflareFeaturesManager |
| 4 | * |
| 5 | * Tracks Cloudflare-related optimization toggles (Polish, Mirage, Fonts) and |
| 6 | * manages a single .htaccess fragment that sets a sticky cookie indicating the |
| 7 | * current optimization tuple. Uses the centralized HtaccessApi to ensure safe, |
| 8 | * debounced writes and conflict-free composition with other fragments. |
| 9 | * |
| 10 | * @package NewfoldLabs\WP\Module\Performance\Cloudflare |
| 11 | * @since 1.0.0 |
| 12 | */ |
| 13 | |
| 14 | namespace NewfoldLabs\WP\Module\Performance\Cloudflare; |
| 15 | |
| 16 | use NewfoldLabs\WP\Module\Performance\Fonts\FontSettings; |
| 17 | use NewfoldLabs\WP\Module\Performance\Images\ImageSettings; |
| 18 | use NewfoldLabs\WP\Module\Htaccess\Api as HtaccessApi; |
| 19 | use NewfoldLabs\WP\Module\Performance\Cloudflare\Fragments\CloudflareOptimizationHeaderFragment; |
| 20 | |
| 21 | /** |
| 22 | * Handles detection and tracking of Cloudflare Polish, Mirage, and Font Optimization. |
| 23 | * |
| 24 | * Listens to option/transient changes and registers/unregisters a single |
| 25 | * fragment that sets a cookie reflecting which CF features are enabled. |
| 26 | * |
| 27 | * @since 1.0.0 |
| 28 | */ |
| 29 | class CloudflareFeaturesManager { |
| 30 | |
| 31 | /** |
| 32 | * Human-friendly marker printed in BEGIN/END comments in .htaccess. |
| 33 | * |
| 34 | * @var string |
| 35 | */ |
| 36 | private const MARKER = 'Newfold CF Optimization Header'; |
| 37 | |
| 38 | /** |
| 39 | * Globally-unique identifier for the Cloudflare optimization header fragment. |
| 40 | * |
| 41 | * @var string |
| 42 | */ |
| 43 | private const FRAGMENT_ID = 'nfd.cloudflare.optimization.header'; |
| 44 | |
| 45 | /** |
| 46 | * Constructor to register hooks for settings changes. |
| 47 | * |
| 48 | * @since 1.0.0 |
| 49 | */ |
| 50 | public function __construct() { |
| 51 | add_action( 'update_option_nfd_image_optimization', array( $this, 'on_image_optimization_change' ), 10, 2 ); |
| 52 | add_action( 'add_option_nfd_image_optimization', array( $this, 'on_image_optimization_change' ), 10, 2 ); |
| 53 | add_action( 'update_option_nfd_fonts_optimization', array( $this, 'on_fonts_optimization_change' ), 10, 2 ); |
| 54 | add_action( 'add_option_nfd_fonts_optimization', array( $this, 'on_fonts_optimization_change' ), 10, 2 ); |
| 55 | add_action( 'set_transient_nfd_site_capabilities', array( $this, 'on_site_capabilities_change' ), 10, 2 ); |
| 56 | } |
| 57 | |
| 58 | /** |
| 59 | * Handles image optimization setting changes. |
| 60 | * |
| 61 | * @since 1.0.0 |
| 62 | * |
| 63 | * @param mixed $old_value Previous value. |
| 64 | * @param mixed $new_value New value. |
| 65 | * @return void |
| 66 | */ |
| 67 | public function on_image_optimization_change( $old_value, $new_value ): void { |
| 68 | $this->update_htaccess_header( $new_value, get_option( 'nfd_fonts_optimization', array() ) ); |
| 69 | } |
| 70 | |
| 71 | /** |
| 72 | * Handles font optimization setting changes. |
| 73 | * |
| 74 | * @since 1.0.0 |
| 75 | * |
| 76 | * @param mixed $old_value Previous value. |
| 77 | * @param mixed $new_value New value. |
| 78 | * @return void |
| 79 | */ |
| 80 | public function on_fonts_optimization_change( $old_value, $new_value ): void { |
| 81 | $this->update_htaccess_header( get_option( 'nfd_image_optimization', array() ), $new_value ); |
| 82 | } |
| 83 | |
| 84 | /** |
| 85 | * Callback for when the `nfd_site_capabilities` transient is set. |
| 86 | * |
| 87 | * Triggers a refresh of image and font optimization settings based on updated site capabilities. |
| 88 | * |
| 89 | * @since 1.0.0 |
| 90 | * |
| 91 | * @param mixed $value The value being set in the transient. |
| 92 | * @return void |
| 93 | */ |
| 94 | public function on_site_capabilities_change( $value ): void { |
| 95 | if ( is_array( $value ) ) { |
| 96 | ImageSettings::maybe_refresh_with_capabilities( $value ); |
| 97 | FontSettings::maybe_refresh_with_capabilities( $value ); |
| 98 | $this->update_htaccess_header( get_option( 'nfd_image_optimization', array() ), get_option( 'nfd_fonts_optimization', array() ) ); |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | /** |
| 103 | * Ensure the fragment reflects current optimization state. |
| 104 | * |
| 105 | * If no CF features are enabled, the fragment is unregistered. Otherwise, |
| 106 | * a deterministic cookie value is computed and a fragment is registered |
| 107 | * that sets the cookie when absent/mismatched. |
| 108 | * |
| 109 | * @since 1.0.0 |
| 110 | * |
| 111 | * @param array $image_settings Array-like image optimization settings. |
| 112 | * @param array $fonts_settings Array-like font optimization settings. |
| 113 | * @return void |
| 114 | */ |
| 115 | private function update_htaccess_header( $image_settings, $fonts_settings ): void { |
| 116 | $images_cloudflare = isset( $image_settings['cloudflare'] ) ? (array) $image_settings['cloudflare'] : array(); |
| 117 | $fonts_cloudflare = isset( $fonts_settings['cloudflare'] ) ? (array) $fonts_settings['cloudflare'] : array(); |
| 118 | |
| 119 | $mirage_enabled = ! empty( $images_cloudflare['mirage']['value'] ); |
| 120 | $polish_enabled = ! empty( $images_cloudflare['polish']['value'] ); |
| 121 | $fonts_enabled_flag = ! empty( $fonts_cloudflare['fonts']['value'] ); |
| 122 | |
| 123 | // Build a short, stable header/cookie value for the enabled set. |
| 124 | $mirage_hash = $mirage_enabled ? substr( sha1( 'mirage' ), 0, 8 ) : ''; |
| 125 | $polish_hash = $polish_enabled ? substr( sha1( 'polish' ), 0, 8 ) : ''; |
| 126 | $fonts_hash = $fonts_enabled_flag ? substr( sha1( 'fonts' ), 0, 8 ) : ''; |
| 127 | $header_value = "{$mirage_hash}{$polish_hash}{$fonts_hash}"; |
| 128 | |
| 129 | // Remove any existing fragment first to avoid duplicates. |
| 130 | HtaccessApi::unregister( self::FRAGMENT_ID ); |
| 131 | |
| 132 | // If no features enabled, return. |
| 133 | if ( '' === $header_value ) { |
| 134 | return; |
| 135 | } |
| 136 | |
| 137 | // Register/replace the fragment with the current header value. |
| 138 | HtaccessApi::register( |
| 139 | new CloudflareOptimizationHeaderFragment( |
| 140 | self::FRAGMENT_ID, |
| 141 | self::MARKER, |
| 142 | $header_value |
| 143 | ), |
| 144 | true // queue apply to coalesce writes |
| 145 | ); |
| 146 | } |
| 147 | } |