PluginProbe ʕ •ᴥ•ʔ
Cookiebot by Usercentrics – Automatic Cookie Banner for GDPR/CCPA & Google Consent Mode / trunk
Cookiebot by Usercentrics – Automatic Cookie Banner for GDPR/CCPA & Google Consent Mode vtrunk
4.7.2 4.7.1 trunk 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 3.0.0 3.0.1 3.1.0 3.10.0 3.10.1 3.11.1 3.11.2 3.11.3 3.2.0 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.5 3.6.6 3.7.0 3.7.1 3.8.0 3.9.0 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.2.0 4.2.1 4.2.10 4.2.11 4.2.12 4.2.13 4.2.14 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.3.10 4.3.11 4.3.12 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.3.7.1 4.3.8 4.3.9 4.3.9.1 4.4.0 4.4.1 4.4.2 4.5.0 4.5.1 4.5.10 4.5.11 4.5.2 4.5.3 4.5.4 4.5.5 4.5.6 4.5.7 4.5.8 4.5.9 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.6.6 4.6.7 4.7.0
cookiebot / src / lib / Cookiebot_WP.php
cookiebot / src / lib Last commit date
buffer 1 year ago script_loader_tag 4 months ago traits 4 months ago Account_Service.php 4 months ago Consent_API_Helper.php 1 year ago Cookie_Consent.php 4 months ago Cookie_Consent_Interface.php 1 year ago Cookiebot_Activated.php 4 months ago Cookiebot_Admin_Links.php 1 year ago Cookiebot_Automatic_Updates.php 1 year ago Cookiebot_Deactivated.php 5 months ago Cookiebot_Frame.php 1 year ago Cookiebot_Javascript_Helper.php 7 months ago Cookiebot_Review.php 4 months ago Cookiebot_WP.php 2 weeks ago Dependency_Container.php 4 months ago Settings_Page_Tab.php 1 year ago Settings_Service.php 1 year ago Settings_Service_Interface.php 1 year ago Supported_Languages.php 1 year ago Supported_Regions.php 1 year ago WP_Rocket_Helper.php 1 year ago Widgets.php 1 year ago global-deprecations.php 1 year ago helper.php 4 months ago
Cookiebot_WP.php
789 lines
1 <?php
2
3
4 namespace cybot\cookiebot\lib;
5
6 use cybot\cookiebot\addons\Cookiebot_Addons;
7 use cybot\cookiebot\admin_notices\Cookiebot_Notices;
8 use cybot\cookiebot\gutenberg\Cookiebot_Gutenberg_Declaration_Block;
9 use cybot\cookiebot\settings\Menu_Settings;
10 use cybot\cookiebot\settings\Network_Menu_Settings;
11 use cybot\cookiebot\shortcode\Cookiebot_Embedding_Shortcode;
12 use cybot\cookiebot\widgets\Dashboard_Widget_Cookiebot_Status;
13 use cybot\cookiebot\lib\Account_Service;
14 use cybot\cookiebot\settings\pages\PPG_Page;
15 use cybot\cookiebot\abilities\Cookiebot_Abilities_Registrar;
16 use DomainException;
17 use RuntimeException;
18
19 if ( ! defined( 'CYBOT_COOKIEBOT_VERSION' ) ) {
20 define( 'CYBOT_COOKIEBOT_VERSION', '1.0.0' );
21 }
22
23 class Cookiebot_WP {
24
25 public static function debug_log( $message ) {
26 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
27 // phpcs:ignore
28 error_log( '[Cookiebot] ' . $message );
29 }
30 }
31
32 const COOKIEBOT_PLUGIN_VERSION = '4.7.2';
33 const COOKIEBOT_MIN_PHP_VERSION = '5.6.0';
34
35 /**
36 * @var Cookiebot_WP The single instance of the class
37 * @since 1.0.0
38 */
39 private static $instance = null;
40
41 private $account_service;
42
43 /**
44 * Main Cookiebot_WP Instance
45 *
46 * Ensures only one instance of Cookiebot_WP is loaded or can be loaded.
47 *
48 * @return Cookiebot_WP - Main instance
49 * @throws RuntimeException
50 * @version 1.0.0
51 * @since 1.0.0
52 * @static
53 */
54 public static function instance() {
55 if ( is_null( self::$instance ) ) {
56 self::$instance = new self();
57 }
58
59 return self::$instance;
60 }
61
62 /**
63 * Cookiebot_WP Constructor.
64 *
65 * @throws RuntimeException
66 * @since 1.0.0
67 * @access public
68 * @version 2.1.4
69 */
70 public function __construct() {
71 $this->throw_exception_if_php_version_is_incompatible();
72 $this->cookiebot_init();
73 register_activation_hook( CYBOT_COOKIEBOT_PLUGIN_DIR . 'cookiebot.php', array( new Cookiebot_Activated(), 'run' ) );
74 register_deactivation_hook( CYBOT_COOKIEBOT_PLUGIN_DIR . 'cookiebot.php', array( new Cookiebot_Deactivated(), 'run' ) );
75
76 // Initialize services
77 $this->account_service = new Account_Service();
78 }
79
80 /**
81 * @throws RuntimeException
82 */
83 private function throw_exception_if_php_version_is_incompatible() {
84 if ( version_compare( PHP_VERSION, self::COOKIEBOT_MIN_PHP_VERSION, '<' ) ) {
85 $message = sprintf(
86 // translators: The placeholder is for the COOKIEBOT_MIN_PHP_VERSION constant
87 __( 'The Cookiebot plugin requires PHP version %s or greater.', 'cookiebot' ),
88 self::COOKIEBOT_MIN_PHP_VERSION
89 );
90 throw new DomainException( esc_html( $message ) );
91 }
92 }
93
94 public function cookiebot_init() {
95 Cookiebot_Addons::instance();
96 add_action( 'init', array( $this, 'cookiebot_load_textdomain' ) );
97
98 if ( is_admin() ) {
99 ( new Menu_Settings() )->add_menu();
100 if ( is_multisite() && is_plugin_active_for_network( 'cookiebot/cookiebot.php' ) ) {
101 ( new Network_Menu_Settings() )->add_menu();
102 }
103 ( new Dashboard_Widget_Cookiebot_Status() )->register_hooks();
104 ( new Cookiebot_Notices() )->register_hooks();
105 ( new Cookiebot_Review() )->register_hooks();
106 ( new PPG_Page() )->register_ajax_hooks();
107 }
108
109 ( new Consent_API_Helper() )->register_hooks();
110 ( new Cookiebot_Javascript_Helper() )->register_hooks();
111 ( new Cookiebot_Embedding_Shortcode() )->register_hooks();
112 ( new Cookiebot_Automatic_Updates() )->register_hooks();
113 ( new Widgets() )->register_hooks();
114 ( new Cookiebot_Gutenberg_Declaration_Block() )->register_hooks();
115 ( new WP_Rocket_Helper() )->register_hooks();
116 ( new Cookiebot_Abilities_Registrar() )->register_hooks();
117
118 if ( defined( 'WP_CLI' ) && \WP_CLI ) {
119 \WP_CLI::add_command(
120 'cookiebot',
121 \cybot\cookiebot\cli\Cookiebot_CLI_Command::class
122 );
123 }
124
125 $this->set_default_options();
126 ( new Cookiebot_Admin_Links() )->register_hooks();
127 }
128
129 /**
130 * Returns true if an user is logged in and has an edit_themes capability
131 *
132 * @return bool
133 *
134 * @since 3.3.1
135 * @version 3.4.1
136 */
137 public static function can_current_user_edit_theme() {
138 if ( is_user_logged_in() &&
139 (
140 current_user_can( 'edit_themes' ) ||
141 current_user_can( 'edit_pages' ) ||
142 current_user_can( 'edit_posts' )
143 )
144 ) {
145 return true;
146 }
147
148 return false;
149 }
150
151 /**
152 * Loads translations textdomain
153 *
154 * @return void
155 */
156 public function cookiebot_load_textdomain() {
157 load_textdomain(
158 'cookiebot',
159 CYBOT_COOKIEBOT_PLUGIN_DIR . 'langs/cookiebot-' . get_locale() . '.mo'
160 );
161 load_plugin_textdomain( 'cookiebot', false, dirname( plugin_basename( __FILE__ ) ) . '/langs' );
162 }
163
164 /**
165 * @return string
166 */
167 public static function get_cbid() {
168 $network_setting = (string) get_site_option( 'cookiebot-cbid', '' );
169 $setting = (string) get_option( 'cookiebot-cbid', $network_setting );
170
171 return empty( $setting ) ? $network_setting : $setting;
172 }
173
174 public static function get_auth_token() {
175 $token = (string) get_option( 'cookiebot-auth-token' );
176 return $token;
177 }
178
179 public static function get_user_data() {
180 $user_data = get_option( 'cookiebot-user-data', '' );
181 return empty( $user_data ) ? '' : $user_data;
182 }
183
184 /**
185 * Check if the user was onboarded via signup
186 *
187 * @return bool
188 */
189 public static function was_onboarded_via_signup() {
190 return (bool) get_option( 'cookiebot-uc-onboarded-via-signup', false );
191 }
192
193 public static function get_scan_status() {
194 $scan_status = get_option( 'cookiebot-scan-status', '' );
195 return empty( $scan_status ) ? '' : $scan_status;
196 }
197
198 /**
199 * @return string
200 */
201 public static function get_network_cbid() {
202 return get_site_option( 'cookiebot-cbid', '' );
203 }
204
205 /**
206 * @return string
207 */
208 public static function get_banner_enabled() {
209 $enabled = get_option( 'cookiebot-banner-enabled', 'default' );
210 if ( $enabled === 'default' ) {
211 $enabled = '1';
212 update_option( 'cookiebot-banner-enabled', $enabled );
213 }
214 return $enabled;
215 }
216
217 public static function get_auto_blocking_mode() {
218 $enabled = get_option( 'cookiebot-uc-auto-blocking-mode', 'default' );
219 if ( $enabled === 'default' ) {
220 $enabled = '1';
221 update_option( 'cookiebot-uc-auto-blocking-mode', $enabled );
222 }
223 return $enabled;
224 }
225
226 /**
227 * @return string
228 */
229 public static function get_gcm_enabled() {
230 $enabled = get_option( 'cookiebot-gcm', 'default' );
231 if ( $enabled === 'default' ) {
232 $enabled = '1';
233 update_option( 'cookiebot-gcm', $enabled );
234 }
235 return $enabled;
236 }
237
238 /**
239 * @return string
240 */
241 public static function get_preview_link() {
242 $url = get_site_option( 'siteurl', '#' );
243 return $url;
244 }
245
246 /**
247 * @return string
248 */
249 public static function get_subscription_type() {
250 $raw_data = get_option( 'cookiebot-user-data', '' );
251
252 if ( empty( $raw_data ) ) {
253 self::debug_log( 'Raw data is empty' );
254 return '';
255 }
256
257 // Use the data directly if it's already an array
258 $data = is_array( $raw_data ) ? $raw_data : json_decode( $raw_data, true );
259
260 // Check if we have the new subscription structure
261 if ( ! isset( $data['subscriptions']['active'] ) ) {
262 self::debug_log( 'No active subscription found' );
263 return '';
264 }
265
266 $subscription = $data['subscriptions']['active'];
267 $status = isset( $subscription['subscription_status'] ) ? $subscription['subscription_status'] : '';
268 $price_plan = isset( $subscription['price_plan'] ) ? $subscription['price_plan'] : 'free';
269
270 self::debug_log( 'Subscription details:' );
271 self::debug_log( 'Status: ' . $status );
272 self::debug_log( 'Price Plan: ' . $price_plan );
273
274 // Check for trial status first
275 if ( in_array( $status, array( 'trial_will_be_billed', 'trial_missing_payment' ), true ) ) {
276 self::debug_log( 'Trial status detected, returning Premium trial' );
277 return 'Premium Trial';
278 }
279
280 // If not in trial, check active subscriptions
281 if ( in_array( $status, array( 'active_auto_renew', 'active_no_renew' ), true ) ) {
282 // Map extended plan names to their base names
283 $plan_mapping = array(
284 'FreeExtended' => 'Free',
285 'EssentialExtended' => 'Essential',
286 'PlusExtended' => 'Plus',
287 'ProExtended' => 'Pro',
288 'BusinessExtended' => 'Business',
289 );
290
291 $result = isset( $plan_mapping[ $price_plan ] ) ? $plan_mapping[ $price_plan ] : ucfirst( $price_plan );
292 self::debug_log( 'Active subscription, returning: ' . $result );
293 return $result;
294 }
295
296 self::debug_log( 'No conditions met, returning Free' );
297 return '';
298 }
299
300 /**
301 * @return string
302 */
303 public static function get_legal_framwework() {
304 $configuration = get_option( 'cookiebot-configuration', array() );
305 return isset( $configuration['legal_framework_template'] ) ? strtoupper( $configuration['legal_framework_template'] ) : 'GDPR';
306 }
307
308 /**
309 * @return string
310 */
311 public static function get_cookie_blocking_mode() {
312 $allowed_modes = array( 'auto', 'manual' );
313 $network_setting = (string) get_site_option( 'cookiebot-cookie-blocking-mode', 'manual' );
314 $setting = $network_setting === 'manual' ?
315 (string) get_option( 'cookiebot-cookie-blocking-mode', $network_setting ) :
316 $network_setting;
317
318 return in_array( $setting, $allowed_modes, true ) ? $setting : 'auto';
319 }
320
321 /**
322 * @return bool
323 */
324 public static function check_network_auto_blocking_mode() {
325 $network_setting = (string) get_site_option( 'cookiebot-cookie-blocking-mode' );
326
327 return $network_setting === 'auto' ? true : false;
328 }
329
330 /**
331 * @return string
332 */
333 public static function get_cookie_categories_status() {
334 return self::get_cookie_blocking_mode() === 'auto' ? 'disabled' : '';
335 }
336
337 /**
338 * @return bool
339 */
340 public static function is_cookie_category_selected( $option, $category ) {
341 $categories = get_option( $option );
342 if ( ! $categories || ! is_array( $categories ) ) {
343 return false;
344 }
345
346 return in_array( $category, $categories, true );
347 }
348
349 /**
350 * Cookiebot_WP Check if Cookiebot is active in admin
351 *
352 * @version 4.2.8
353 * @since 3.1.0
354 */
355 public static function cookiebot_disabled_in_admin() {
356 if ( ( is_network_admin() && get_site_option( 'cookiebot-nooutput-admin', false ) ) ||
357 ( ! is_network_admin() && get_site_option( 'cookiebot-nooutput-admin', false ) ) ||
358 ( ! is_network_admin() && get_option( 'cookiebot-nooutput-admin', false ) ) ) {
359 return true;
360 }
361
362 return false;
363 }
364
365 /**
366 * Cookiebot_WP Set default options
367 *
368 * @version 4.2.5
369 * @since 4.2.5
370 */
371 private function set_default_options() {
372 $options = array(
373 'cookiebot-nooutput-admin' => '1',
374 'cookiebot-gcm' => '1',
375 'cookiebot-banner-enabled' => '1',
376 'cookiebot-cookie-blocking-mode' => 'auto',
377 );
378
379 foreach ( $options as $option => $default ) {
380 if ( get_option( $option ) === false && ! get_option( $option . self::OPTION_FIRST_RUN_SUFFIX ) ) {
381 update_option( $option, $default );
382 }
383
384 if ( ( get_option( $option ) || get_option( $option ) !== false ) && ! get_option( $option . self::OPTION_FIRST_RUN_SUFFIX ) ) {
385 update_option( $option . self::OPTION_FIRST_RUN_SUFFIX, '1' );
386 }
387 }
388
389 // Safeguard to always garantee the blocking mode has a value.
390 // There is one situation in which this value is cleared after disconnecting an onboarded user account
391 if ( empty( get_option( 'cookiebot-cookie-blocking-mode' ) ) ) {
392 update_option( 'cookiebot-cookie-blocking-mode', 'auto' );
393 }
394
395 self::set_tcf_version();
396 }
397
398 private static function set_tcf_version() {
399 $iab_version = get_option( 'cookiebot-tcf-version' );
400 if ( empty( $iab_version ) || $iab_version === 'IAB' ) {
401 update_option( 'cookiebot-tcf-version', 'TCFv2.2' );
402 }
403 }
404
405 public function set_settings_action_link( $actions ) {
406 $cblinks = array(
407 '<a href="' . esc_url( add_query_arg( 'page', 'cookiebot', admin_url( 'admin.php' ) ) ) . '">' . esc_html__( 'Dashboard', 'cookiebot' ) . '</a>',
408 );
409 $actions = array_merge( $actions, $cblinks );
410 return $actions;
411 }
412
413 /**
414 * @return string
415 */
416 public static function get_manager_language() {
417 $locale = get_locale();
418 $supported_langs = array(
419 'de_DE' => 'de',
420 'da_DK' => 'da',
421 'fr_FR' => 'fr',
422 'it_IT' => 'it',
423 'es_ES' => 'es',
424 );
425
426 return array_key_exists( $locale, $supported_langs ) ? $supported_langs[ $locale ] : esc_html( 'en' );
427 }
428
429 const OPTION_FIRST_RUN_SUFFIX = '-first-run';
430
431 public function get_usercentrics_script() {
432 $final_script = '';
433
434 // Enqueue Usercentrics scripts
435 wp_enqueue_script(
436 'usercentrics-tcf-stub',
437 'https://web.cmp.usercentrics.eu/tcf/stub.js',
438 array(),
439 CYBOT_COOKIEBOT_VERSION,
440 true
441 );
442
443 wp_enqueue_script(
444 'usercentrics-autoblocker',
445 'https://web.cmp.usercentrics.eu/modules/autoblocker.js',
446 array(),
447 CYBOT_COOKIEBOT_VERSION,
448 true
449 );
450
451 wp_enqueue_script(
452 'usercentrics-cmp',
453 'https://web.cmp.usercentrics.eu/ui/loader.js',
454 array(),
455 CYBOT_COOKIEBOT_VERSION,
456 true
457 );
458
459 // Add data attributes to the CMP script
460 wp_script_add_data(
461 'usercentrics-cmp',
462 'data-usercentrics',
463 'Usercentrics Consent Management Platform'
464 );
465 wp_script_add_data(
466 'usercentrics-cmp',
467 'data-settings-id',
468 '%s'
469 );
470 wp_script_add_data(
471 'usercentrics-cmp',
472 'async',
473 true
474 );
475
476 return $final_script;
477 }
478
479 public function enqueue_scripts() {
480 wp_enqueue_script(
481 'cookiebot',
482 'https://consent.cookiebot.com/uc.js',
483 array(),
484 CYBOT_COOKIEBOT_VERSION,
485 true
486 );
487
488 wp_enqueue_script(
489 'cookiebot-helper',
490 plugins_url( 'js/cookiebot-helper.js', dirname( __FILE__ ) ),
491 array( 'jquery' ),
492 CYBOT_COOKIEBOT_VERSION,
493 true
494 );
495
496 wp_enqueue_script(
497 'cookiebot-admin',
498 plugins_url( 'js/cookiebot-admin.js', dirname( __FILE__ ) ),
499 array( 'jquery' ),
500 CYBOT_COOKIEBOT_VERSION,
501 true
502 );
503 }
504
505 /**
506 * Clone object and return it
507 *
508 * @return object
509 *
510 * @since 1.0.0
511 */
512 public function get_cloned_object() {
513 $temp = clone $this;
514 return $temp;
515 }
516
517 /**
518 * Get the banner script HTML
519 *
520 * @return string
521 *
522 * @phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedScript
523 */
524 public static function get_banner_script() {
525 $cbid = self::get_cbid();
526 self::debug_log( '=== get_banner_script: Starting ===' );
527 self::debug_log( 'CBID: ' . $cbid );
528
529 // Basic validation checks
530 if ( empty( $cbid ) || defined( 'COOKIEBOT_DISABLE_ON_PAGE' ) ) {
531 self::debug_log( 'get_banner_script: Basic validation failed - CBID empty or disabled' );
532 return '';
533 }
534
535 // Banner enabled check
536 $banner_enabled = get_option( 'cookiebot-banner-enabled', '1' );
537 self::debug_log( 'Banner enabled setting: ' . $banner_enabled );
538 if ( $banner_enabled !== '1' ) {
539 self::debug_log( 'get_banner_script: Banner disabled in settings' );
540 return '';
541 }
542
543 // User verification and trial checks
544 $user_data = self::get_user_data();
545
546 if ( ! empty( $user_data ) && self::is_trial_expired() ) {
547 self::debug_log( 'get_banner_script: Trial expired' );
548 return '';
549 }
550
551 // Output conditions check
552 self::debug_log( 'get_banner_script: Generating dynamic script' );
553
554 // Build the script HTML
555 $script_html = '';
556
557 // Add TCF stub if IAB is enabled
558 $iab_enabled = ! empty( get_option( 'cookiebot-iab' ) );
559 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
560 self::debug_log( 'IAB enabled: ' . ( $iab_enabled ? 'yes' : 'no' ) );
561 if ( $iab_enabled ) {
562 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
563 $script_html .= sprintf(
564 '<script src="%s"></script>',
565 esc_url( 'https://web.cmp.usercentrics.eu/tcf/stub.js' )
566 );
567 }
568
569 // Add autoblocker if auto mode is enabled
570 $blocking_mode = get_option( 'cookiebot-uc-auto-blocking-mode', '1' );
571 $blocking_mode_cookiebot = get_option( 'cookiebot-cookie-blocking-mode', 'auto' );
572
573 if ( $blocking_mode === '0' || $blocking_mode_cookiebot === 'manual' ) {
574 $blocking_mode = '0';
575 }
576
577 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
578 self::debug_log( 'Blocking mode: ' . $blocking_mode );
579 if ( $blocking_mode === '1' ) {
580 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
581 $script_html .= sprintf(
582 '<script src="%s"></script>',
583 esc_url( 'https://web.cmp.usercentrics.eu/modules/autoblocker.js' )
584 );
585 }
586
587 $data_label = ! empty( get_option( 'cookiebot-ruleset-id' ) ) ? get_option( 'cookiebot-ruleset-id' ) : 'settings';
588 // Add main banner script
589 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
590 $script_html .= sprintf(
591 '<script id="usercentrics-cmp" data-%s-id="%s" data-usercentrics="%s" src="%s" async></script>',
592 esc_attr( $data_label ),
593 esc_attr( $cbid ),
594 esc_attr( 'Usercentrics Consent Management Platform' ),
595 esc_url( 'https://web.cmp.usercentrics.eu/ui/loader.js' )
596 );
597
598 self::debug_log( 'Final script HTML: ' . $script_html );
599 return $script_html;
600 }
601
602 /**
603 * Check if the trial has expired by checking various conditions
604 *
605 * @return bool True if trial has expired, false otherwise
606 */
607 public static function is_trial_expired() {
608 $user_data = self::get_user_data();
609
610 if ( empty( $user_data ) ) {
611 self::debug_log( 'is_trial_expired: No user data found' );
612 return false;
613 }
614
615 // Check if there's an active subscription
616 if ( isset( $user_data['subscriptions']['active'] ) ) {
617 $active_subscription = $user_data['subscriptions']['active'];
618
619 // Check subscription status
620 if ( isset( $active_subscription['subscription_status'] ) ) {
621 $status = $active_subscription['subscription_status'];
622 self::debug_log( 'is_trial_expired: Subscription status: ' . $status );
623
624 // For trial statuses, check the trial period
625 if ( in_array( $status, array( 'trial_will_be_billed', 'trial_missing_payment' ), true ) ) {
626 if ( isset( $active_subscription['trial_end_date'] ) && ! empty( $active_subscription['trial_end_date'] ) ) {
627 $trial_end = \DateTime::createFromFormat( 'Y-m-d\TH:i:s.000\Z', $active_subscription['trial_end_date'] );
628
629 if ( $trial_end === false ) {
630 self::debug_log( 'is_trial_expired: Failed to parse trial end date' );
631 return false;
632 }
633
634 $now = new \DateTime();
635 $interval = $now->diff( $trial_end );
636
637 // If the interval is negative (past the end date) or zero, the trial has expired
638 $is_expired = $interval->invert || $interval->days === 0;
639 self::debug_log( 'is_trial_expired: Is expired? ' . ( $is_expired ? 'yes' : 'no' ) );
640 return $is_expired;
641 }
642 }
643
644 // For active subscriptions, check if it's a trial plan
645 if ( in_array( $status, array( 'active_auto_renew', 'active_no_renew' ), true ) ) {
646 // Not a trial subscription
647 self::debug_log( 'is_trial_expired: Active subscription - not a trial' );
648 return false;
649 }
650
651 // Cancelled subscriptions are considered expired
652 if ( $status === 'cancelled' ) {
653 self::debug_log( 'is_trial_expired: Cancelled subscription - expired' );
654 return true;
655 }
656 }
657 }
658
659 // If we get here and subscription type is Free, consider trial as expired
660 $subscription_type = self::get_subscription_type();
661 if ( $subscription_type === 'Free' ) {
662 self::debug_log( 'is_trial_expired: Free subscription - considered expired' );
663 return true;
664 }
665
666 self::debug_log( 'is_trial_expired: Default case - not expired' );
667 return false;
668 }
669
670 /**
671 * Check if the user has upgraded from the free plan
672 *
673 * @return bool
674 */
675 public static function has_upgraded() {
676 $user_data = get_option( 'cookiebot-user-data' );
677
678 if ( ! isset( $user_data['subscriptions']['active'] ) ) {
679 return false;
680 }
681
682 $active_subscription = $user_data['subscriptions']['active'];
683 $status = isset( $active_subscription['subscription_status'] ) ? $active_subscription['subscription_status'] : '';
684 $price_plan = isset( $active_subscription['price_plan'] ) ? $active_subscription['price_plan'] : '';
685
686 if ( empty( $price_plan ) ) {
687 return false;
688 }
689
690 // Check if the subscription is active (not trial or cancelled)
691 if ( in_array( $status, array( 'active_auto_renew', 'active_no_renew' ), true ) ) {
692 // Map extended plan names to their base names
693 $plan_mapping = array(
694 'FreeExtended' => 'Free',
695 'EssentialExtended' => 'Essential',
696 'PlusExtended' => 'Plus',
697 'ProExtended' => 'Pro',
698 'BusinessExtended' => 'Business',
699 );
700
701 $base_plan = isset( $plan_mapping[ $price_plan ] ) ? $plan_mapping[ $price_plan ] : $price_plan;
702 return true;
703 }
704
705 return false;
706 }
707
708 /**
709 * Get the number of days left in the trial period
710 *
711 * @return int Number of days left in the trial, or 0 if trial has expired or no trial exists
712 */
713 public static function get_trial_days_left() {
714 $user_data = self::get_user_data();
715
716 if ( empty( $user_data ) ) {
717 self::debug_log( 'get_trial_days_left: No user data found' );
718 return 0;
719 }
720
721 // Check if there's an active subscription
722 if ( isset( $user_data['subscriptions']['active'] ) ) {
723 $active_subscription = $user_data['subscriptions']['active'];
724
725 // Check subscription status
726 if ( isset( $active_subscription['subscription_status'] ) ) {
727 $status = $active_subscription['subscription_status'];
728 self::debug_log( 'get_trial_days_left: Subscription status: ' . $status );
729
730 // For trial statuses, calculate days left until trial_end_date
731 if ( in_array( $status, array( 'trial_will_be_billed', 'trial_missing_payment' ), true ) ) {
732 if ( isset( $active_subscription['trial_end_date'] ) && ! empty( $active_subscription['trial_end_date'] ) ) {
733 $trial_end = \DateTime::createFromFormat( 'Y-m-d\TH:i:s.000\Z', $active_subscription['trial_end_date'] );
734
735 if ( $trial_end === false ) {
736 self::debug_log( 'get_trial_days_left: Failed to parse trial end date' );
737 return 0;
738 }
739
740 $now = new \DateTime();
741 $interval = $now->diff( $trial_end );
742
743 // If the interval is negative (past the end date), return 0
744 if ( $interval->invert ) {
745 self::debug_log( 'get_trial_days_left: Trial has already ended' );
746 return 0;
747 }
748
749 // Add 1 to include the current day
750 $days_left = $interval->days + 1;
751 self::debug_log( 'get_trial_days_left: Days left: ' . $days_left );
752 return $days_left;
753 }
754 }
755
756 // For active subscriptions, no trial days left
757 if ( in_array( $status, array( 'active_auto_renew', 'active_no_renew' ), true ) ) {
758 self::debug_log( 'get_trial_days_left: Active subscription - no trial days' );
759 return 0;
760 }
761 }
762 }
763
764 return 0;
765 }
766
767 /**
768 * Check if the subscription is in trial status
769 *
770 * @return bool True if subscription is in trial status, false otherwise
771 */
772 public static function is_in_trial() {
773 $user_data = self::get_user_data();
774
775 if ( empty( $user_data ) || ! isset( $user_data['subscriptions']['active']['subscription_status'] ) ) {
776 self::debug_log( 'is_in_trial: No user data or subscription status found' );
777 return false;
778 }
779
780 $status = $user_data['subscriptions']['active']['subscription_status'];
781 $is_trial = in_array( $status, array( 'trial_will_be_billed', 'trial_missing_payment' ), true );
782
783 self::debug_log( 'is_in_trial: Subscription status: ' . $status );
784 self::debug_log( 'is_in_trial: Is trial? ' . ( $is_trial ? 'yes' : 'no' ) );
785
786 return $is_trial;
787 }
788 }
789