Changeset 3268043
- Timestamp:
- 04/07/2025 05:35:06 PM (12 months ago)
- Location:
- shopkeeper-extender
- Files:
-
- 4 added
- 2 deleted
- 20 edited
- 1 copied
-
tags/5.1 (copied) (copied from shopkeeper-extender/trunk)
-
tags/5.1/README.txt (modified) (1 diff)
-
tags/5.1/core/updater/assets/plugin.json (modified) (2 diffs)
-
tags/5.1/dashboard/css/license-notifications.css (modified) (8 diffs)
-
tags/5.1/dashboard/inc/classes/class-gbt-notification-handler.php (added)
-
tags/5.1/dashboard/inc/classes/class-license-subscription-checker.php (modified) (15 diffs)
-
tags/5.1/dashboard/inc/pages/content/license.php (modified) (5 diffs)
-
tags/5.1/dashboard/inc/pages/includes.php (modified) (1 diff)
-
tags/5.1/dashboard/index.php (modified) (5 diffs)
-
tags/5.1/dashboard/js/gbt-notification-handler.js (added)
-
tags/5.1/dashboard/js/license-subscription-notification.js (modified) (6 diffs)
-
tags/5.1/dashboard/js/notifications.js (deleted)
-
tags/5.1/dashboard/setup.php (modified) (1 diff)
-
tags/5.1/shopkeeper-extender.php (modified) (1 diff)
-
trunk/README.txt (modified) (1 diff)
-
trunk/core/updater/assets/plugin.json (modified) (2 diffs)
-
trunk/dashboard/css/license-notifications.css (modified) (8 diffs)
-
trunk/dashboard/inc/classes/class-gbt-notification-handler.php (added)
-
trunk/dashboard/inc/classes/class-license-subscription-checker.php (modified) (15 diffs)
-
trunk/dashboard/inc/pages/content/license.php (modified) (5 diffs)
-
trunk/dashboard/inc/pages/includes.php (modified) (1 diff)
-
trunk/dashboard/index.php (modified) (5 diffs)
-
trunk/dashboard/js/gbt-notification-handler.js (added)
-
trunk/dashboard/js/license-subscription-notification.js (modified) (6 diffs)
-
trunk/dashboard/js/notifications.js (deleted)
-
trunk/dashboard/setup.php (modified) (1 diff)
-
trunk/shopkeeper-extender.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
shopkeeper-extender/tags/5.1/README.txt
r3267058 r3268043 138 138 == Changelog == 139 139 140 = 5. 0=140 = 5.1 = 141 141 - Maintenance update 142 142 -
shopkeeper-extender/tags/5.1/core/updater/assets/plugin.json
r3267058 r3268043 1 1 { 2 2 "name": "Shopkeeper Extender", 3 "version": "5. 0",4 "download_url": "https://downloads.wordpress.org/plugin/shopkeeper-extender.5. 0.zip",3 "version": "5.1", 4 "download_url": "https://downloads.wordpress.org/plugin/shopkeeper-extender.5.1.zip", 5 5 6 6 "homepage": "https://wordpress.org/plugins/shopkeeper-extender/", 7 7 "requires": "6.0", 8 8 "tested": "6.7.2", 9 "last_updated": "2025-04-0 412:00:00",9 "last_updated": "2025-04-07 12:00:00", 10 10 11 11 "author": "GetBowtied", … … 14 14 "sections": { 15 15 "description": "<p>Companion plugin for the <b>Shopkeeper</b> theme. Extends the functionality by adding theme specific features.</p><h4>Features:</h4><ul><li>Adds 'Social Media' section in Customizer for easy management of links to social media profiles</li><li>Adds header image option for WooCommerce product categories</li><li>Adds 'Additional JS' section in Customizer allowing for site customization with custom JavaScript code</li><li>Adds social sharing buttons for WooCommerce products</li><li>Adds 'Background URL' field for menu items</li></ul><h4>Gutenberg Blocks:</h4><ul><li>Image Slider</li><li>Banner</li><li>Posts Grid</li><li>Product Categories Grid</li><li>Social Media Profiles</li></ul><h4>Widgets:</h4><ul><li>Social Media Profiles</li></ul><h4>WPBakery Page Builder Elements:</h4><ul><li>Slider</li><li>Banner</li><li>Posts Slider</li><li>Product Categories Grid</li><li>Social Media Profiles</li></ul>", 16 "changelog": "<h4>5. 0</h4><ul><li>Maintenance update</li></ul>"16 "changelog": "<h4>5.1</h4><ul><li>Maintenance update</li></ul>" 17 17 }, 18 18 -
shopkeeper-extender/tags/5.1/dashboard/css/license-notifications.css
r3267058 r3268043 18 18 .getbowtied_ext_notice__collapsible_content { 19 19 display: none; /* Hide by default */ 20 width: 100%; 20 21 } 21 22 … … 25 26 margin-bottom: 0; 26 27 margin-right: 10px; 27 text-transform: uppercase; 28 letter-spacing: 0.6px; 29 font-weight: 700; 28 text-transform: none; 30 29 display: inline-block; 31 30 background-color: #ffea00; … … 269 268 position: relative; 270 269 overflow: visible; 271 max-width: calc(100% - 450px); /* Add max-width to avoid text overlap with background icon */270 max-width: calc(100% - 450px); 272 271 display: flex; 273 flex-wrap: wrap; 272 flex-direction: column; 273 align-items: flex-start; 274 } 275 276 /* Title and toggle link container */ 277 .getbowtied_ext_notice .title-container { 278 display: flex; 274 279 align-items: center; 280 width: 100%; 281 } 282 283 /* Move title into container */ 284 .getbowtied_ext_notice .title { 285 margin: 0; 286 } 287 288 /* Adjust toggle link position */ 289 .getbowtied_ext_notice__toggle_link { 290 margin-left: 20px; 291 } 292 293 /* Ensure collapsible content takes full width */ 294 .getbowtied_ext_notice__collapsible_content { 295 width: 100%; 296 } 297 298 /* Ensure proper spacing for paragraphs and headings */ 299 .getbowtied_ext_notice__collapsible_content p, 300 .getbowtied_ext_notice__collapsible_content h4 { 301 width: 100%; 275 302 } 276 303 … … 458 485 /* Hide dismiss button and Remind Me Later for no-license notification */ 459 486 .no-license-notification .notice-dismiss, 460 .no-license-notification .dismiss-notification { 487 .no-license-notification .dismiss-notification, 488 .no-license-notification .reminder-options { 461 489 display: none !important; 490 } 491 492 .no-license-notification .title strong { 493 font-weight: 700; 462 494 } 463 495 464 496 /* Styles for Remind Me Later button */ 465 497 .getbowtied_ext_notice .dismiss-notification { 466 color: #777; 467 text-decoration: none; 468 margin-left: 10px; 469 font-size: 13px; 470 display: inline-block; 471 opacity: 0.7; 472 transition: opacity 0.2s ease; 498 color: #2271b1; 499 text-decoration: none; 500 white-space: nowrap; 473 501 } 474 502 475 503 .getbowtied_ext_notice .dismiss-notification:hover { 476 color: #444; 477 text-decoration: underline; 478 opacity: 1; 504 color: #135e96; 505 text-decoration: underline; 506 } 507 508 /* Styles for reminder options */ 509 .getbowtied_ext_notice .reminder-options { 510 display: inline-flex; 511 flex-wrap: wrap; 512 gap: 10px; 513 margin-top: 15px; 514 border-top: 1px solid #dcdcde; 515 padding-top: 15px; 516 width: 100%; 517 justify-content: flex-end; 518 } 519 520 /* Style for reminder buttons */ 521 .getbowtied_ext_notice .reminder-btn { 522 display: inline-flex; 523 align-items: center; 524 padding: 6px 12px; 525 background-color: transparent; 526 border: none; 527 border-radius: 4px; 528 font-size: 13px; 529 line-height: 1.5; 530 text-decoration: none; 531 color: #737373; 532 transition: all 0.2s ease-out; 533 margin-left: 5px; 534 } 535 536 .getbowtied_ext_notice .reminder-btn:hover { 537 background-color: rgba(0,0,0,0.02); 538 color: #50575e; 539 text-decoration: none; 540 } 541 542 .getbowtied_ext_notice .reminder-btn:before { 543 content: "\f469"; /* WordPress dashicon clock */ 544 font-family: dashicons; 545 font-size: 14px; 546 margin-right: 4px; 547 line-height: 1; 548 opacity: 0.7; 549 } 550 551 /* Responsive adjustments for small screens */ 552 @media (max-width: 782px) { 553 .getbowtied_ext_notice .reminder-options { 554 flex-direction: column; 555 align-items: stretch; 556 gap: 0; /* Reduce gap to 0 */ 557 border-top: none; 558 margin-top: 0; /* Reduce margin */ 559 padding-top: 0; /* Reduce padding */ 560 } 561 562 .getbowtied_ext_notice .reminder-btn { 563 text-align: center; 564 justify-content: center; 565 margin-left: 0; 566 border-top: 1px solid #dcdcde; 567 padding-top: 8px; /* Reduce padding */ 568 padding-bottom: 8px; /* Reduce padding */ 569 border-radius: 0; 570 } 571 572 .getbowtied_ext_notice .reminder-btn:first-child { 573 border-top: 1px solid #dcdcde; 574 } 479 575 } 480 576 … … 492 588 493 589 .getbowtied_ext_notice .getbowtied_ext_notice__content { 494 padding: 1 5px;590 padding: 12px; 495 591 } 496 592 … … 513 609 width: 100%; 514 610 text-align: center; 515 margin: 0 0 8px 0;611 margin: 0 0 5px 0; /* Reduce bottom margin */ 516 612 box-sizing: border-box; 517 613 } … … 521 617 display: flex; 522 618 flex-direction: column; 523 margin-top: 1 5px;619 margin-top: 10px; /* Reduce top margin */ 524 620 margin-bottom: 0; 525 621 } … … 529 625 display: block; 530 626 text-align: center; 531 margin: 8px 0 0 0;532 padding: 10px;627 margin: 5px 0 0 0; /* Reduce top margin */ 628 padding: 8px; /* Reduce padding */ 533 629 color: #666; 534 border-top: 1px solid #eee;630 border-top: none; 535 631 } 536 632 -
shopkeeper-extender/tags/5.1/dashboard/inc/classes/class-license-subscription-checker.php
r3267058 r3268043 175 175 176 176 <div class="getbowtied_ext_notice__content"> 177 <h3 class="title">CRITICAL ALERT: <?php echo esc_html($theme_name); ?> THEME LICENSE NOT DETECTED!</h3> 178 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 177 <div class="title-container"> 178 <h3 class="title"><strong>CRITICAL ALERT:</strong> <?php echo esc_html($theme_name); ?> theme license not detected!</h3> 179 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 180 </div> 179 181 <div class="getbowtied_ext_notice__collapsible_content"> 180 182 <p>Your <?php echo esc_html($theme_name); ?> theme is currently operating without a valid license key.</p> … … 190 192 <p> 191 193 <a href="<?php echo esc_url($license_page_url); ?>" class="button button-primary button-large">Activate Your License Now</a> 192 193 194 <a href="<?php echo esc_url($purchase_url); ?>" target="_blank" class="button button-large">Get a License</a> 194 195 <a href="#" class="dismiss-notification" data-message-id="license_no_license_detected" data-theme-slug="<?php echo esc_attr($theme_slug); ?>">Remind Me Later</a> 195 <span class="reminder-options"> 196 <a href="#" class="dismiss-notification reminder-btn" data-message-id="license_no_license_detected" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="1">Remind me tomorrow</a> 197 <a href="#" class="dismiss-notification reminder-btn" data-message-id="license_no_license_detected" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="7">Remind me in 1 week</a> 198 <a href="#" class="dismiss-notification reminder-btn" data-message-id="license_no_license_detected" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="30">Remind me in 1 month</a> 199 </span> 196 200 </p> 197 201 </div> … … 223 227 224 228 <div class="getbowtied_ext_notice__content"> 225 <h3 class="title">URGENT: YOUR <?php echo esc_html(strtoupper($theme_name)); ?> Professional Plan HAS EXPIRED!</h3> 226 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 229 <div class="title-container"> 230 <h3 class="title">Your "<?php echo esc_html($theme_name); ?>" Professional Plan has expired</h3> 231 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 232 </div> 227 233 <div class="getbowtied_ext_notice__collapsible_content"> 228 234 <h4>Your <?php echo esc_html($theme_name); ?> theme Professional Plan has ended, putting your website at risk.</h4> … … 233 239 234 240 <ul> 235 <li class="dashicons-before dashicons-shield-alt"> Automaticcritical security updates</li>236 <li class="dashicons-before dashicons-update-alt"> Automaticpriority bug fixes, security & compatibility updates</li>241 <li class="dashicons-before dashicons-shield-alt">Built-in critical security updates</li> 242 <li class="dashicons-before dashicons-update-alt">Built-in priority bug fixes, security & compatibility updates</li> 237 243 <li class="dashicons-before dashicons-admin-users">Expert assistance from a dedicated developer</li> 238 244 </ul> … … 249 255 <a href="<?php echo esc_url($license_details_url); ?>" class="button button-primary button-large">View Your License Details</a> 250 256 251 <a href="#" class="dismiss-notification" data-message-id="<?php echo esc_attr($this->notification_settings['expired_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>">Remind Me Later</a> 257 <span class="reminder-options"> 258 <a href="#" class="dismiss-notification reminder-btn" data-message-id="<?php echo esc_attr($this->notification_settings['expired_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="1">Remind me tomorrow</a> 259 <a href="#" class="dismiss-notification reminder-btn" data-message-id="<?php echo esc_attr($this->notification_settings['expired_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="7">Remind me in 1 week</a> 260 <a href="#" class="dismiss-notification reminder-btn" data-message-id="<?php echo esc_attr($this->notification_settings['expired_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="30">Remind me in 1 month</a> 261 </span> 252 262 </p> 253 263 </div> … … 260 270 * Display notification for subscription expiring soon 261 271 * 262 * @param int $days_remaining Number of days remaining until expiration272 * @param int $days_remaining The number of days remaining until expiration 263 273 */ 264 274 public function display_expiring_soon_notification($days_remaining) … … 276 286 $renew_url = $gbt_dashboard->get_theme_sales_page_url(); 277 287 288 // Format days remaining text 289 $days_text = $days_remaining == 1 ? 'day' : 'days'; 290 278 291 ?> 279 292 <div class="notice-warning settings-error notice getbowtied_ext_notice gbt-dashboard-notification" 280 data-message-id="<?php echo esc_attr($this->notification_settings['expiring_soon_id']); ?>" 293 data-message-id="<?php echo esc_attr($this->notification_settings['expiring_soon_id']); ?>" 281 294 data-theme-slug="<?php echo esc_attr($theme_slug); ?>"> 282 295 <div class="getbowtied_ext_notice__aside"> … … 285 298 286 299 <div class="getbowtied_ext_notice__content"> 287 <h3 class="title">IMPORTANT: YOUR <?php echo esc_html(strtoupper($theme_name)); ?> Professional Plan <?php 300 <div class="title-container"> 301 <h3 class="title">IMPORTANT: Your <?php echo esc_html($theme_name); ?> Professional Plan <?php 288 302 if ($days_remaining == 0) { 289 echo ' EXPIRES TODAY!';303 echo 'expires today!'; 290 304 } elseif ($days_remaining == 1) { 291 echo ' EXPIRES TOMORROW!';305 echo 'expires tomorrow!'; 292 306 } else { 293 echo ' EXPIRES IN ' . esc_html($days_remaining) . ' DAYS!';307 echo 'expires in ' . esc_html($days_remaining) . ' days!'; 294 308 } 295 309 ?></h3> 296 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 310 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 311 </div> 297 312 <div class="getbowtied_ext_notice__collapsible_content"> 298 313 <h4>Your <?php echo esc_html($theme_name); ?> Professional Plan will expire on <?php echo esc_html($expiration_date); ?>, putting your site at risk.</h4> … … 311 326 312 327 <ul> 313 <li class="dashicons-before dashicons-shield-alt"> Automaticcritical security updates</li>314 <li class="dashicons-before dashicons-update-alt"> Automaticpriority bug fixes, security & compatibility updates</li>328 <li class="dashicons-before dashicons-shield-alt">Built-in critical security updates</li> 329 <li class="dashicons-before dashicons-update-alt">Built-in priority bug fixes, security & compatibility updates</li> 315 330 <li class="dashicons-before dashicons-admin-users">Expert assistance from a dedicated developer</li> 316 331 </ul> … … 323 338 <a href="<?php echo esc_url($license_details_url); ?>" class="button button-primary button-large">View Your License Details</a> 324 339 325 <a href="#" class="dismiss-notification" data-message-id="<?php echo esc_attr($this->notification_settings['expiring_soon_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>">Remind Me Later</a> 340 <span class="reminder-options"> 341 <a href="#" class="dismiss-notification reminder-btn" data-message-id="<?php echo esc_attr($this->notification_settings['expiring_soon_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="1">Remind me tomorrow</a> 342 </span> 326 343 </p> 327 344 </div> 328 345 </div> 329 346 </div> 330 <?php347 <?php 331 348 } 332 349 … … 371 388 } 372 389 373 // Check if dismiss period has passed 374 $dismissed_time = $dismissed[$theme_slug]; 375 $dismiss_seconds = $this->notification_settings['dismiss_days'] * DAY_IN_SECONDS; 390 // Check if stored value is an array (new format) or timestamp (old format) 391 if (is_array($dismissed[$theme_slug])) { 392 $dismissed_time = $dismissed[$theme_slug]['time']; 393 $dismiss_days = $dismissed[$theme_slug]['days']; 394 } else { 395 // Legacy format - just a timestamp with default days 396 $dismissed_time = $dismissed[$theme_slug]; 397 $dismiss_days = $this->notification_settings['dismiss_days']; 398 } 399 400 // Calculate dismiss period 401 $dismiss_seconds = $dismiss_days * DAY_IN_SECONDS; 376 402 377 403 // Still dismissed if within the dismissal period … … 410 436 $message_id = isset($_POST['message_id']) ? sanitize_text_field($_POST['message_id']) : ''; 411 437 $theme_slug = isset($_POST['theme_slug']) ? sanitize_text_field($_POST['theme_slug']) : ''; 438 $days = isset($_POST['days']) ? absint($_POST['days']) : $this->notification_settings['dismiss_days']; 412 439 413 440 // Get the appropriate dismiss option based on message ID … … 418 445 } 419 446 420 // Save dismissal timestamp 421 $this->save_notification_dismissal($theme_slug, $dismiss_option );447 // Save dismissal timestamp with days parameter 448 $this->save_notification_dismissal($theme_slug, $dismiss_option, $days); 422 449 423 450 wp_send_json_success(); … … 437 464 case $this->notification_settings['expiring_soon_id']: 438 465 return $this->notification_settings['dismiss_soon_option']; 466 case 'license_no_license_detected': 467 return $this->notification_settings['dismiss_option']; 439 468 default: 440 469 return false; … … 447 476 * @param string $theme_slug The theme slug to associate with dismissal 448 477 * @param string $option_name The option name to update 449 */ 450 private function save_notification_dismissal($theme_slug, $option_name) 478 * @param int $days Number of days to dismiss for 479 */ 480 private function save_notification_dismissal($theme_slug, $option_name, $days = 1) 451 481 { 452 482 $dismissed = get_option($option_name, []); 453 $dismissed[$theme_slug] = time(); 483 // Store both the time and the number of days to dismiss for 484 $dismissed[$theme_slug] = [ 485 'time' => time(), 486 'days' => $days 487 ]; 454 488 update_option($option_name, $dismissed); 455 489 } -
shopkeeper-extender/tags/5.1/dashboard/inc/pages/content/license.php
r3267058 r3268043 250 250 // Auto-verify license on page load if there's an active license 251 251 if (!empty($stored_options['license_key']) && !isset($_GET['license_updated'])) { 252 // Only do this if not immediately after a license update to avoid duplicate checks 253 $auto_check_result = $license_manager->cron_process_license(); 254 255 // If the check failed due to domain restriction, the license will be cleared 256 // Update stored options to match the current state after verification 257 if ($auto_check_result && !$auto_check_result['success']) { 258 $stored_options = $auto_check_result['license_data']; 259 $license_key = $stored_options['license_key'] ?? ''; 260 $license_status = $stored_options['license_status'] ?? 'inactive'; 261 $license_info = $stored_options['license_info'] ?? []; 262 $support_expiration_date = $stored_options['support_expiration_date'] ?? ''; 263 264 // Set transient to show notification on this page load 265 set_transient('gbt_license_result', $auto_check_result, 60); 252 // Check when the license was last verified and only perform the check 253 // if it has been more than 30 days since the last verification 254 $last_verified = $license_manager->get_last_verified_time(); 255 $current_time = time(); 256 $interval_days = 30; 257 $interval_seconds = $interval_days * DAY_IN_SECONDS; 258 259 if ($current_time - $last_verified >= $interval_seconds) { 260 // Only do this if not immediately after a license update to avoid duplicate checks 261 $auto_check_result = $license_manager->cron_process_license(); 262 263 // If the check failed due to domain restriction, the license will be cleared 264 // Update stored options to match the current state after verification 265 if ($auto_check_result && !$auto_check_result['success']) { 266 $stored_options = $auto_check_result['license_data']; 267 $license_key = $stored_options['license_key'] ?? ''; 268 $license_status = $stored_options['license_status'] ?? 'inactive'; 269 $license_info = $stored_options['license_info'] ?? []; 270 $support_expiration_date = $stored_options['support_expiration_date'] ?? ''; 271 272 // Set transient to show notification on this page load 273 set_transient('gbt_license_result', $auto_check_result, 60); 274 } 266 275 } 267 276 } … … 882 891 <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" /> 883 892 </svg> 884 <span class="text-gray-600"> Automaticcritical security updates</span>893 <span class="text-gray-600">Built-in critical security updates</span> 885 894 </li> 886 895 <li class="flex gap-x-3"> … … 888 897 <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" /> 889 898 </svg> 890 <span class="text-gray-600"> Automaticpriority bug fixes</span>899 <span class="text-gray-600">Built-in priority bug fixes</span> 891 900 </li> 892 901 <li class="flex gap-x-3"> … … 965 974 <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z" clip-rule="evenodd" /> 966 975 </svg> 967 Automaticcritical security updates976 Built-in critical security updates 968 977 </li> 969 978 <li class="flex gap-x-3"> … … 977 986 <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z" clip-rule="evenodd" /> 978 987 </svg> 979 Automaticpriority bug fixes988 Built-in priority bug fixes 980 989 </li> 981 990 <li class="flex gap-x-3"> -
shopkeeper-extender/tags/5.1/dashboard/inc/pages/includes.php
r3267058 r3268043 90 90 } 91 91 92 // Dashboard Message 93 wp_enqueue_script( 94 'gbt-dashboard-notification', 95 $base_paths['url'] . '/dashboard/js/notifications.js', 96 array('jquery'), 97 $theme_version_gbt_dash, 98 true 99 ); 92 if (isset($_GET['page']) && $_GET['page'] === 'getbowtied-theme-documentation') { 93 wp_enqueue_script( 94 'gbt-documentation-iframe', 95 $base_paths['url'] . '/dashboard/js/iframe.js', 96 array('jquery'), 97 $theme_version_gbt_dash, 98 true 99 ); 100 } 100 101 101 wp_localize_script( 102 'gbt-dashboard-notification', 103 'gbtDashboard', 104 array( 105 'nonce' => wp_create_nonce('dismiss_message') 106 ) 107 ); 102 // Removed old Dashboard Message script - now using global notification handler 108 103 } 109 104 -
shopkeeper-extender/tags/5.1/dashboard/index.php
r3267058 r3268043 174 174 if (get_option('gbt_theme_updated_redirect')) { 175 175 delete_option('gbt_theme_updated_redirect'); 176 177 // Clear notification transients after theme update 178 if (class_exists('GBT_Notification_Handler')) { 179 gbt_notification_handler()->clear_all_notification_transients(); 180 } 181 182 // Clear license notification dismissals to show them after update 183 if (class_exists('GBT_License_Subscription_Checker')) { 184 $theme_slug = $this->get_theme_slug(); 185 186 // Get the option keys for dismissals 187 $expired_option = 'getbowtied_theme_license_subscription_expired_dismissed'; 188 $expiring_option = 'getbowtied_theme_license_subscription_expiring_soon_dismissed'; 189 190 // Get the current dismissal data 191 $expired_data = get_option($expired_option, []); 192 $expiring_data = get_option($expiring_option, []); 193 194 // Remove dismissals for this theme 195 if (isset($expired_data[$theme_slug])) { 196 unset($expired_data[$theme_slug]); 197 update_option($expired_option, $expired_data); 198 } 199 200 if (isset($expiring_data[$theme_slug])) { 201 unset($expiring_data[$theme_slug]); 202 update_option($expiring_option, $expiring_data); 203 } 204 205 // The no-license notification also uses the expired_option, but we've already cleared that 206 } 207 176 208 $this->redirect_to_dashboard(); 177 209 } … … 518 550 519 551 private function validate_message($message_data) { 520 if (!$this->is_valid_message($message_data)) { 521 return false; 522 } 523 524 $dismissed_messages = get_user_meta(get_current_user_id(), 'gbt_dashboard_dismissed_notifications', true); 525 if (is_array($dismissed_messages) && in_array($message_data['id'], $dismissed_messages)) { 526 return false; 527 } 528 529 if (!$message_data['active']) { 552 if (!$this->is_valid_message($message_data) || 553 !$message_data['active'] || 554 gbt_notification_handler()->is_dismissed($message_data['id'])) { 530 555 return false; 531 556 } … … 535 560 $end_date = strtotime($message_data['end_date']); 536 561 537 if ($current_time >= $start_date && $current_time <= $end_date) { 538 return $message_data; 539 } 540 541 return false; 562 return ($current_time >= $start_date && $current_time <= $end_date) ? $message_data : false; 542 563 } 543 564 … … 551 572 552 573 public function display_dashboard_message() { 553 $message_data = $this->get_external_message();554 555 if ($message_data) {556 ?>557 <div class="notice notice-success is-dismissible gbt-dashboard-notification"558 data-message-id="<?php echo esc_attr($message_data['id']); ?>"559 data-theme-slug="<?php echo esc_attr($this->theme_slug_gbt_dash); ?>">560 <p><?php echo wp_kses_post($message_data['message']); ?></p>561 </div>562 <?php 563 }564 }565 574 if ($message_data = $this->get_external_message()) { 575 printf( 576 '<div class="notice notice-success is-dismissible gbt-dashboard-notification" data-message-id="%s" data-theme-slug="%s"><p>%s</p></div>', 577 esc_attr($message_data['id']), 578 esc_attr($this->theme_slug_gbt_dash), 579 wp_kses_post($message_data['message']) 580 ); 581 } 582 } 583 584 /** 585 * Handle message dismissal via AJAX (Legacy method) 586 */ 566 587 public function handle_message_dismissal() { 567 588 check_ajax_referer('dismiss_message', 'nonce'); … … 572 593 573 594 $message_id = isset($_POST['message_id']) ? sanitize_text_field($_POST['message_id']) : ''; 574 $theme_slug = isset($_POST['theme_slug']) ? sanitize_text_field($_POST['theme_slug']) : ''; 575 576 if ($message_id && $theme_slug) { 577 $dismissed_messages = get_user_meta(get_current_user_id(), 'gbt_dashboard_dismissed_notifications', true); 578 if (!is_array($dismissed_messages)) { 579 $dismissed_messages = array(); 580 } 581 $dismissed_messages[] = $message_id; 582 update_user_meta(get_current_user_id(), 'gbt_dashboard_dismissed_notifications', $dismissed_messages); 595 596 if ($message_id) { 597 gbt_notification_handler()->save_dismissal($message_id); 583 598 } 584 599 -
shopkeeper-extender/tags/5.1/dashboard/js/license-subscription-notification.js
r3267058 r3268043 6 6 (function($) { 7 7 'use strict'; 8 9 // Configuration 10 const config = { 11 autoExpandNoLicense: false // Set to true to auto-expand no-license notifications 12 }; 8 13 9 14 // Wait for DOM to be ready … … 16 21 } 17 22 18 // Auto-expand no-license notification when not on the license page19 if ( !window.location.href.includes('page=getbowtied-license')) {23 // Auto-expand no-license notification when configured 24 if (config.autoExpandNoLicense && !window.location.href.includes('page=getbowtied-license')) { 20 25 // Add a slight delay to ensure DOM is fully loaded and ready 21 26 setTimeout(function() { … … 29 34 } 30 35 31 // Handle dismiss button click - updated for Remind Me Later button 36 // Function to toggle content visibility 37 function toggleContent($content) { 38 // Toggle the expanded class 39 $content.toggleClass('expanded'); 40 41 // Update the More details link text based on expanded state 42 const $link = $content.find('.getbowtied_ext_notice__toggle_link'); 43 $link.text($content.hasClass('expanded') ? 'Hide details' : 'Click for details'); 44 } 45 46 // Toggle collapsible content when clicking on title 47 $notifications.on('click', '.title', function(e) { 48 e.preventDefault(); 49 const $content = $(this).closest('.getbowtied_ext_notice__content'); 50 toggleContent($content); 51 }); 52 53 // Toggle collapsible content when clicking on the "More details" link 54 $notifications.on('click', '.getbowtied_ext_notice__toggle_link', function(e) { 55 e.preventDefault(); 56 const $content = $(this).closest('.getbowtied_ext_notice__content'); 57 toggleContent($content); 58 }); 59 60 // Handle both "View License Details" and "Activate Your License Now" button clicks 61 $notifications.on('click', 'a[href*="page=getbowtied-license"]', function(e) { 62 e.preventDefault(); 63 var href = $(this).attr('href'); 64 65 // Navigate to the license page if we're not already there 66 if (!window.location.href.includes('page=getbowtied-license')) { 67 // Simply navigate to the URL without any scroll parameter 68 window.location.href = href; 69 return; 70 } 71 72 // If we're already on the license page, scroll to the dashboard scope 73 scrollToDashboard(); 74 }); 75 76 // Check if we need to scroll on page load (coming from external page) 77 function scrollToDashboard() { 78 var $target = $('.gbt-dashboard-scope'); 79 if ($target.length) { 80 $('html, body').animate({ 81 scrollTop: $target.offset().top 82 }, 500); 83 } 84 } 85 86 // Handle dismiss button click - updated for individual reminder buttons 32 87 $notifications.on('click', '.dismiss-notification', function(e) { 33 // Prevent default action since this is now an anchor tag88 // Prevent default action 34 89 e.preventDefault(); 35 90 … … 37 92 const messageId = $button.data('message-id'); 38 93 const themeSlug = $button.data('theme-slug'); 94 const days = $button.data('days'); 39 95 const $notification = $button.closest('.gbt-dashboard-notification'); 40 96 … … 53 109 message_id: messageId, 54 110 theme_slug: themeSlug, 111 days: days, 55 112 nonce: gbtLicenseSubscriptionData.nonce 56 113 }, … … 108 165 }); 109 166 }); 110 111 // Handle both "View License Details" and "Activate Your License Now" button clicks112 $notifications.on('click', 'a[href*="page=getbowtied-license"]', function(e) {113 e.preventDefault();114 var href = $(this).attr('href');115 116 // Navigate to the license page if we're not already there117 if (!window.location.href.includes('page=getbowtied-license')) {118 // Simply navigate to the URL without any scroll parameter119 window.location.href = href;120 return;121 }122 123 // If we're already on the license page, scroll to the dashboard scope124 scrollToDashboard();125 });126 127 // Check if we need to scroll on page load (coming from external page)128 function scrollToDashboard() {129 var $target = $('.gbt-dashboard-scope');130 if ($target.length) {131 $('html, body').animate({132 scrollTop: $target.offset().top133 }, 500);134 }135 }136 137 // Function to toggle content visibility138 function toggleContent($content) {139 // Toggle the expanded class140 $content.toggleClass('expanded');141 142 // Update the More details link text based on expanded state143 const $link = $content.find('.getbowtied_ext_notice__toggle_link');144 $link.text($content.hasClass('expanded') ? 'Hide details' : 'Click for details');145 }146 147 // Toggle collapsible content when clicking on title148 $notifications.on('click', '.title', function(e) {149 e.preventDefault();150 const $content = $(this).closest('.getbowtied_ext_notice__content');151 toggleContent($content);152 });153 154 // Toggle collapsible content when clicking on the "More details" link155 $notifications.on('click', '.getbowtied_ext_notice__toggle_link', function(e) {156 e.preventDefault();157 const $content = $(this).closest('.getbowtied_ext_notice__content');158 toggleContent($content);159 });160 167 }); 161 168 })(jQuery); -
shopkeeper-extender/tags/5.1/dashboard/setup.php
r3267058 r3268043 9 9 include_once( $base_paths['path'] . '/dashboard/inc/pages/setup.php' ); 10 10 include_once( $base_paths['path'] . '/dashboard/inc/classes/class-theme-li.php' ); 11 include_once( $base_paths['path'] . '/dashboard/inc/classes/class-gbt-notification-handler.php' ); 11 12 12 13 // Only include pointers if theme is not Block Shop -
shopkeeper-extender/tags/5.1/shopkeeper-extender.php
r3267058 r3268043 5 5 * Plugin URI: https://shopkeeper.wp-theme.design/ 6 6 * Description: Extends the functionality of Shopkeeper with theme specific features. 7 * Version: 5. 07 * Version: 5.1 8 8 * Author: Get Bowtied 9 9 * Author URI: https://getbowtied.com -
shopkeeper-extender/trunk/README.txt
r3267058 r3268043 138 138 == Changelog == 139 139 140 = 5. 0=140 = 5.1 = 141 141 - Maintenance update 142 142 -
shopkeeper-extender/trunk/core/updater/assets/plugin.json
r3267058 r3268043 1 1 { 2 2 "name": "Shopkeeper Extender", 3 "version": "5. 0",4 "download_url": "https://downloads.wordpress.org/plugin/shopkeeper-extender.5. 0.zip",3 "version": "5.1", 4 "download_url": "https://downloads.wordpress.org/plugin/shopkeeper-extender.5.1.zip", 5 5 6 6 "homepage": "https://wordpress.org/plugins/shopkeeper-extender/", 7 7 "requires": "6.0", 8 8 "tested": "6.7.2", 9 "last_updated": "2025-04-0 412:00:00",9 "last_updated": "2025-04-07 12:00:00", 10 10 11 11 "author": "GetBowtied", … … 14 14 "sections": { 15 15 "description": "<p>Companion plugin for the <b>Shopkeeper</b> theme. Extends the functionality by adding theme specific features.</p><h4>Features:</h4><ul><li>Adds 'Social Media' section in Customizer for easy management of links to social media profiles</li><li>Adds header image option for WooCommerce product categories</li><li>Adds 'Additional JS' section in Customizer allowing for site customization with custom JavaScript code</li><li>Adds social sharing buttons for WooCommerce products</li><li>Adds 'Background URL' field for menu items</li></ul><h4>Gutenberg Blocks:</h4><ul><li>Image Slider</li><li>Banner</li><li>Posts Grid</li><li>Product Categories Grid</li><li>Social Media Profiles</li></ul><h4>Widgets:</h4><ul><li>Social Media Profiles</li></ul><h4>WPBakery Page Builder Elements:</h4><ul><li>Slider</li><li>Banner</li><li>Posts Slider</li><li>Product Categories Grid</li><li>Social Media Profiles</li></ul>", 16 "changelog": "<h4>5. 0</h4><ul><li>Maintenance update</li></ul>"16 "changelog": "<h4>5.1</h4><ul><li>Maintenance update</li></ul>" 17 17 }, 18 18 -
shopkeeper-extender/trunk/dashboard/css/license-notifications.css
r3267058 r3268043 18 18 .getbowtied_ext_notice__collapsible_content { 19 19 display: none; /* Hide by default */ 20 width: 100%; 20 21 } 21 22 … … 25 26 margin-bottom: 0; 26 27 margin-right: 10px; 27 text-transform: uppercase; 28 letter-spacing: 0.6px; 29 font-weight: 700; 28 text-transform: none; 30 29 display: inline-block; 31 30 background-color: #ffea00; … … 269 268 position: relative; 270 269 overflow: visible; 271 max-width: calc(100% - 450px); /* Add max-width to avoid text overlap with background icon */270 max-width: calc(100% - 450px); 272 271 display: flex; 273 flex-wrap: wrap; 272 flex-direction: column; 273 align-items: flex-start; 274 } 275 276 /* Title and toggle link container */ 277 .getbowtied_ext_notice .title-container { 278 display: flex; 274 279 align-items: center; 280 width: 100%; 281 } 282 283 /* Move title into container */ 284 .getbowtied_ext_notice .title { 285 margin: 0; 286 } 287 288 /* Adjust toggle link position */ 289 .getbowtied_ext_notice__toggle_link { 290 margin-left: 20px; 291 } 292 293 /* Ensure collapsible content takes full width */ 294 .getbowtied_ext_notice__collapsible_content { 295 width: 100%; 296 } 297 298 /* Ensure proper spacing for paragraphs and headings */ 299 .getbowtied_ext_notice__collapsible_content p, 300 .getbowtied_ext_notice__collapsible_content h4 { 301 width: 100%; 275 302 } 276 303 … … 458 485 /* Hide dismiss button and Remind Me Later for no-license notification */ 459 486 .no-license-notification .notice-dismiss, 460 .no-license-notification .dismiss-notification { 487 .no-license-notification .dismiss-notification, 488 .no-license-notification .reminder-options { 461 489 display: none !important; 490 } 491 492 .no-license-notification .title strong { 493 font-weight: 700; 462 494 } 463 495 464 496 /* Styles for Remind Me Later button */ 465 497 .getbowtied_ext_notice .dismiss-notification { 466 color: #777; 467 text-decoration: none; 468 margin-left: 10px; 469 font-size: 13px; 470 display: inline-block; 471 opacity: 0.7; 472 transition: opacity 0.2s ease; 498 color: #2271b1; 499 text-decoration: none; 500 white-space: nowrap; 473 501 } 474 502 475 503 .getbowtied_ext_notice .dismiss-notification:hover { 476 color: #444; 477 text-decoration: underline; 478 opacity: 1; 504 color: #135e96; 505 text-decoration: underline; 506 } 507 508 /* Styles for reminder options */ 509 .getbowtied_ext_notice .reminder-options { 510 display: inline-flex; 511 flex-wrap: wrap; 512 gap: 10px; 513 margin-top: 15px; 514 border-top: 1px solid #dcdcde; 515 padding-top: 15px; 516 width: 100%; 517 justify-content: flex-end; 518 } 519 520 /* Style for reminder buttons */ 521 .getbowtied_ext_notice .reminder-btn { 522 display: inline-flex; 523 align-items: center; 524 padding: 6px 12px; 525 background-color: transparent; 526 border: none; 527 border-radius: 4px; 528 font-size: 13px; 529 line-height: 1.5; 530 text-decoration: none; 531 color: #737373; 532 transition: all 0.2s ease-out; 533 margin-left: 5px; 534 } 535 536 .getbowtied_ext_notice .reminder-btn:hover { 537 background-color: rgba(0,0,0,0.02); 538 color: #50575e; 539 text-decoration: none; 540 } 541 542 .getbowtied_ext_notice .reminder-btn:before { 543 content: "\f469"; /* WordPress dashicon clock */ 544 font-family: dashicons; 545 font-size: 14px; 546 margin-right: 4px; 547 line-height: 1; 548 opacity: 0.7; 549 } 550 551 /* Responsive adjustments for small screens */ 552 @media (max-width: 782px) { 553 .getbowtied_ext_notice .reminder-options { 554 flex-direction: column; 555 align-items: stretch; 556 gap: 0; /* Reduce gap to 0 */ 557 border-top: none; 558 margin-top: 0; /* Reduce margin */ 559 padding-top: 0; /* Reduce padding */ 560 } 561 562 .getbowtied_ext_notice .reminder-btn { 563 text-align: center; 564 justify-content: center; 565 margin-left: 0; 566 border-top: 1px solid #dcdcde; 567 padding-top: 8px; /* Reduce padding */ 568 padding-bottom: 8px; /* Reduce padding */ 569 border-radius: 0; 570 } 571 572 .getbowtied_ext_notice .reminder-btn:first-child { 573 border-top: 1px solid #dcdcde; 574 } 479 575 } 480 576 … … 492 588 493 589 .getbowtied_ext_notice .getbowtied_ext_notice__content { 494 padding: 1 5px;590 padding: 12px; 495 591 } 496 592 … … 513 609 width: 100%; 514 610 text-align: center; 515 margin: 0 0 8px 0;611 margin: 0 0 5px 0; /* Reduce bottom margin */ 516 612 box-sizing: border-box; 517 613 } … … 521 617 display: flex; 522 618 flex-direction: column; 523 margin-top: 1 5px;619 margin-top: 10px; /* Reduce top margin */ 524 620 margin-bottom: 0; 525 621 } … … 529 625 display: block; 530 626 text-align: center; 531 margin: 8px 0 0 0;532 padding: 10px;627 margin: 5px 0 0 0; /* Reduce top margin */ 628 padding: 8px; /* Reduce padding */ 533 629 color: #666; 534 border-top: 1px solid #eee;630 border-top: none; 535 631 } 536 632 -
shopkeeper-extender/trunk/dashboard/inc/classes/class-license-subscription-checker.php
r3267058 r3268043 175 175 176 176 <div class="getbowtied_ext_notice__content"> 177 <h3 class="title">CRITICAL ALERT: <?php echo esc_html($theme_name); ?> THEME LICENSE NOT DETECTED!</h3> 178 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 177 <div class="title-container"> 178 <h3 class="title"><strong>CRITICAL ALERT:</strong> <?php echo esc_html($theme_name); ?> theme license not detected!</h3> 179 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 180 </div> 179 181 <div class="getbowtied_ext_notice__collapsible_content"> 180 182 <p>Your <?php echo esc_html($theme_name); ?> theme is currently operating without a valid license key.</p> … … 190 192 <p> 191 193 <a href="<?php echo esc_url($license_page_url); ?>" class="button button-primary button-large">Activate Your License Now</a> 192 193 194 <a href="<?php echo esc_url($purchase_url); ?>" target="_blank" class="button button-large">Get a License</a> 194 195 <a href="#" class="dismiss-notification" data-message-id="license_no_license_detected" data-theme-slug="<?php echo esc_attr($theme_slug); ?>">Remind Me Later</a> 195 <span class="reminder-options"> 196 <a href="#" class="dismiss-notification reminder-btn" data-message-id="license_no_license_detected" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="1">Remind me tomorrow</a> 197 <a href="#" class="dismiss-notification reminder-btn" data-message-id="license_no_license_detected" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="7">Remind me in 1 week</a> 198 <a href="#" class="dismiss-notification reminder-btn" data-message-id="license_no_license_detected" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="30">Remind me in 1 month</a> 199 </span> 196 200 </p> 197 201 </div> … … 223 227 224 228 <div class="getbowtied_ext_notice__content"> 225 <h3 class="title">URGENT: YOUR <?php echo esc_html(strtoupper($theme_name)); ?> Professional Plan HAS EXPIRED!</h3> 226 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 229 <div class="title-container"> 230 <h3 class="title">Your "<?php echo esc_html($theme_name); ?>" Professional Plan has expired</h3> 231 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 232 </div> 227 233 <div class="getbowtied_ext_notice__collapsible_content"> 228 234 <h4>Your <?php echo esc_html($theme_name); ?> theme Professional Plan has ended, putting your website at risk.</h4> … … 233 239 234 240 <ul> 235 <li class="dashicons-before dashicons-shield-alt"> Automaticcritical security updates</li>236 <li class="dashicons-before dashicons-update-alt"> Automaticpriority bug fixes, security & compatibility updates</li>241 <li class="dashicons-before dashicons-shield-alt">Built-in critical security updates</li> 242 <li class="dashicons-before dashicons-update-alt">Built-in priority bug fixes, security & compatibility updates</li> 237 243 <li class="dashicons-before dashicons-admin-users">Expert assistance from a dedicated developer</li> 238 244 </ul> … … 249 255 <a href="<?php echo esc_url($license_details_url); ?>" class="button button-primary button-large">View Your License Details</a> 250 256 251 <a href="#" class="dismiss-notification" data-message-id="<?php echo esc_attr($this->notification_settings['expired_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>">Remind Me Later</a> 257 <span class="reminder-options"> 258 <a href="#" class="dismiss-notification reminder-btn" data-message-id="<?php echo esc_attr($this->notification_settings['expired_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="1">Remind me tomorrow</a> 259 <a href="#" class="dismiss-notification reminder-btn" data-message-id="<?php echo esc_attr($this->notification_settings['expired_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="7">Remind me in 1 week</a> 260 <a href="#" class="dismiss-notification reminder-btn" data-message-id="<?php echo esc_attr($this->notification_settings['expired_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="30">Remind me in 1 month</a> 261 </span> 252 262 </p> 253 263 </div> … … 260 270 * Display notification for subscription expiring soon 261 271 * 262 * @param int $days_remaining Number of days remaining until expiration272 * @param int $days_remaining The number of days remaining until expiration 263 273 */ 264 274 public function display_expiring_soon_notification($days_remaining) … … 276 286 $renew_url = $gbt_dashboard->get_theme_sales_page_url(); 277 287 288 // Format days remaining text 289 $days_text = $days_remaining == 1 ? 'day' : 'days'; 290 278 291 ?> 279 292 <div class="notice-warning settings-error notice getbowtied_ext_notice gbt-dashboard-notification" 280 data-message-id="<?php echo esc_attr($this->notification_settings['expiring_soon_id']); ?>" 293 data-message-id="<?php echo esc_attr($this->notification_settings['expiring_soon_id']); ?>" 281 294 data-theme-slug="<?php echo esc_attr($theme_slug); ?>"> 282 295 <div class="getbowtied_ext_notice__aside"> … … 285 298 286 299 <div class="getbowtied_ext_notice__content"> 287 <h3 class="title">IMPORTANT: YOUR <?php echo esc_html(strtoupper($theme_name)); ?> Professional Plan <?php 300 <div class="title-container"> 301 <h3 class="title">IMPORTANT: Your <?php echo esc_html($theme_name); ?> Professional Plan <?php 288 302 if ($days_remaining == 0) { 289 echo ' EXPIRES TODAY!';303 echo 'expires today!'; 290 304 } elseif ($days_remaining == 1) { 291 echo ' EXPIRES TOMORROW!';305 echo 'expires tomorrow!'; 292 306 } else { 293 echo ' EXPIRES IN ' . esc_html($days_remaining) . ' DAYS!';307 echo 'expires in ' . esc_html($days_remaining) . ' days!'; 294 308 } 295 309 ?></h3> 296 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 310 <a href="#" class="getbowtied_ext_notice__toggle_link">Click for details</a> 311 </div> 297 312 <div class="getbowtied_ext_notice__collapsible_content"> 298 313 <h4>Your <?php echo esc_html($theme_name); ?> Professional Plan will expire on <?php echo esc_html($expiration_date); ?>, putting your site at risk.</h4> … … 311 326 312 327 <ul> 313 <li class="dashicons-before dashicons-shield-alt"> Automaticcritical security updates</li>314 <li class="dashicons-before dashicons-update-alt"> Automaticpriority bug fixes, security & compatibility updates</li>328 <li class="dashicons-before dashicons-shield-alt">Built-in critical security updates</li> 329 <li class="dashicons-before dashicons-update-alt">Built-in priority bug fixes, security & compatibility updates</li> 315 330 <li class="dashicons-before dashicons-admin-users">Expert assistance from a dedicated developer</li> 316 331 </ul> … … 323 338 <a href="<?php echo esc_url($license_details_url); ?>" class="button button-primary button-large">View Your License Details</a> 324 339 325 <a href="#" class="dismiss-notification" data-message-id="<?php echo esc_attr($this->notification_settings['expiring_soon_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>">Remind Me Later</a> 340 <span class="reminder-options"> 341 <a href="#" class="dismiss-notification reminder-btn" data-message-id="<?php echo esc_attr($this->notification_settings['expiring_soon_id']); ?>" data-theme-slug="<?php echo esc_attr($theme_slug); ?>" data-days="1">Remind me tomorrow</a> 342 </span> 326 343 </p> 327 344 </div> 328 345 </div> 329 346 </div> 330 <?php347 <?php 331 348 } 332 349 … … 371 388 } 372 389 373 // Check if dismiss period has passed 374 $dismissed_time = $dismissed[$theme_slug]; 375 $dismiss_seconds = $this->notification_settings['dismiss_days'] * DAY_IN_SECONDS; 390 // Check if stored value is an array (new format) or timestamp (old format) 391 if (is_array($dismissed[$theme_slug])) { 392 $dismissed_time = $dismissed[$theme_slug]['time']; 393 $dismiss_days = $dismissed[$theme_slug]['days']; 394 } else { 395 // Legacy format - just a timestamp with default days 396 $dismissed_time = $dismissed[$theme_slug]; 397 $dismiss_days = $this->notification_settings['dismiss_days']; 398 } 399 400 // Calculate dismiss period 401 $dismiss_seconds = $dismiss_days * DAY_IN_SECONDS; 376 402 377 403 // Still dismissed if within the dismissal period … … 410 436 $message_id = isset($_POST['message_id']) ? sanitize_text_field($_POST['message_id']) : ''; 411 437 $theme_slug = isset($_POST['theme_slug']) ? sanitize_text_field($_POST['theme_slug']) : ''; 438 $days = isset($_POST['days']) ? absint($_POST['days']) : $this->notification_settings['dismiss_days']; 412 439 413 440 // Get the appropriate dismiss option based on message ID … … 418 445 } 419 446 420 // Save dismissal timestamp 421 $this->save_notification_dismissal($theme_slug, $dismiss_option );447 // Save dismissal timestamp with days parameter 448 $this->save_notification_dismissal($theme_slug, $dismiss_option, $days); 422 449 423 450 wp_send_json_success(); … … 437 464 case $this->notification_settings['expiring_soon_id']: 438 465 return $this->notification_settings['dismiss_soon_option']; 466 case 'license_no_license_detected': 467 return $this->notification_settings['dismiss_option']; 439 468 default: 440 469 return false; … … 447 476 * @param string $theme_slug The theme slug to associate with dismissal 448 477 * @param string $option_name The option name to update 449 */ 450 private function save_notification_dismissal($theme_slug, $option_name) 478 * @param int $days Number of days to dismiss for 479 */ 480 private function save_notification_dismissal($theme_slug, $option_name, $days = 1) 451 481 { 452 482 $dismissed = get_option($option_name, []); 453 $dismissed[$theme_slug] = time(); 483 // Store both the time and the number of days to dismiss for 484 $dismissed[$theme_slug] = [ 485 'time' => time(), 486 'days' => $days 487 ]; 454 488 update_option($option_name, $dismissed); 455 489 } -
shopkeeper-extender/trunk/dashboard/inc/pages/content/license.php
r3267058 r3268043 250 250 // Auto-verify license on page load if there's an active license 251 251 if (!empty($stored_options['license_key']) && !isset($_GET['license_updated'])) { 252 // Only do this if not immediately after a license update to avoid duplicate checks 253 $auto_check_result = $license_manager->cron_process_license(); 254 255 // If the check failed due to domain restriction, the license will be cleared 256 // Update stored options to match the current state after verification 257 if ($auto_check_result && !$auto_check_result['success']) { 258 $stored_options = $auto_check_result['license_data']; 259 $license_key = $stored_options['license_key'] ?? ''; 260 $license_status = $stored_options['license_status'] ?? 'inactive'; 261 $license_info = $stored_options['license_info'] ?? []; 262 $support_expiration_date = $stored_options['support_expiration_date'] ?? ''; 263 264 // Set transient to show notification on this page load 265 set_transient('gbt_license_result', $auto_check_result, 60); 252 // Check when the license was last verified and only perform the check 253 // if it has been more than 30 days since the last verification 254 $last_verified = $license_manager->get_last_verified_time(); 255 $current_time = time(); 256 $interval_days = 30; 257 $interval_seconds = $interval_days * DAY_IN_SECONDS; 258 259 if ($current_time - $last_verified >= $interval_seconds) { 260 // Only do this if not immediately after a license update to avoid duplicate checks 261 $auto_check_result = $license_manager->cron_process_license(); 262 263 // If the check failed due to domain restriction, the license will be cleared 264 // Update stored options to match the current state after verification 265 if ($auto_check_result && !$auto_check_result['success']) { 266 $stored_options = $auto_check_result['license_data']; 267 $license_key = $stored_options['license_key'] ?? ''; 268 $license_status = $stored_options['license_status'] ?? 'inactive'; 269 $license_info = $stored_options['license_info'] ?? []; 270 $support_expiration_date = $stored_options['support_expiration_date'] ?? ''; 271 272 // Set transient to show notification on this page load 273 set_transient('gbt_license_result', $auto_check_result, 60); 274 } 266 275 } 267 276 } … … 882 891 <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" /> 883 892 </svg> 884 <span class="text-gray-600"> Automaticcritical security updates</span>893 <span class="text-gray-600">Built-in critical security updates</span> 885 894 </li> 886 895 <li class="flex gap-x-3"> … … 888 897 <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" /> 889 898 </svg> 890 <span class="text-gray-600"> Automaticpriority bug fixes</span>899 <span class="text-gray-600">Built-in priority bug fixes</span> 891 900 </li> 892 901 <li class="flex gap-x-3"> … … 965 974 <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z" clip-rule="evenodd" /> 966 975 </svg> 967 Automaticcritical security updates976 Built-in critical security updates 968 977 </li> 969 978 <li class="flex gap-x-3"> … … 977 986 <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z" clip-rule="evenodd" /> 978 987 </svg> 979 Automaticpriority bug fixes988 Built-in priority bug fixes 980 989 </li> 981 990 <li class="flex gap-x-3"> -
shopkeeper-extender/trunk/dashboard/inc/pages/includes.php
r3267058 r3268043 90 90 } 91 91 92 // Dashboard Message 93 wp_enqueue_script( 94 'gbt-dashboard-notification', 95 $base_paths['url'] . '/dashboard/js/notifications.js', 96 array('jquery'), 97 $theme_version_gbt_dash, 98 true 99 ); 92 if (isset($_GET['page']) && $_GET['page'] === 'getbowtied-theme-documentation') { 93 wp_enqueue_script( 94 'gbt-documentation-iframe', 95 $base_paths['url'] . '/dashboard/js/iframe.js', 96 array('jquery'), 97 $theme_version_gbt_dash, 98 true 99 ); 100 } 100 101 101 wp_localize_script( 102 'gbt-dashboard-notification', 103 'gbtDashboard', 104 array( 105 'nonce' => wp_create_nonce('dismiss_message') 106 ) 107 ); 102 // Removed old Dashboard Message script - now using global notification handler 108 103 } 109 104 -
shopkeeper-extender/trunk/dashboard/index.php
r3267058 r3268043 174 174 if (get_option('gbt_theme_updated_redirect')) { 175 175 delete_option('gbt_theme_updated_redirect'); 176 177 // Clear notification transients after theme update 178 if (class_exists('GBT_Notification_Handler')) { 179 gbt_notification_handler()->clear_all_notification_transients(); 180 } 181 182 // Clear license notification dismissals to show them after update 183 if (class_exists('GBT_License_Subscription_Checker')) { 184 $theme_slug = $this->get_theme_slug(); 185 186 // Get the option keys for dismissals 187 $expired_option = 'getbowtied_theme_license_subscription_expired_dismissed'; 188 $expiring_option = 'getbowtied_theme_license_subscription_expiring_soon_dismissed'; 189 190 // Get the current dismissal data 191 $expired_data = get_option($expired_option, []); 192 $expiring_data = get_option($expiring_option, []); 193 194 // Remove dismissals for this theme 195 if (isset($expired_data[$theme_slug])) { 196 unset($expired_data[$theme_slug]); 197 update_option($expired_option, $expired_data); 198 } 199 200 if (isset($expiring_data[$theme_slug])) { 201 unset($expiring_data[$theme_slug]); 202 update_option($expiring_option, $expiring_data); 203 } 204 205 // The no-license notification also uses the expired_option, but we've already cleared that 206 } 207 176 208 $this->redirect_to_dashboard(); 177 209 } … … 518 550 519 551 private function validate_message($message_data) { 520 if (!$this->is_valid_message($message_data)) { 521 return false; 522 } 523 524 $dismissed_messages = get_user_meta(get_current_user_id(), 'gbt_dashboard_dismissed_notifications', true); 525 if (is_array($dismissed_messages) && in_array($message_data['id'], $dismissed_messages)) { 526 return false; 527 } 528 529 if (!$message_data['active']) { 552 if (!$this->is_valid_message($message_data) || 553 !$message_data['active'] || 554 gbt_notification_handler()->is_dismissed($message_data['id'])) { 530 555 return false; 531 556 } … … 535 560 $end_date = strtotime($message_data['end_date']); 536 561 537 if ($current_time >= $start_date && $current_time <= $end_date) { 538 return $message_data; 539 } 540 541 return false; 562 return ($current_time >= $start_date && $current_time <= $end_date) ? $message_data : false; 542 563 } 543 564 … … 551 572 552 573 public function display_dashboard_message() { 553 $message_data = $this->get_external_message();554 555 if ($message_data) {556 ?>557 <div class="notice notice-success is-dismissible gbt-dashboard-notification"558 data-message-id="<?php echo esc_attr($message_data['id']); ?>"559 data-theme-slug="<?php echo esc_attr($this->theme_slug_gbt_dash); ?>">560 <p><?php echo wp_kses_post($message_data['message']); ?></p>561 </div>562 <?php 563 }564 }565 574 if ($message_data = $this->get_external_message()) { 575 printf( 576 '<div class="notice notice-success is-dismissible gbt-dashboard-notification" data-message-id="%s" data-theme-slug="%s"><p>%s</p></div>', 577 esc_attr($message_data['id']), 578 esc_attr($this->theme_slug_gbt_dash), 579 wp_kses_post($message_data['message']) 580 ); 581 } 582 } 583 584 /** 585 * Handle message dismissal via AJAX (Legacy method) 586 */ 566 587 public function handle_message_dismissal() { 567 588 check_ajax_referer('dismiss_message', 'nonce'); … … 572 593 573 594 $message_id = isset($_POST['message_id']) ? sanitize_text_field($_POST['message_id']) : ''; 574 $theme_slug = isset($_POST['theme_slug']) ? sanitize_text_field($_POST['theme_slug']) : ''; 575 576 if ($message_id && $theme_slug) { 577 $dismissed_messages = get_user_meta(get_current_user_id(), 'gbt_dashboard_dismissed_notifications', true); 578 if (!is_array($dismissed_messages)) { 579 $dismissed_messages = array(); 580 } 581 $dismissed_messages[] = $message_id; 582 update_user_meta(get_current_user_id(), 'gbt_dashboard_dismissed_notifications', $dismissed_messages); 595 596 if ($message_id) { 597 gbt_notification_handler()->save_dismissal($message_id); 583 598 } 584 599 -
shopkeeper-extender/trunk/dashboard/js/license-subscription-notification.js
r3267058 r3268043 6 6 (function($) { 7 7 'use strict'; 8 9 // Configuration 10 const config = { 11 autoExpandNoLicense: false // Set to true to auto-expand no-license notifications 12 }; 8 13 9 14 // Wait for DOM to be ready … … 16 21 } 17 22 18 // Auto-expand no-license notification when not on the license page19 if ( !window.location.href.includes('page=getbowtied-license')) {23 // Auto-expand no-license notification when configured 24 if (config.autoExpandNoLicense && !window.location.href.includes('page=getbowtied-license')) { 20 25 // Add a slight delay to ensure DOM is fully loaded and ready 21 26 setTimeout(function() { … … 29 34 } 30 35 31 // Handle dismiss button click - updated for Remind Me Later button 36 // Function to toggle content visibility 37 function toggleContent($content) { 38 // Toggle the expanded class 39 $content.toggleClass('expanded'); 40 41 // Update the More details link text based on expanded state 42 const $link = $content.find('.getbowtied_ext_notice__toggle_link'); 43 $link.text($content.hasClass('expanded') ? 'Hide details' : 'Click for details'); 44 } 45 46 // Toggle collapsible content when clicking on title 47 $notifications.on('click', '.title', function(e) { 48 e.preventDefault(); 49 const $content = $(this).closest('.getbowtied_ext_notice__content'); 50 toggleContent($content); 51 }); 52 53 // Toggle collapsible content when clicking on the "More details" link 54 $notifications.on('click', '.getbowtied_ext_notice__toggle_link', function(e) { 55 e.preventDefault(); 56 const $content = $(this).closest('.getbowtied_ext_notice__content'); 57 toggleContent($content); 58 }); 59 60 // Handle both "View License Details" and "Activate Your License Now" button clicks 61 $notifications.on('click', 'a[href*="page=getbowtied-license"]', function(e) { 62 e.preventDefault(); 63 var href = $(this).attr('href'); 64 65 // Navigate to the license page if we're not already there 66 if (!window.location.href.includes('page=getbowtied-license')) { 67 // Simply navigate to the URL without any scroll parameter 68 window.location.href = href; 69 return; 70 } 71 72 // If we're already on the license page, scroll to the dashboard scope 73 scrollToDashboard(); 74 }); 75 76 // Check if we need to scroll on page load (coming from external page) 77 function scrollToDashboard() { 78 var $target = $('.gbt-dashboard-scope'); 79 if ($target.length) { 80 $('html, body').animate({ 81 scrollTop: $target.offset().top 82 }, 500); 83 } 84 } 85 86 // Handle dismiss button click - updated for individual reminder buttons 32 87 $notifications.on('click', '.dismiss-notification', function(e) { 33 // Prevent default action since this is now an anchor tag88 // Prevent default action 34 89 e.preventDefault(); 35 90 … … 37 92 const messageId = $button.data('message-id'); 38 93 const themeSlug = $button.data('theme-slug'); 94 const days = $button.data('days'); 39 95 const $notification = $button.closest('.gbt-dashboard-notification'); 40 96 … … 53 109 message_id: messageId, 54 110 theme_slug: themeSlug, 111 days: days, 55 112 nonce: gbtLicenseSubscriptionData.nonce 56 113 }, … … 108 165 }); 109 166 }); 110 111 // Handle both "View License Details" and "Activate Your License Now" button clicks112 $notifications.on('click', 'a[href*="page=getbowtied-license"]', function(e) {113 e.preventDefault();114 var href = $(this).attr('href');115 116 // Navigate to the license page if we're not already there117 if (!window.location.href.includes('page=getbowtied-license')) {118 // Simply navigate to the URL without any scroll parameter119 window.location.href = href;120 return;121 }122 123 // If we're already on the license page, scroll to the dashboard scope124 scrollToDashboard();125 });126 127 // Check if we need to scroll on page load (coming from external page)128 function scrollToDashboard() {129 var $target = $('.gbt-dashboard-scope');130 if ($target.length) {131 $('html, body').animate({132 scrollTop: $target.offset().top133 }, 500);134 }135 }136 137 // Function to toggle content visibility138 function toggleContent($content) {139 // Toggle the expanded class140 $content.toggleClass('expanded');141 142 // Update the More details link text based on expanded state143 const $link = $content.find('.getbowtied_ext_notice__toggle_link');144 $link.text($content.hasClass('expanded') ? 'Hide details' : 'Click for details');145 }146 147 // Toggle collapsible content when clicking on title148 $notifications.on('click', '.title', function(e) {149 e.preventDefault();150 const $content = $(this).closest('.getbowtied_ext_notice__content');151 toggleContent($content);152 });153 154 // Toggle collapsible content when clicking on the "More details" link155 $notifications.on('click', '.getbowtied_ext_notice__toggle_link', function(e) {156 e.preventDefault();157 const $content = $(this).closest('.getbowtied_ext_notice__content');158 toggleContent($content);159 });160 167 }); 161 168 })(jQuery); -
shopkeeper-extender/trunk/dashboard/setup.php
r3267058 r3268043 9 9 include_once( $base_paths['path'] . '/dashboard/inc/pages/setup.php' ); 10 10 include_once( $base_paths['path'] . '/dashboard/inc/classes/class-theme-li.php' ); 11 include_once( $base_paths['path'] . '/dashboard/inc/classes/class-gbt-notification-handler.php' ); 11 12 12 13 // Only include pointers if theme is not Block Shop -
shopkeeper-extender/trunk/shopkeeper-extender.php
r3267058 r3268043 5 5 * Plugin URI: https://shopkeeper.wp-theme.design/ 6 6 * Description: Extends the functionality of Shopkeeper with theme specific features. 7 * Version: 5. 07 * Version: 5.1 8 8 * Author: Get Bowtied 9 9 * Author URI: https://getbowtied.com
Note: See TracChangeset
for help on using the changeset viewer.