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