Plugin Directory

Changeset 3268043


Ignore:
Timestamp:
04/07/2025 05:35:06 PM (12 months ago)
Author:
getbowtied
Message:

Update to version 5.1 from GitHub

Location:
shopkeeper-extender
Files:
4 added
2 deleted
20 edited
1 copied

Legend:

Unmodified
Added
Removed
  • shopkeeper-extender/tags/5.1/README.txt

    r3267058 r3268043  
    138138== Changelog ==
    139139
    140 = 5.0 =
     140= 5.1 =
    141141- Maintenance update
    142142
  • shopkeeper-extender/tags/5.1/core/updater/assets/plugin.json

    r3267058 r3268043  
    11{
    22    "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",
    55
    66    "homepage": "https://wordpress.org/plugins/shopkeeper-extender/",
    77    "requires": "6.0",
    88    "tested": "6.7.2",
    9     "last_updated": "2025-04-04 12:00:00",
     9    "last_updated": "2025-04-07 12:00:00",
    1010
    1111    "author": "GetBowtied",
     
    1414    "sections": {
    1515        "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>"
    1717    },
    1818
  • shopkeeper-extender/tags/5.1/dashboard/css/license-notifications.css

    r3267058 r3268043  
    1818.getbowtied_ext_notice__collapsible_content {
    1919  display: none; /* Hide by default */
     20  width: 100%;
    2021}
    2122
     
    2526  margin-bottom: 0;
    2627  margin-right: 10px;
    27   text-transform: uppercase;
    28   letter-spacing: 0.6px;
    29   font-weight: 700;
     28  text-transform: none;
    3029  display: inline-block;
    3130  background-color: #ffea00;
     
    269268  position: relative;
    270269  overflow: visible;
    271   max-width: calc(100% - 450px); /* Add max-width to avoid text overlap with background icon */
     270  max-width: calc(100% - 450px);
    272271  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;
    274279  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%;
    275302}
    276303
     
    458485/* Hide dismiss button and Remind Me Later for no-license notification */
    459486.no-license-notification .notice-dismiss,
    460 .no-license-notification .dismiss-notification {
     487.no-license-notification .dismiss-notification,
     488.no-license-notification .reminder-options {
    461489    display: none !important;
     490}
     491
     492.no-license-notification .title strong {
     493  font-weight: 700;
    462494}
    463495
    464496/* Styles for Remind Me Later button */
    465497.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;
    473501}
    474502
    475503.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    }
    479575}
    480576
     
    492588 
    493589  .getbowtied_ext_notice .getbowtied_ext_notice__content {
    494     padding: 15px;
     590    padding: 12px;
    495591  }
    496592 
     
    513609    width: 100%;
    514610    text-align: center;
    515     margin: 0 0 8px 0;
     611    margin: 0 0 5px 0; /* Reduce bottom margin */
    516612    box-sizing: border-box;
    517613  }
     
    521617    display: flex;
    522618    flex-direction: column;
    523     margin-top: 15px;
     619    margin-top: 10px; /* Reduce top margin */
    524620    margin-bottom: 0;
    525621  }
     
    529625    display: block;
    530626    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 */
    533629    color: #666;
    534     border-top: 1px solid #eee;
     630    border-top: none;
    535631  }
    536632 
  • shopkeeper-extender/tags/5.1/dashboard/inc/classes/class-license-subscription-checker.php

    r3267058 r3268043  
    175175
    176176            <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>
    179181                <div class="getbowtied_ext_notice__collapsible_content">
    180182                    <p>Your <?php echo esc_html($theme_name); ?> theme is currently operating without a valid license key.</p>
     
    190192                    <p>
    191193                        <a href="<?php echo esc_url($license_page_url); ?>" class="button button-primary button-large">Activate Your License Now</a>
    192                         &nbsp;
    193194                        <a href="<?php echo esc_url($purchase_url); ?>" target="_blank" class="button button-large">Get a License</a>
    194                         &nbsp;
    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>
    196200                    </p>
    197201                </div>
     
    223227
    224228            <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>
    227233                <div class="getbowtied_ext_notice__collapsible_content">
    228234                    <h4>Your <?php echo esc_html($theme_name); ?> theme Professional Plan has ended, putting your website at risk.</h4>
     
    233239
    234240                    <ul>
    235                         <li class="dashicons-before dashicons-shield-alt">Automatic critical security updates</li>
    236                         <li class="dashicons-before dashicons-update-alt">Automatic priority 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>
    237243                        <li class="dashicons-before dashicons-admin-users">Expert assistance from a dedicated developer</li>
    238244                    </ul>
     
    249255                        <a href="<?php echo esc_url($license_details_url); ?>" class="button button-primary button-large">View Your License Details</a>
    250256                        &nbsp;
    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>
    252262                    </p>
    253263                </div>
     
    260270     * Display notification for subscription expiring soon
    261271     *
    262      * @param int $days_remaining Number of days remaining until expiration
     272     * @param int $days_remaining The number of days remaining until expiration
    263273     */
    264274    public function display_expiring_soon_notification($days_remaining)
     
    276286        $renew_url = $gbt_dashboard->get_theme_sales_page_url();
    277287
     288        // Format days remaining text
     289        $days_text = $days_remaining == 1 ? 'day' : 'days';
     290
    278291    ?>
    279292        <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']); ?>" 
    281294            data-theme-slug="<?php echo esc_attr($theme_slug); ?>">
    282295            <div class="getbowtied_ext_notice__aside">
     
    285298
    286299            <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
    288302                                                                                                                    if ($days_remaining == 0) {
    289                                                                                                                         echo 'EXPIRES TODAY!';
     303                                                                                                                        echo 'expires today!';
    290304                                                                                                                    } elseif ($days_remaining == 1) {
    291                                                                                                                         echo 'EXPIRES TOMORROW!';
     305                                                                                                                        echo 'expires tomorrow!';
    292306                                                                                                                    } else {
    293                                                                                                                         echo 'EXPIRES IN ' . esc_html($days_remaining) . ' DAYS!';
     307                                                                                                                        echo 'expires in ' . esc_html($days_remaining) . ' days!';
    294308                                                                                                                    }
    295309                                                                                                                    ?></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>
    297312                <div class="getbowtied_ext_notice__collapsible_content">
    298313                    <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>
     
    311326
    312327                    <ul>
    313                         <li class="dashicons-before dashicons-shield-alt">Automatic critical security updates</li>
    314                         <li class="dashicons-before dashicons-update-alt">Automatic priority 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>
    315330                        <li class="dashicons-before dashicons-admin-users">Expert assistance from a dedicated developer</li>
    316331                    </ul>
     
    323338                        <a href="<?php echo esc_url($license_details_url); ?>" class="button button-primary button-large">View Your License Details</a>
    324339                        &nbsp;
    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>
    326343                    </p>
    327344                </div>
    328345            </div>
    329346        </div>
    330 <?php
     347    <?php
    331348    }
    332349
     
    371388        }
    372389
    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;
    376402
    377403        // Still dismissed if within the dismissal period
     
    410436        $message_id = isset($_POST['message_id']) ? sanitize_text_field($_POST['message_id']) : '';
    411437        $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'];
    412439
    413440        // Get the appropriate dismiss option based on message ID
     
    418445        }
    419446
    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);
    422449
    423450        wp_send_json_success();
     
    437464            case $this->notification_settings['expiring_soon_id']:
    438465                return $this->notification_settings['dismiss_soon_option'];
     466            case 'license_no_license_detected':
     467                return $this->notification_settings['dismiss_option'];
    439468            default:
    440469                return false;
     
    447476     * @param string $theme_slug The theme slug to associate with dismissal
    448477     * @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)
    451481    {
    452482        $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        ];
    454488        update_option($option_name, $dismissed);
    455489    }
  • shopkeeper-extender/tags/5.1/dashboard/inc/pages/content/license.php

    r3267058 r3268043  
    250250        // Auto-verify license on page load if there's an active license
    251251        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                }
    266275            }
    267276        }
     
    882891                                    <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" />
    883892                                </svg>
    884                                 <span class="text-gray-600">Automatic critical security updates</span>
     893                                <span class="text-gray-600">Built-in critical security updates</span>
    885894                            </li>
    886895                            <li class="flex gap-x-3">
     
    888897                                    <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" />
    889898                                </svg>
    890                                 <span class="text-gray-600">Automatic priority bug fixes</span>
     899                                <span class="text-gray-600">Built-in priority bug fixes</span>
    891900                            </li>
    892901                            <li class="flex gap-x-3">
     
    965974                                    <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" />
    966975                                </svg>
    967                                 Automatic critical security updates
     976                                Built-in critical security updates
    968977                            </li>
    969978                            <li class="flex gap-x-3">
     
    977986                                    <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" />
    978987                                </svg>
    979                                 Automatic priority bug fixes
     988                                Built-in priority bug fixes
    980989                            </li>
    981990                            <li class="flex gap-x-3">
  • shopkeeper-extender/tags/5.1/dashboard/inc/pages/includes.php

    r3267058 r3268043  
    9090        }
    9191
    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        }
    100101
    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
    108103    }
    109104
  • shopkeeper-extender/tags/5.1/dashboard/index.php

    r3267058 r3268043  
    174174            if (get_option('gbt_theme_updated_redirect')) {
    175175                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               
    176208                $this->redirect_to_dashboard();
    177209            }
     
    518550
    519551        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'])) {
    530555                return false;
    531556            }
     
    535560            $end_date = strtotime($message_data['end_date']);
    536561           
    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;
    542563        }
    543564
     
    551572
    552573        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         */
    566587        public function handle_message_dismissal() {
    567588            check_ajax_referer('dismiss_message', 'nonce');
     
    572593
    573594            $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);
    583598            }
    584599           
  • shopkeeper-extender/tags/5.1/dashboard/js/license-subscription-notification.js

    r3267058 r3268043  
    66(function($) {
    77    'use strict';
     8   
     9    // Configuration
     10    const config = {
     11        autoExpandNoLicense: false // Set to true to auto-expand no-license notifications
     12    };
    813   
    914    // Wait for DOM to be ready
     
    1621        }
    1722       
    18         // Auto-expand no-license notification when not on the license page
    19         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')) {
    2025            // Add a slight delay to ensure DOM is fully loaded and ready
    2126            setTimeout(function() {
     
    2934        }
    3035       
    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
    3287        $notifications.on('click', '.dismiss-notification', function(e) {
    33             // Prevent default action since this is now an anchor tag
     88            // Prevent default action
    3489            e.preventDefault();
    3590           
     
    3792            const messageId = $button.data('message-id');
    3893            const themeSlug = $button.data('theme-slug');
     94            const days = $button.data('days');
    3995            const $notification = $button.closest('.gbt-dashboard-notification');
    4096           
     
    53109                    message_id: messageId,
    54110                    theme_slug: themeSlug,
     111                    days: days,
    55112                    nonce: gbtLicenseSubscriptionData.nonce
    56113                },
     
    108165            });
    109166        });
    110        
    111         // Handle both "View License Details" and "Activate Your License Now" button clicks
    112         $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 there
    117             if (!window.location.href.includes('page=getbowtied-license')) {
    118                 // Simply navigate to the URL without any scroll parameter
    119                 window.location.href = href;
    120                 return;
    121             }
    122            
    123             // If we're already on the license page, scroll to the dashboard scope
    124             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().top
    133                 }, 500);
    134             }
    135         }
    136        
    137         // Function to toggle content visibility
    138         function toggleContent($content) {
    139             // Toggle the expanded class
    140             $content.toggleClass('expanded');
    141            
    142             // Update the More details link text based on expanded state
    143             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 title
    148         $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" link
    155         $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         });
    160167    });
    161168})(jQuery);
  • shopkeeper-extender/tags/5.1/dashboard/setup.php

    r3267058 r3268043  
    99include_once( $base_paths['path'] . '/dashboard/inc/pages/setup.php' );
    1010include_once( $base_paths['path'] . '/dashboard/inc/classes/class-theme-li.php' );
     11include_once( $base_paths['path'] . '/dashboard/inc/classes/class-gbt-notification-handler.php' );
    1112
    1213// Only include pointers if theme is not Block Shop
  • shopkeeper-extender/tags/5.1/shopkeeper-extender.php

    r3267058 r3268043  
    55 * Plugin URI:              https://shopkeeper.wp-theme.design/
    66 * Description:             Extends the functionality of Shopkeeper with theme specific features.
    7  * Version:                 5.0
     7 * Version:                 5.1
    88 * Author:                  Get Bowtied
    99 * Author URI:              https://getbowtied.com
  • shopkeeper-extender/trunk/README.txt

    r3267058 r3268043  
    138138== Changelog ==
    139139
    140 = 5.0 =
     140= 5.1 =
    141141- Maintenance update
    142142
  • shopkeeper-extender/trunk/core/updater/assets/plugin.json

    r3267058 r3268043  
    11{
    22    "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",
    55
    66    "homepage": "https://wordpress.org/plugins/shopkeeper-extender/",
    77    "requires": "6.0",
    88    "tested": "6.7.2",
    9     "last_updated": "2025-04-04 12:00:00",
     9    "last_updated": "2025-04-07 12:00:00",
    1010
    1111    "author": "GetBowtied",
     
    1414    "sections": {
    1515        "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>"
    1717    },
    1818
  • shopkeeper-extender/trunk/dashboard/css/license-notifications.css

    r3267058 r3268043  
    1818.getbowtied_ext_notice__collapsible_content {
    1919  display: none; /* Hide by default */
     20  width: 100%;
    2021}
    2122
     
    2526  margin-bottom: 0;
    2627  margin-right: 10px;
    27   text-transform: uppercase;
    28   letter-spacing: 0.6px;
    29   font-weight: 700;
     28  text-transform: none;
    3029  display: inline-block;
    3130  background-color: #ffea00;
     
    269268  position: relative;
    270269  overflow: visible;
    271   max-width: calc(100% - 450px); /* Add max-width to avoid text overlap with background icon */
     270  max-width: calc(100% - 450px);
    272271  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;
    274279  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%;
    275302}
    276303
     
    458485/* Hide dismiss button and Remind Me Later for no-license notification */
    459486.no-license-notification .notice-dismiss,
    460 .no-license-notification .dismiss-notification {
     487.no-license-notification .dismiss-notification,
     488.no-license-notification .reminder-options {
    461489    display: none !important;
     490}
     491
     492.no-license-notification .title strong {
     493  font-weight: 700;
    462494}
    463495
    464496/* Styles for Remind Me Later button */
    465497.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;
    473501}
    474502
    475503.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    }
    479575}
    480576
     
    492588 
    493589  .getbowtied_ext_notice .getbowtied_ext_notice__content {
    494     padding: 15px;
     590    padding: 12px;
    495591  }
    496592 
     
    513609    width: 100%;
    514610    text-align: center;
    515     margin: 0 0 8px 0;
     611    margin: 0 0 5px 0; /* Reduce bottom margin */
    516612    box-sizing: border-box;
    517613  }
     
    521617    display: flex;
    522618    flex-direction: column;
    523     margin-top: 15px;
     619    margin-top: 10px; /* Reduce top margin */
    524620    margin-bottom: 0;
    525621  }
     
    529625    display: block;
    530626    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 */
    533629    color: #666;
    534     border-top: 1px solid #eee;
     630    border-top: none;
    535631  }
    536632 
  • shopkeeper-extender/trunk/dashboard/inc/classes/class-license-subscription-checker.php

    r3267058 r3268043  
    175175
    176176            <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>
    179181                <div class="getbowtied_ext_notice__collapsible_content">
    180182                    <p>Your <?php echo esc_html($theme_name); ?> theme is currently operating without a valid license key.</p>
     
    190192                    <p>
    191193                        <a href="<?php echo esc_url($license_page_url); ?>" class="button button-primary button-large">Activate Your License Now</a>
    192                         &nbsp;
    193194                        <a href="<?php echo esc_url($purchase_url); ?>" target="_blank" class="button button-large">Get a License</a>
    194                         &nbsp;
    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>
    196200                    </p>
    197201                </div>
     
    223227
    224228            <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>
    227233                <div class="getbowtied_ext_notice__collapsible_content">
    228234                    <h4>Your <?php echo esc_html($theme_name); ?> theme Professional Plan has ended, putting your website at risk.</h4>
     
    233239
    234240                    <ul>
    235                         <li class="dashicons-before dashicons-shield-alt">Automatic critical security updates</li>
    236                         <li class="dashicons-before dashicons-update-alt">Automatic priority 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>
    237243                        <li class="dashicons-before dashicons-admin-users">Expert assistance from a dedicated developer</li>
    238244                    </ul>
     
    249255                        <a href="<?php echo esc_url($license_details_url); ?>" class="button button-primary button-large">View Your License Details</a>
    250256                        &nbsp;
    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>
    252262                    </p>
    253263                </div>
     
    260270     * Display notification for subscription expiring soon
    261271     *
    262      * @param int $days_remaining Number of days remaining until expiration
     272     * @param int $days_remaining The number of days remaining until expiration
    263273     */
    264274    public function display_expiring_soon_notification($days_remaining)
     
    276286        $renew_url = $gbt_dashboard->get_theme_sales_page_url();
    277287
     288        // Format days remaining text
     289        $days_text = $days_remaining == 1 ? 'day' : 'days';
     290
    278291    ?>
    279292        <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']); ?>" 
    281294            data-theme-slug="<?php echo esc_attr($theme_slug); ?>">
    282295            <div class="getbowtied_ext_notice__aside">
     
    285298
    286299            <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
    288302                                                                                                                    if ($days_remaining == 0) {
    289                                                                                                                         echo 'EXPIRES TODAY!';
     303                                                                                                                        echo 'expires today!';
    290304                                                                                                                    } elseif ($days_remaining == 1) {
    291                                                                                                                         echo 'EXPIRES TOMORROW!';
     305                                                                                                                        echo 'expires tomorrow!';
    292306                                                                                                                    } else {
    293                                                                                                                         echo 'EXPIRES IN ' . esc_html($days_remaining) . ' DAYS!';
     307                                                                                                                        echo 'expires in ' . esc_html($days_remaining) . ' days!';
    294308                                                                                                                    }
    295309                                                                                                                    ?></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>
    297312                <div class="getbowtied_ext_notice__collapsible_content">
    298313                    <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>
     
    311326
    312327                    <ul>
    313                         <li class="dashicons-before dashicons-shield-alt">Automatic critical security updates</li>
    314                         <li class="dashicons-before dashicons-update-alt">Automatic priority 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>
    315330                        <li class="dashicons-before dashicons-admin-users">Expert assistance from a dedicated developer</li>
    316331                    </ul>
     
    323338                        <a href="<?php echo esc_url($license_details_url); ?>" class="button button-primary button-large">View Your License Details</a>
    324339                        &nbsp;
    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>
    326343                    </p>
    327344                </div>
    328345            </div>
    329346        </div>
    330 <?php
     347    <?php
    331348    }
    332349
     
    371388        }
    372389
    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;
    376402
    377403        // Still dismissed if within the dismissal period
     
    410436        $message_id = isset($_POST['message_id']) ? sanitize_text_field($_POST['message_id']) : '';
    411437        $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'];
    412439
    413440        // Get the appropriate dismiss option based on message ID
     
    418445        }
    419446
    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);
    422449
    423450        wp_send_json_success();
     
    437464            case $this->notification_settings['expiring_soon_id']:
    438465                return $this->notification_settings['dismiss_soon_option'];
     466            case 'license_no_license_detected':
     467                return $this->notification_settings['dismiss_option'];
    439468            default:
    440469                return false;
     
    447476     * @param string $theme_slug The theme slug to associate with dismissal
    448477     * @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)
    451481    {
    452482        $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        ];
    454488        update_option($option_name, $dismissed);
    455489    }
  • shopkeeper-extender/trunk/dashboard/inc/pages/content/license.php

    r3267058 r3268043  
    250250        // Auto-verify license on page load if there's an active license
    251251        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                }
    266275            }
    267276        }
     
    882891                                    <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" />
    883892                                </svg>
    884                                 <span class="text-gray-600">Automatic critical security updates</span>
     893                                <span class="text-gray-600">Built-in critical security updates</span>
    885894                            </li>
    886895                            <li class="flex gap-x-3">
     
    888897                                    <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" />
    889898                                </svg>
    890                                 <span class="text-gray-600">Automatic priority bug fixes</span>
     899                                <span class="text-gray-600">Built-in priority bug fixes</span>
    891900                            </li>
    892901                            <li class="flex gap-x-3">
     
    965974                                    <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" />
    966975                                </svg>
    967                                 Automatic critical security updates
     976                                Built-in critical security updates
    968977                            </li>
    969978                            <li class="flex gap-x-3">
     
    977986                                    <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" />
    978987                                </svg>
    979                                 Automatic priority bug fixes
     988                                Built-in priority bug fixes
    980989                            </li>
    981990                            <li class="flex gap-x-3">
  • shopkeeper-extender/trunk/dashboard/inc/pages/includes.php

    r3267058 r3268043  
    9090        }
    9191
    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        }
    100101
    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
    108103    }
    109104
  • shopkeeper-extender/trunk/dashboard/index.php

    r3267058 r3268043  
    174174            if (get_option('gbt_theme_updated_redirect')) {
    175175                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               
    176208                $this->redirect_to_dashboard();
    177209            }
     
    518550
    519551        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'])) {
    530555                return false;
    531556            }
     
    535560            $end_date = strtotime($message_data['end_date']);
    536561           
    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;
    542563        }
    543564
     
    551572
    552573        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         */
    566587        public function handle_message_dismissal() {
    567588            check_ajax_referer('dismiss_message', 'nonce');
     
    572593
    573594            $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);
    583598            }
    584599           
  • shopkeeper-extender/trunk/dashboard/js/license-subscription-notification.js

    r3267058 r3268043  
    66(function($) {
    77    'use strict';
     8   
     9    // Configuration
     10    const config = {
     11        autoExpandNoLicense: false // Set to true to auto-expand no-license notifications
     12    };
    813   
    914    // Wait for DOM to be ready
     
    1621        }
    1722       
    18         // Auto-expand no-license notification when not on the license page
    19         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')) {
    2025            // Add a slight delay to ensure DOM is fully loaded and ready
    2126            setTimeout(function() {
     
    2934        }
    3035       
    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
    3287        $notifications.on('click', '.dismiss-notification', function(e) {
    33             // Prevent default action since this is now an anchor tag
     88            // Prevent default action
    3489            e.preventDefault();
    3590           
     
    3792            const messageId = $button.data('message-id');
    3893            const themeSlug = $button.data('theme-slug');
     94            const days = $button.data('days');
    3995            const $notification = $button.closest('.gbt-dashboard-notification');
    4096           
     
    53109                    message_id: messageId,
    54110                    theme_slug: themeSlug,
     111                    days: days,
    55112                    nonce: gbtLicenseSubscriptionData.nonce
    56113                },
     
    108165            });
    109166        });
    110        
    111         // Handle both "View License Details" and "Activate Your License Now" button clicks
    112         $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 there
    117             if (!window.location.href.includes('page=getbowtied-license')) {
    118                 // Simply navigate to the URL without any scroll parameter
    119                 window.location.href = href;
    120                 return;
    121             }
    122            
    123             // If we're already on the license page, scroll to the dashboard scope
    124             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().top
    133                 }, 500);
    134             }
    135         }
    136        
    137         // Function to toggle content visibility
    138         function toggleContent($content) {
    139             // Toggle the expanded class
    140             $content.toggleClass('expanded');
    141            
    142             // Update the More details link text based on expanded state
    143             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 title
    148         $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" link
    155         $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         });
    160167    });
    161168})(jQuery);
  • shopkeeper-extender/trunk/dashboard/setup.php

    r3267058 r3268043  
    99include_once( $base_paths['path'] . '/dashboard/inc/pages/setup.php' );
    1010include_once( $base_paths['path'] . '/dashboard/inc/classes/class-theme-li.php' );
     11include_once( $base_paths['path'] . '/dashboard/inc/classes/class-gbt-notification-handler.php' );
    1112
    1213// Only include pointers if theme is not Block Shop
  • shopkeeper-extender/trunk/shopkeeper-extender.php

    r3267058 r3268043  
    55 * Plugin URI:              https://shopkeeper.wp-theme.design/
    66 * Description:             Extends the functionality of Shopkeeper with theme specific features.
    7  * Version:                 5.0
     7 * Version:                 5.1
    88 * Author:                  Get Bowtied
    99 * Author URI:              https://getbowtied.com
Note: See TracChangeset for help on using the changeset viewer.