PluginProbe
SureCookie – GDPR Cookie Consent Banner, Cookie Scanner & Script Blocking / 1.4.0
SureCookie – GDPR Cookie Consent Banner, Cookie Scanner & Script Blocking v1.4.0
1.5.0 1.4.0 1.3.0 1.3.1 trunk 0.0.0-alpha.1 0.0.0-alpha.2 0.0.0-alpha.3 0.0.1-beta.1 0.0.1-beta.2 0.0.1-beta.3 0.0.1-beta.4 1.0.0 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4
surecookie / loader.php

loader.php in SureCookie – GDPR Cookie Consent Banner, Cookie Scanner & Script Blocking 1.4.0, at loader.php

382 lines 10.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Loader.
4 *
5 * @package SureCookie
6 * @since 0.0.1
7 */
8
9 namespace SureCookie;
10
11 use SureCookie\Admin\Analytics;
12 use SureCookie\Admin\Menu;
13 use SureCookie\Admin\Onboarding;
14 use SureCookie\Admin\Rating_Notice;
15 use SureCookie\Admin\Sync;
16 use SureCookie\Core\Frontend as Frontend_App;
17 use SureCookie\Core\Maintenance;
18 use SureCookie\Inc\API\Init as API_Initializer;
19 use SureCookie\Inc\Database\Init as DB_Initializer;
20 use SureCookie\Inc\Functions\Get;
21 use SureCookie\Inc\Integrations\Init as Integrations_Initializer;
22 use SureCookie\Inc\Integrations\Wordpress\Init as Wordpress_Abilities_Initializer;
23 use SureCookie\Inc\Modules\GoogleConsentMode\Actions as Gcm_Actions;
24 use SureCookie\Inc\Modules\Init as Modules_Initiator;
25 use SureCookie\Inc\Modules\Mcp\Init as Mcp_Initializer;
26 use SureCookie\Inc\Utils\Settings_Metadata;
27
28 // Exit if accessed directly.
29 defined( 'ABSPATH' ) || exit;
30
31 /**
32 * SureCookie_Loader
33 *
34 * Handles plugin initialization, autoloading, constants, and text domain loading.
35 *
36 * @since 0.0.1
37 */
38 class SureCookie_Loader {
39 /**
40 * Instance
41 *
42 * @access private
43 * @var SureCookie_Loader|null Class instance.
44 * @since 0.0.1
45 */
46 private static $instance = null;
47
48 /**
49 * Constructor.
50 *
51 * @since 0.0.1
52 */
53 public function __construct() {
54 // Define plugin constants.
55 $this->define_constants();
56
57 // Register autoloader.
58 spl_autoload_register( [ $this, 'autoload' ] );
59
60 add_action( 'plugins_loaded', [ $this, 'register_settings_dataset' ], 1 );
61 add_action( 'plugins_loaded', [ $this, 'load_routes' ] );
62
63 // Initialize plugin hooks.
64 add_action( 'init', [ $this, 'load_textdomain' ], 1 );
65 add_action( 'init', [ $this, 'load_plugin' ], 999 );
66 add_action( 'admin_init', [ $this, 'activation_redirect' ] );
67
68 // Site initialization.
69 add_action( 'wp_initialize_site', [ $this, 'initialize_new_site' ] );
70
71 // Activation hooks.
72 register_activation_hook( SURECOOKIE_FILE, [ $this, 'activation' ] );
73 register_deactivation_hook( SURECOOKIE_FILE, [ $this, 'deactivation' ] );
74
75 // Remove this after the translation error is fixed.
76 add_filter( 'doing_it_wrong_trigger_error', [ $this, 'suppress_translation_error' ], 10, 4 );
77
78 // Prevent Query Monitor from collecting the error.
79 add_action( 'doing_it_wrong_run', [ $this, 'prevent_qm_collection' ], 5, 3 );
80 }
81
82 /**
83 * Get instance
84 *
85 * @since 0.0.1
86 * @return SureCookie_Loader Instance of the class.
87 */
88 public static function get_instance() {
89 if ( self::$instance === null ) {
90 self::$instance = new self();
91 }
92 return self::$instance;
93 }
94
95 /**
96 * Prevent Query Monitor from collecting textdomain errors.
97 *
98 * @param string $function_name The function that was called.
99 * @param string $message The error message.
100 * @param string $version The version.
101 * @return void
102 * @since 1.0.0
103 */
104 public function prevent_qm_collection( $function_name, $message, $version ): void {
105 if ( $function_name === '_load_textdomain_just_in_time' && strpos( $message, 'surecookie' ) !== false ) {
106 // Remove Query Monitor's action temporarily.
107 if ( class_exists( '\QM_Collectors' ) ) {
108 $collector = \QM_Collectors::get( 'doing_it_wrong' );
109 if ( $collector ) {
110 remove_action( 'doing_it_wrong_run', [ $collector, 'action_doing_it_wrong_run' ], 10 );
111
112 // Re-add it after this specific error.
113 add_action(
114 'shutdown',
115 static function() use ( $collector ): void {
116 if ( ! has_action( 'doing_it_wrong_run', [ $collector, 'action_doing_it_wrong_run' ] ) ) {
117 add_action( 'doing_it_wrong_run', [ $collector, 'action_doing_it_wrong_run' ], 10, 3 );
118 }
119 },
120 -1
121 );
122 }
123 }
124 }
125 }
126
127 /**
128 * Suppress translation error.
129 *
130 * @param bool $status Status.
131 * @param string $function_name Function name.
132 * @param string $message Message.
133 * @param string $version Version.
134 *
135 * @return bool
136 * @since 1.0.0
137 */
138 public function suppress_translation_error( $status, $function_name, $message, $version ) {
139 if ( $function_name === '_load_textdomain_just_in_time' && strpos( $message, 'surecookie' ) !== false ) {
140 return false;
141 }
142 return $status;
143 }
144
145 /**
146 * Define plugin constants.
147 *
148 * @since 0.0.1
149 * @return void
150 */
151 public function define_constants(): void {
152 ! defined( 'SURECOOKIE_DEVELOPMENT_MODE' ) && define( 'SURECOOKIE_DEVELOPMENT_MODE', false );
153
154 $css_suffix = SURECOOKIE_DEVELOPMENT_MODE ? '.css' : '.min.css';
155 $js_suffix = SURECOOKIE_DEVELOPMENT_MODE ? '.js' : '.min.js';
156
157 define( 'SURECOOKIE_CSS_SUFFIX', $css_suffix );
158 define( 'SURECOOKIE_JS_SUFFIX', $js_suffix );
159 }
160
161 /**
162 * Autoload plugin classes.
163 *
164 * @param string $class Class name.
165 * @return void
166 */
167 public function autoload( $class ): void {
168 if ( strpos( $class, __NAMESPACE__ ) !== 0 ) {
169 return;
170 }
171
172 $class_to_load = $class;
173
174 $filename = preg_replace( // phpcs:ignore Generic.PHP.ForbiddenFunctions.FoundWithAlternative
175 [ '/^' . __NAMESPACE__ . '\\\/', '/([a-z])([A-Z])/', '/_/', '/\\\/' ],
176 [ '', '$1-$2', '-', DIRECTORY_SEPARATOR ],
177 $class_to_load
178 );
179
180 if ( is_string( $filename ) ) {
181 $filename = strtolower( $filename );
182
183 $file = SURECOOKIE_DIR . $filename . '.php';
184
185 // if the file readable, include it.
186 if ( is_readable( $file ) ) {
187 require_once $file;
188 }
189 }
190 }
191
192 /**
193 * Register settings-dataset contributions that must exist before init:20.
194 *
195 * The MCP adapter builds the abilities registry at init:20, which freezes
196 * manage-settings' input schema and primes the static cache in
197 * Settings::get_settings_defaults(). Modules boot at init:999, so a module
198 * that contributes setting keys registers that one filter here instead;
199 * registering it in the module would leave those keys unwritable over MCP
200 * and absent from the defaults for the rest of the request.
201 *
202 * @since 1.4.0
203 * @return void
204 */
205 public function register_settings_dataset(): void {
206 add_filter( 'surecookie_plugin_settings_dataset', [ Gcm_Actions::class, 'add_gcm_settings_to_dataset' ] );
207
208 // Priority 20 so every contributor has added its keys first; the
209 // annotator only touches keys that already exist.
210 add_filter( 'surecookie_plugin_settings_dataset', [ Settings_Metadata::class, 'merge' ], 20 );
211 }
212
213 /**
214 * Load routes.
215 *
216 * @since 0.0.1
217 * @return void
218 */
219 public function load_routes(): void {
220 do_action( 'surecookie_before_load_routes' );
221
222 /* Maintenance & API Initializer tasks */
223 Maintenance::get_instance();
224 API_Initializer::get_instance();
225
226 /*
227 * MCP + abilities must hook before init:20, where the MCP Adapter fires
228 * mcp_adapter_init under WP-CLI (modules/integrations auto-load too late
229 * at init:999). Singletons, so the later auto-discovery calls are no-ops.
230 */
231 Mcp_Initializer::get_instance();
232 if ( function_exists( 'wp_register_ability' ) ) {
233 Wordpress_Abilities_Initializer::get_instance();
234 }
235
236 /* BSF Analytics */
237 Analytics::get_instance();
238
239 do_action( 'surecookie_after_load_routes' );
240 }
241
242 /**
243 * Load plugin classes and initialize.
244 *
245 * @since 0.0.1
246 * @return void
247 */
248 public function load_plugin(): void {
249 do_action( 'surecookie_before_load_components' );
250
251 /* Site scanning sync processor */
252 Sync::get_instance();
253
254 /* Include all modules */
255 Modules_Initiator::get_instance();
256
257 /* Initialize third-party integrations (Abilities API, etc.) */
258 Integrations_Initializer::get_instance();
259
260 if ( is_admin() ) {
261 /* Admin menu */
262 Menu::get_instance();
263 Onboarding::get_instance();
264 Rating_Notice::get_instance();
265 } else {
266 /* Public app */
267 Frontend_App::get_instance();
268 }
269
270 do_action( 'surecookie_after_load_components' );
271
272 /**
273 * SureCookie Init.
274 *
275 * Fires when SureCookie is instantiated.
276 *
277 * @since 0.0.1
278 */
279 do_action( 'surecookie_loaded' );
280 }
281
282 /**
283 * Load plugin textdomain.
284 *
285 * @since 1.0.0
286 * @return void
287 */
288 public function load_textdomain(): void {
289 load_plugin_textdomain( 'surecookie', false, dirname( SURECOOKIE_BASE ) . '/languages/' );
290 }
291
292 /**
293 * Check if we should redirect.
294 *
295 * @since 0.0.1
296 * @return void
297 */
298 public function activation_redirect(): void {
299 // Avoid redirection in case of WP_CLI calls.
300 if ( defined( 'WP_CLI' ) && \WP_CLI ) {
301 return;
302 }
303
304 // Avoid redirection in case of ajax calls.
305 if ( wp_doing_ajax() ) {
306 return;
307 }
308
309 // Check if we should redirect.
310 $do_redirect = get_option( 'surecookie_do_activation_redirect' );
311
312 if ( $do_redirect ) {
313 // Clear the redirect option so it doesn't happen again.
314 delete_option( 'surecookie_do_activation_redirect' );
315
316 // Make sure we're not in a multisite network.
317 if ( ! is_multisite() ) {
318 $is_onboarding_completed = (bool) Get::option( SURECOOKIE_ONBOARDING_COMPLETED_OPTION, false );
319
320 // Always redirect to onboarding for fresh activations, dashboard if onboarding is completed.
321 $redirect_url = $is_onboarding_completed ? admin_url( 'admin.php?page=surecookie' ) : admin_url( 'admin.php?page=surecookie-onboarding' );
322
323 wp_safe_redirect( $redirect_url );
324 exit;
325 }
326 }
327 }
328
329 /**
330 * Initialize database tables when a new site is created in multisite.
331 *
332 * @param \WP_Site $site The new site's object.
333 * @since 0.0.1
334 * @return void
335 */
336 public function initialize_new_site( $site ): void {
337 DB_Initializer::initialize_new_site( $site );
338 }
339
340 /**
341 * Activation trigger.
342 *
343 * @since 0.0.1
344 * @return void
345 */
346 public function activation(): void {
347 update_option( 'surecookie_do_activation_redirect', true );
348 if ( get_option( 'surecookie_usage_installed_time', false ) === false ) {
349 add_option( 'surecookie_usage_installed_time', time(), '', false );
350 }
351 DB_Initializer::create_db_tables();
352 Maintenance::store_db_version();
353
354 // Warm the remote datasets shortly after activation (off-request) so the
355 // blocking + declared-cookie catalogs are current without waiting for the
356 // first daily cron tick. Bundled floors cover the interim.
357 if ( ! wp_next_scheduled( 'surecookie_refresh_datasets' ) ) {
358 wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'surecookie_refresh_datasets' );
359 }
360 }
361
362 /**
363 * Deactivation trigger.
364 *
365 * @since 0.0.1
366 * @return void
367 */
368 public function deactivation(): void {
369 wp_clear_scheduled_hook( 'surecookie_cleanup_consent_logs' );
370 wp_clear_scheduled_hook( 'surecookie_poll_scan_status' );
371 wp_clear_scheduled_hook( 'surecookie_auto_scan_run' );
372 wp_clear_scheduled_hook( 'surecookie_auto_scan_retry' );
373 wp_clear_scheduled_hook( 'surecookie_refresh_datasets' );
374 wp_clear_scheduled_hook( 'surecookie_first_party_detect' );
375 }
376 }
377
378 /**
379 * Kick off the plugin by calling get_instance().
380 */
381 SureCookie_Loader::get_instance();
382