Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
PerformanceLifecycleHooks
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 9
420
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 plugin_hooks
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 hooks
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 on_activation
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 on_deactivation
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 on_cache_level_change
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
20
 get_response_header_manager
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 nfd_force_disable_epc_options
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
30
 nfd_sync_epc_from_brand
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * PerformanceLifecycleHooks
4 *
5 * Unified lifecycle wiring for Performance features:
6 * - Cache headers (File + Browser types, ResponseHeaderManager)
7 * - Skip404 rules (.htaccess fragment via HtaccessApi)
8 *
9 * @package NewfoldLabs\WP\Module\Performance
10 * @since 1.0.0
11 */
12
13namespace NewfoldLabs\WP\Module\Performance;
14
15use NewfoldLabs\WP\Module\Performance\Cache\CacheManager;
16use NewfoldLabs\WP\Module\Performance\Cache\ResponseHeaderManager;
17use NewfoldLabs\WP\ModuleLoader\Container;
18use NewfoldLabs\WP\Module\Performance\OptionListener;
19use NewfoldLabs\WP\Module\Performance\Cache\Types\Browser;
20use NewfoldLabs\WP\Module\Performance\Cache\Types\File;
21use NewfoldLabs\WP\Module\Performance\Images\ImageRewriteHandler;
22use NewfoldLabs\WP\Module\Performance\Skip404\Skip404;
23
24use function NewfoldLabs\WP\Module\Performance\get_cache_level;
25
26/**
27 * Class PerformanceLifecycleHooks
28 *
29 * Combines lifecycle hooks for Cache and Skip404 so you can bootstrap once.
30 *
31 * @since 1.0.0
32 */
33class PerformanceLifecycleHooks {
34
35    /**
36     * Dependency injection container.
37     *
38     * @var Container
39     */
40    protected $container;
41
42    /**
43     * Constructor.
44     */
45    public function __construct() {
46        if ( function_exists( 'add_action' ) ) {
47            add_action( 'newfold_container_set', array( $this, 'plugin_hooks' ) );
48            add_action( 'plugins_loaded', array( $this, 'hooks' ) );
49
50            // Keep Cache level header in sync with option changes.
51            new OptionListener( CacheManager::OPTION_CACHE_LEVEL, array( $this, 'on_cache_level_change' ) );
52        }
53    }
54
55    /**
56     * Hooks for plugin activation/deactivation.
57     *
58     * @param Container $container From the plugin.
59     * @return void
60     */
61    public function plugin_hooks( Container $container ) {
62        $this->container = $container;
63
64        register_activation_hook(
65            $container->plugin()->file,
66            array( $this, 'on_activation' )
67        );
68
69        register_deactivation_hook(
70            $container->plugin()->file,
71            array( $this, 'on_deactivation' )
72        );
73    }
74
75    /**
76     * Add feature enable/disable hooks.
77     *
78     * @return void
79     */
80    public function hooks() {
81        add_action(
82            'newfold/features/action/onEnable:performance',
83            array( $this, 'on_activation' )
84        );
85
86        add_action(
87            'newfold/features/action/onDisable:performance',
88            array( $this, 'on_deactivation' )
89        );
90    }
91
92    /**
93     * Activation/Enable: apply Cache + Skip404.
94     *
95     * @since 1.0.0
96     * @return void
97     */
98    public function on_activation() {
99        // Cache feature bits.
100        File::on_activation();
101        Browser::on_activation();
102
103        // Image rewrite rules.
104        ImageRewriteHandler::on_activation();
105
106        // Skip404 rules based on current option value.
107        Skip404::maybe_add_rules( Skip404::get_value() );
108
109        // Ensure EPC is off and removes its rules
110        $this->nfd_force_disable_epc_options();
111    }
112
113    /**
114     * Deactivation/Disable: remove Cache + Skip404.
115     *
116     * @since 1.0.0
117     * @return void
118     */
119    public function on_deactivation() {
120        // Cache feature bits.
121        File::on_deactivation();
122        Browser::on_deactivation();
123
124        // Remove image rewrite rules.
125        ImageRewriteHandler::on_deactivation();
126
127        // Remove all headers written by ResponseHeaderManager.
128        $response_header_manager = $this->get_response_header_manager();
129        if ( $response_header_manager ) {
130            $response_header_manager->remove_all_headers();
131        }
132
133        // Remove Skip404 rules.
134        Skip404::remove_rules();
135
136        // Hand settings back to EPC to match the brand plugin's current values
137        $this->nfd_sync_epc_from_brand();
138    }
139
140    /**
141     * On cache level change, update the response header and clean up legacy EPC option.
142     *
143     * @return void
144     */
145    public function on_cache_level_change() {
146
147        // Remove the old option from EPC, if it exists.
148        if ( $this->container && $this->container->get( 'hasMustUsePlugin' ) && absint( get_option( 'endurance_cache_level', 0 ) ) ) {
149            update_option( 'endurance_cache_level', 0 );
150            delete_option( 'endurance_cache_level' );
151        }
152    }
153
154    /**
155     * Helper to fetch ResponseHeaderManager from the container (if available).
156     *
157     * @return \NewfoldLabs\WP\Module\Performance\ResponseHeaderManager|null
158     */
159    protected function get_response_header_manager() {
160        return new ResponseHeaderManager();
161    }
162
163    /**
164     * Force Endurance Page Cache off by clamping its options to 0.
165     * Triggers EPC to remove its own rules, then tidies the options.
166     */
167    private function nfd_force_disable_epc_options(): void {
168        $changed = false;
169
170        // Clamp EPC options to 0 so its own code tears down rules.
171        if ( (int) get_option( 'endurance_cache_level', 0 ) !== 0 ) {
172            update_option( 'endurance_cache_level', 0 );
173            $changed = true;
174        }
175        if ( (int) get_option( 'epc_skip_404_handling', 0 ) !== 0 ) {
176            update_option( 'epc_skip_404_handling', 0 );
177            $changed = true;
178        }
179
180        // If anything changed, write .htaccess once and tidy options.
181        if ( $changed ) {
182            if ( ! function_exists( 'save_mod_rewrite_rules' ) ) {
183                require_once ABSPATH . 'wp-admin/includes/misc.php';
184            }
185            // Causes WP to regenerate rules; EPC listeners (if loaded) have just been triggered by the updates above.
186            save_mod_rewrite_rules();
187
188            // Optional cleanup so these don't linger in the DB.
189            delete_option( 'endurance_cache_level' );
190            delete_option( 'epc_skip_404_handling' );
191        }
192    }
193
194    /**
195     * When the brand plugin is deactivated, mirror its current settings into EPC.
196     * - EPC cache level (endurance_cache_level) is set to the current brand cache level (0–3).
197     * - EPC skip404 (epc_skip_404_handling) is set to the current brand skip404 value (0/1).
198     */
199    private function nfd_sync_epc_from_brand(): void {
200        // Clamp to EPC's range 0–3
201        $brand_level = (int) max( 0, min( 3, get_cache_level() ) );
202
203        // Brand Skip404: true/false -> EPC 1/0
204        $brand_skip404 = Skip404::get_value() ? 1 : 0;
205
206        // Write EPC options to reflect the brand plugin's current state
207        update_option( 'endurance_cache_level', $brand_level );
208        update_option( 'epc_skip_404_handling', $brand_skip404 );
209
210        // Ask WP to regenerate .htaccess so EPC can add/remove its own rules accordingly
211        if ( ! function_exists( 'save_mod_rewrite_rules' ) ) {
212            require_once ABSPATH . 'wp-admin/includes/misc.php';
213        }
214        save_mod_rewrite_rules();
215    }
216}