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