Plugin Directory

Changeset 3377797


Ignore:
Timestamp:
10/14/2025 02:34:14 AM (6 months ago)
Author:
azplugins
Message:

Update to version 1.0.3 from GitHub

Location:
lean-cart-share-and-save
Files:
3 added
1 deleted
15 edited
1 copied

Legend:

Unmodified
Added
Removed
  • lean-cart-share-and-save/tags/1.0.3/assets/css/frontend.css

    r3373310 r3377797  
    1717}
    1818
    19 .lean-csns-buttons-wrapper button {
    20     margin-right: 10px;
     19.lean-csns-buttons-wrapper button,
     20.woocommerce-js .lean-csns-buttons-wrapper button {
     21    margin-left: 10px;
    2122}
    2223
  • lean-cart-share-and-save/tags/1.0.3/assets/js/frontend.js

    r3367807 r3377797  
    4444                if (navigator.clipboard && navigator.clipboard.writeText) {
    4545                    navigator.clipboard.writeText(text).then(function() {
    46                         alert(lean_csns_ajax.i18n.link_copied);
     46                        alert(lean_csns_params.i18n.link_copied);
    4747                    }).catch(function() {
    4848                        lean_csns.utils.fallbackCopyTextToClipboard(text);
     
    7070                try {
    7171                    document.execCommand('copy');
    72                     alert(lean_csns_ajax.i18n.link_copied);
     72                    alert(lean_csns_params.i18n.link_copied);
    7373                } catch (err) {
    7474                    alert('Failed to copy link');
     
    9999    };
    100100   
     101    /**
     102     * WooCommerce Cart Block Detection and Button Injection
     103     * Uses triple-defense approach for FSE theme compatibility
     104     */
     105    var cartBlockDetection = {
     106        injectionTimeout: null,
     107        hasInjectedButtons: false,
     108       
     109        /**
     110         * Configuration: Choose where to insert buttons
     111         * Available options:
     112         * - 'after-cart-items' : Right after the cart items table
     113         * - 'before-checkout-button' : Before the checkout button
     114         */
     115        insertionPoint: 'after-cart-items',
     116       
     117        /**
     118         * Check if Cart Block exists and inject buttons if needed
     119         */
     120        checkAndInjectButtons: function() {
     121            // Check if Cart Block exists
     122            if ($('.wc-block-cart').length > 0) {
     123                // Only inject if buttons haven't been added yet
     124                if ($('.wc-block-cart .lean-csns-buttons-wrapper').length === 0) {
     125                    this.injectButtonsToCartBlock();
     126                }
     127            }
     128        },
     129       
     130        /**
     131         * Inject buttons into Cart Block
     132         * Uses pre-rendered HTML from PHP (single source of truth)
     133         */
     134        injectButtonsToCartBlock: function() {
     135            // Get pre-rendered button HTML from PHP
     136            var buttonsHtml = lean_csns_params.buttons_html;
     137           
     138            // Don't inject if no buttons HTML (both features disabled)
     139            if (!buttonsHtml || buttonsHtml.trim() === '') {
     140                return;
     141            }
     142           
     143            // Try configured insertion point
     144            var inserted = this.tryConfiguredInsertionPoint(buttonsHtml);
     145           
     146            if (!inserted) {
     147                console.log('Lean Cart Share & Save: Could not find insertion point "' + this.insertionPoint + '"');
     148            }
     149        },
     150       
     151        /**
     152         * Try to inject buttons at the configured insertion point
     153         *
     154         * @param {string} buttonsHtml Button HTML to inject
     155         * @return {boolean} True if injection was successful
     156         */
     157        tryConfiguredInsertionPoint: function(buttonsHtml) {
     158            // Map friendly names to actual selectors and methods
     159            var insertionMap = {
     160                'after-cart-items': {
     161                    selector: '.wc-block-cart-items',
     162                    method: 'after'
     163                },
     164                'before-checkout-button': {
     165                    selector: '.wc-block-cart__submit-button, .wc-block-components-checkout-button',
     166                    method: 'before-parent'
     167                }
     168            };
     169           
     170            var config = insertionMap[this.insertionPoint];
     171            if (!config) {
     172                console.log('Lean Cart Share & Save: Invalid insertion point: ' + this.insertionPoint);
     173                return false;
     174            }
     175           
     176            var $target = $(config.selector).first();
     177            if ($target.length === 0) {
     178                return false;
     179            }
     180           
     181            // Apply the insertion method
     182            if (config.method === 'after') {
     183                $(buttonsHtml).insertAfter($target);
     184            } else if (config.method === 'before-parent') {
     185                $(buttonsHtml).insertBefore($target.parent());
     186            }
     187           
     188            console.log('Lean Cart Share & Save: Buttons injected at "' + this.insertionPoint + '"');
     189            return true;
     190        },
     191       
     192        /**
     193         * Debounced button injection to prevent duplicates
     194         */
     195        debouncedInjectButtons: function() {
     196            var self = this;
     197            clearTimeout(this.injectionTimeout);
     198            this.injectionTimeout = setTimeout(function() {
     199                if (self.hasInjectedButtons) {
     200                    return;
     201                }
     202                self.hasInjectedButtons = true;
     203                self.checkAndInjectButtons();
     204            }, 300);
     205        },
     206       
     207        /**
     208         * Initialize triple-defense detection strategy
     209         */
     210        init: function() {
     211            var self = this;
     212           
     213            // Initial detection
     214            this.debouncedInjectButtons();
     215           
     216            // Delayed detection (for FSE render timing)
     217            setTimeout(function() {
     218                self.hasInjectedButtons = false; // Allow re-check
     219                self.debouncedInjectButtons();
     220            }, 500);
     221           
     222            // WooCommerce block events
     223            $(document.body).on('updated_wc_block updated_cart_totals wc-blocks_render_blocks_frontend', function() {
     224                self.hasInjectedButtons = false; // Allow re-check on updates
     225                self.debouncedInjectButtons();
     226            });
     227           
     228            // MutationObserver (most reliable for FSE)
     229            if (typeof MutationObserver !== 'undefined') {
     230                var observer = new MutationObserver(function(mutations) {
     231                    // Only trigger if significant DOM changes occurred
     232                    for (var i = 0; i < mutations.length; i++) {
     233                        if (mutations[i].addedNodes.length > 0) {
     234                            self.hasInjectedButtons = false; // Allow re-check
     235                            self.debouncedInjectButtons();
     236                            break;
     237                        }
     238                    }
     239                });
     240               
     241                observer.observe(document.body, {
     242                    childList: true,
     243                    subtree: true
     244                });
     245            }
     246        }
     247    };
     248   
    101249    $(document).ready(function() {
     250       
     251        // Initialize Cart Block detection for FSE themes
     252        cartBlockDetection.init();
    102253       
    103254        /**
     
    111262           
    112263            $.ajax({
    113                 url: lean_csns_ajax.ajax_url,
     264                url: lean_csns_params.ajax_url,
    114265                type: 'POST',
    115266                data: {
    116267                    action: 'lean_csns_share_cart',
    117                     nonce: lean_csns_ajax.nonce
     268                    nonce: lean_csns_params.nonce
    118269                },
    119270                success: function(response) {
     
    121272                   
    122273                    if (response.success) {
    123                         var content = '<h3>' + lean_csns_ajax.i18n.share_title + '</h3>' +
     274                        var content = '<h3>' + lean_csns_params.i18n.share_title + '</h3>' +
    124275                                    '<input type="url" value="' + response.url + '" readonly>' +
    125276                                    '<div class="lean-csns-popup-buttons">' +
    126                                     '<button type="button" onclick="lean_csns.utils.copyToClipboard(\'' + response.url + '\')">' + lean_csns_ajax.i18n.copy_button + '</button>' +
    127                                     '<button type="button" class="button-secondary" onclick="lean_csns.popup.close()">' + lean_csns_ajax.i18n.close_button + '</button>' +
     277                                    '<button type="button" onclick="lean_csns.utils.copyToClipboard(\'' + response.url + '\')">' + lean_csns_params.i18n.copy_button + '</button>' +
     278                                    '<button type="button" class="button-secondary" onclick="lean_csns.popup.close()">' + lean_csns_params.i18n.close_button + '</button>' +
    128279                                    '</div>';
    129280                        lean_csns.popup.open('share', content);
     
    143294         */
    144295        $(document).on('click', '.lean-csns-save-btn', function() {
    145             var content = '<h3>' + lean_csns_ajax.i18n.save_title + '</h3>' +
    146                         '<input type="text" id="cart-name-input" placeholder="' + lean_csns_ajax.i18n.enter_cart_name + '" maxlength="255">' +
     296            var content = '<h3>' + lean_csns_params.i18n.save_title + '</h3>' +
     297                        '<input type="text" id="cart-name-input" placeholder="' + lean_csns_params.i18n.enter_cart_name + '" maxlength="255">' +
    147298                        '<div class="lean-csns-popup-buttons">' +
    148                         '<button type="button" id="save-cart-confirm">' + lean_csns_ajax.i18n.save_button + '</button>' +
    149                         '<button type="button" class="button-secondary" onclick="lean_csns.popup.close()">' + lean_csns_ajax.i18n.cancel_button + '</button>' +
     299                        '<button type="button" id="save-cart-confirm">' + lean_csns_params.i18n.save_button + '</button>' +
     300                        '<button type="button" class="button-secondary" onclick="lean_csns.popup.close()">' + lean_csns_params.i18n.cancel_button + '</button>' +
    150301                        '</div>';
    151302            lean_csns.popup.open('save', content);
     
    167318           
    168319            if (!name) {
    169                 alert(lean_csns_ajax.i18n.cart_name_required);
     320                alert(lean_csns_params.i18n.cart_name_required);
    170321                nameInput.focus();
    171322                return;
     
    175326           
    176327            $.ajax({
    177                 url: lean_csns_ajax.ajax_url,
     328                url: lean_csns_params.ajax_url,
    178329                type: 'POST',
    179330                data: {
    180331                    action: 'lean_csns_save_cart',
    181332                    name: name,
    182                     nonce: lean_csns_ajax.nonce
     333                    nonce: lean_csns_params.nonce
    183334                },
    184335                success: function(response) {
  • lean-cart-share-and-save/tags/1.0.3/includes/class-assets-manager.php

    r3367807 r3377797  
    7373     */
    7474    public function enqueue_frontend_assets() {
    75         if (!is_cart()) {
     75        // Check if this is ANY type of cart page
     76        $is_on_cart_page = is_cart() || has_block('woocommerce/cart');
     77
     78        // Only load on cart pages
     79        if (!$is_on_cart_page) {
    7680            return;
    7781        }
     
    8084        wp_enqueue_style('lean-csns-frontend');
    8185       
    82         // Localize script with AJAX data
    83         wp_localize_script('lean-csns-frontend', 'lean_csns_ajax', [
     86        // Get buttons HTML from single source of truth
     87        $buttons_html = Base::get_instance()->get_buttons_html();
     88       
     89        // Localize script with parameters for frontend
     90        wp_localize_script('lean-csns-frontend', 'lean_csns_params', [
    8491            'ajax_url' => admin_url('admin-ajax.php'),
    8592            'nonce' => wp_create_nonce('lean_csns_nonce'),
     93            'buttons_html' => $buttons_html, // Pre-rendered button HTML
    8694            'i18n' => [
    8795                'share_title' => __('Share Your Cart', 'lean-cart-share-and-save'),
  • lean-cart-share-and-save/tags/1.0.3/includes/class-base.php

    r3367807 r3377797  
    5151        // Frontend hooks
    5252        add_action('woocommerce_cart_coupon', [$this, 'add_cart_buttons']);
     53        add_action('wp_footer', [$this, 'render_popup_template']);
    5354       
    5455        // My Account integration
     
    6263   
    6364    /**
    64      * Add cart share/save buttons to cart page
     65     * Add cart share/save buttons to cart page (classic themes)
    6566     */
    6667    public function add_cart_buttons() {
     68        echo $this->get_buttons_html();
     69    }
     70   
     71    /**
     72     * Get buttons HTML (single source of truth)
     73     * Used by both classic themes and Cart Blocks
     74     *
     75     * @return string Button HTML or empty string if no buttons should show
     76     */
     77    public function get_buttons_html() {
    6778        $share_enabled = lean_csns_get_option('cart_share.enable', '1');
    6879        $save_enabled = lean_csns_get_option('cart_save.enable', '1');
    6980       
    7081        if (!$share_enabled && !$save_enabled) {
     82            return '';
     83        }
     84       
     85        $html = '<div class="lean-csns-buttons-wrapper">';
     86       
     87        if ($share_enabled) {
     88            $html .= '<button type="button" class="wp-element-button button lean-csns-share-btn">' . esc_html(__('Share Cart', 'lean-cart-share-and-save')) . '</button>';
     89        }
     90       
     91        if ($save_enabled && is_user_logged_in()) {
     92            $html .= '<button type="button" class="wp-element-button button lean-csns-save-btn">' . esc_html(__('Save Cart', 'lean-cart-share-and-save')) . '</button>';
     93        }
     94       
     95        $html .= '</div>';
     96       
     97        return $html;
     98    }
     99   
     100    /**
     101     * Render popup template in footer (for both classic and block carts)
     102     */
     103    public function render_popup_template() {
     104        // Only render on pages where WooCommerce is active
     105        if (!function_exists('WC') || !WC()->cart) {
    71106            return;
    72107        }
    73108       
    74         echo '<div class="lean-csns-buttons-wrapper">';
    75        
    76         if ($share_enabled) {
    77             echo '<button type="button" class="button lean-csns-share-btn">' . esc_html(__('Share Cart', 'lean-cart-share-and-save')) . '</button>';
    78         }
    79        
    80         if ($save_enabled && is_user_logged_in()) {
    81             echo '<button type="button" class="button lean-csns-save-btn">' . esc_html(__('Save Cart', 'lean-cart-share-and-save')) . '</button>';
    82         }
    83        
    84         echo '</div>';
    85        
    86         // Include popup template
    87109        include LEAN_CSNS_PL_DIR . 'templates/popup.php';
    88110    }
  • lean-cart-share-and-save/tags/1.0.3/includes/class-settings-page.php

    r3367807 r3377797  
    134134            'lean-csns-settings',
    135135            'lean_csns_data_section',
    136             ['key' => 'data_management.delete_on_uninstall', 'description' => __('Remove all saved & shared carts and plugin settings when the plugin is deleted (unchecked by default). <br> This helps keep your database clean if you no longer plan to use the plugin.', 'lean-cart-share-and-save')]
     136            ['key' => 'data_management.delete_on_uninstall', 'description' => __('Remove all saved & shared carts and plugin settings when the plugin is deleted.<br> This helps keep your database clean if you no longer plan to use the plugin.', 'lean-cart-share-and-save')]
    137137        );
    138138    }
  • lean-cart-share-and-save/tags/1.0.3/lean-cart-share-and-save.php

    r3373310 r3377797  
    33 * Plugin Name: Lean Cart Share and Save for WooCommerce
    44 * Plugin URI:
    5  * Description: Lightweight cart sharing and saving for WooCommerce
    6  * Version: 1.0.2
    7  * Author: AZPlugins
    8  * Author URI:
     5 * Description: Lightweight cart sharing and saving for WooCommerce. Fully compatible with FSE themes and WooCommerce Cart Blocks.
     6 * Version: 1.0.3
     7 * Author: LeanPlugins
     8 * Author URI: https://leanplugins.com/
    99 * License: GPLv2 or later
    1010 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    2020
    2121// Define plugin constants
    22 define('LEAN_CSNS_VERSION', '1.0.2');
     22define('LEAN_CSNS_VERSION', '1.0.3');
    2323define('LEAN_CSNS_DB_VERSION', '1.0.0');
    2424define('LEAN_CSNS_PL_FILE', __FILE__);
  • lean-cart-share-and-save/tags/1.0.3/readme.txt

    r3373332 r3377797  
    55Tested up to: 6.8
    66Requires PHP: 7.4
    7 Stable tag: 1.0.2
     7Stable tag: 1.0.3
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    3030* **Cart Saving**: Allow logged-in users to save carts with custom names 
    3131* **WooCommerce Integration**: Seamlessly integrates with your existing WooCommerce store
     32* **FSE & Block Cart Support**: Works perfectly with both classic themes and modern Full Site Editing (FSE) themes with WooCommerce Cart Blocks
    3233* **My Account Integration**: Saved carts appear in customer My Account area
    3334* **Flexible Settings**: Configure share expiry, enable/disable features
     
    103104No, the plugin is designed to be lightweight and only loads assets when needed. It uses efficient database queries and follows WordPress best practices.
    104105
     106= Does it work with FSE (Full Site Editing) themes and WooCommerce Cart Blocks? =
     107
     108Yes! The plugin fully supports both classic WooCommerce themes and modern FSE themes using WooCommerce Cart Blocks. The buttons automatically appear in both classic and block cart pages.
     109
    105110= Can I customize the appearance of the share/save buttons? =
    106111
     
    119124Go to Settings → Permalinks in your WordPress admin and click "Save Changes" (no need to change anything). This refreshes WordPress URL rules.
    120125
     126== Screenshots ==
     127
     1281. Plugin Settings page
     1292. Share Cart and Save Cart buttons on classic WooCommerce cart page
     1303. Share Cart and Save Cart buttons on FSE theme with WooCommerce Cart Block - works seamlessly with modern block-based cart pages
     1314. Cart sharing popup with generated shareable URL
     1325. Cart saving popup with custom name input
     1336. Saved carts displayed in My Account area
     134
    121135== Changelog ==
     136
     137= 1.0.3 =
     138* New: Compatibility with FSE (Full Site Editing) themes and WooCommerce Cart Blocks
     139
     140= 1.0.2 =
     141* Improved: Enhanced compatibility and performance
     142
    122143= 1.0.1 =
    123 - Improved: Code optimizations and security enhancements
     144* Improved: Code optimizations and security enhancements
    124145
    125146= 1.0.0 =
  • lean-cart-share-and-save/trunk/assets/css/frontend.css

    r3373310 r3377797  
    1717}
    1818
    19 .lean-csns-buttons-wrapper button {
    20     margin-right: 10px;
     19.lean-csns-buttons-wrapper button,
     20.woocommerce-js .lean-csns-buttons-wrapper button {
     21    margin-left: 10px;
    2122}
    2223
  • lean-cart-share-and-save/trunk/assets/js/frontend.js

    r3367807 r3377797  
    4444                if (navigator.clipboard && navigator.clipboard.writeText) {
    4545                    navigator.clipboard.writeText(text).then(function() {
    46                         alert(lean_csns_ajax.i18n.link_copied);
     46                        alert(lean_csns_params.i18n.link_copied);
    4747                    }).catch(function() {
    4848                        lean_csns.utils.fallbackCopyTextToClipboard(text);
     
    7070                try {
    7171                    document.execCommand('copy');
    72                     alert(lean_csns_ajax.i18n.link_copied);
     72                    alert(lean_csns_params.i18n.link_copied);
    7373                } catch (err) {
    7474                    alert('Failed to copy link');
     
    9999    };
    100100   
     101    /**
     102     * WooCommerce Cart Block Detection and Button Injection
     103     * Uses triple-defense approach for FSE theme compatibility
     104     */
     105    var cartBlockDetection = {
     106        injectionTimeout: null,
     107        hasInjectedButtons: false,
     108       
     109        /**
     110         * Configuration: Choose where to insert buttons
     111         * Available options:
     112         * - 'after-cart-items' : Right after the cart items table
     113         * - 'before-checkout-button' : Before the checkout button
     114         */
     115        insertionPoint: 'after-cart-items',
     116       
     117        /**
     118         * Check if Cart Block exists and inject buttons if needed
     119         */
     120        checkAndInjectButtons: function() {
     121            // Check if Cart Block exists
     122            if ($('.wc-block-cart').length > 0) {
     123                // Only inject if buttons haven't been added yet
     124                if ($('.wc-block-cart .lean-csns-buttons-wrapper').length === 0) {
     125                    this.injectButtonsToCartBlock();
     126                }
     127            }
     128        },
     129       
     130        /**
     131         * Inject buttons into Cart Block
     132         * Uses pre-rendered HTML from PHP (single source of truth)
     133         */
     134        injectButtonsToCartBlock: function() {
     135            // Get pre-rendered button HTML from PHP
     136            var buttonsHtml = lean_csns_params.buttons_html;
     137           
     138            // Don't inject if no buttons HTML (both features disabled)
     139            if (!buttonsHtml || buttonsHtml.trim() === '') {
     140                return;
     141            }
     142           
     143            // Try configured insertion point
     144            var inserted = this.tryConfiguredInsertionPoint(buttonsHtml);
     145           
     146            if (!inserted) {
     147                console.log('Lean Cart Share & Save: Could not find insertion point "' + this.insertionPoint + '"');
     148            }
     149        },
     150       
     151        /**
     152         * Try to inject buttons at the configured insertion point
     153         *
     154         * @param {string} buttonsHtml Button HTML to inject
     155         * @return {boolean} True if injection was successful
     156         */
     157        tryConfiguredInsertionPoint: function(buttonsHtml) {
     158            // Map friendly names to actual selectors and methods
     159            var insertionMap = {
     160                'after-cart-items': {
     161                    selector: '.wc-block-cart-items',
     162                    method: 'after'
     163                },
     164                'before-checkout-button': {
     165                    selector: '.wc-block-cart__submit-button, .wc-block-components-checkout-button',
     166                    method: 'before-parent'
     167                }
     168            };
     169           
     170            var config = insertionMap[this.insertionPoint];
     171            if (!config) {
     172                console.log('Lean Cart Share & Save: Invalid insertion point: ' + this.insertionPoint);
     173                return false;
     174            }
     175           
     176            var $target = $(config.selector).first();
     177            if ($target.length === 0) {
     178                return false;
     179            }
     180           
     181            // Apply the insertion method
     182            if (config.method === 'after') {
     183                $(buttonsHtml).insertAfter($target);
     184            } else if (config.method === 'before-parent') {
     185                $(buttonsHtml).insertBefore($target.parent());
     186            }
     187           
     188            console.log('Lean Cart Share & Save: Buttons injected at "' + this.insertionPoint + '"');
     189            return true;
     190        },
     191       
     192        /**
     193         * Debounced button injection to prevent duplicates
     194         */
     195        debouncedInjectButtons: function() {
     196            var self = this;
     197            clearTimeout(this.injectionTimeout);
     198            this.injectionTimeout = setTimeout(function() {
     199                if (self.hasInjectedButtons) {
     200                    return;
     201                }
     202                self.hasInjectedButtons = true;
     203                self.checkAndInjectButtons();
     204            }, 300);
     205        },
     206       
     207        /**
     208         * Initialize triple-defense detection strategy
     209         */
     210        init: function() {
     211            var self = this;
     212           
     213            // Initial detection
     214            this.debouncedInjectButtons();
     215           
     216            // Delayed detection (for FSE render timing)
     217            setTimeout(function() {
     218                self.hasInjectedButtons = false; // Allow re-check
     219                self.debouncedInjectButtons();
     220            }, 500);
     221           
     222            // WooCommerce block events
     223            $(document.body).on('updated_wc_block updated_cart_totals wc-blocks_render_blocks_frontend', function() {
     224                self.hasInjectedButtons = false; // Allow re-check on updates
     225                self.debouncedInjectButtons();
     226            });
     227           
     228            // MutationObserver (most reliable for FSE)
     229            if (typeof MutationObserver !== 'undefined') {
     230                var observer = new MutationObserver(function(mutations) {
     231                    // Only trigger if significant DOM changes occurred
     232                    for (var i = 0; i < mutations.length; i++) {
     233                        if (mutations[i].addedNodes.length > 0) {
     234                            self.hasInjectedButtons = false; // Allow re-check
     235                            self.debouncedInjectButtons();
     236                            break;
     237                        }
     238                    }
     239                });
     240               
     241                observer.observe(document.body, {
     242                    childList: true,
     243                    subtree: true
     244                });
     245            }
     246        }
     247    };
     248   
    101249    $(document).ready(function() {
     250       
     251        // Initialize Cart Block detection for FSE themes
     252        cartBlockDetection.init();
    102253       
    103254        /**
     
    111262           
    112263            $.ajax({
    113                 url: lean_csns_ajax.ajax_url,
     264                url: lean_csns_params.ajax_url,
    114265                type: 'POST',
    115266                data: {
    116267                    action: 'lean_csns_share_cart',
    117                     nonce: lean_csns_ajax.nonce
     268                    nonce: lean_csns_params.nonce
    118269                },
    119270                success: function(response) {
     
    121272                   
    122273                    if (response.success) {
    123                         var content = '<h3>' + lean_csns_ajax.i18n.share_title + '</h3>' +
     274                        var content = '<h3>' + lean_csns_params.i18n.share_title + '</h3>' +
    124275                                    '<input type="url" value="' + response.url + '" readonly>' +
    125276                                    '<div class="lean-csns-popup-buttons">' +
    126                                     '<button type="button" onclick="lean_csns.utils.copyToClipboard(\'' + response.url + '\')">' + lean_csns_ajax.i18n.copy_button + '</button>' +
    127                                     '<button type="button" class="button-secondary" onclick="lean_csns.popup.close()">' + lean_csns_ajax.i18n.close_button + '</button>' +
     277                                    '<button type="button" onclick="lean_csns.utils.copyToClipboard(\'' + response.url + '\')">' + lean_csns_params.i18n.copy_button + '</button>' +
     278                                    '<button type="button" class="button-secondary" onclick="lean_csns.popup.close()">' + lean_csns_params.i18n.close_button + '</button>' +
    128279                                    '</div>';
    129280                        lean_csns.popup.open('share', content);
     
    143294         */
    144295        $(document).on('click', '.lean-csns-save-btn', function() {
    145             var content = '<h3>' + lean_csns_ajax.i18n.save_title + '</h3>' +
    146                         '<input type="text" id="cart-name-input" placeholder="' + lean_csns_ajax.i18n.enter_cart_name + '" maxlength="255">' +
     296            var content = '<h3>' + lean_csns_params.i18n.save_title + '</h3>' +
     297                        '<input type="text" id="cart-name-input" placeholder="' + lean_csns_params.i18n.enter_cart_name + '" maxlength="255">' +
    147298                        '<div class="lean-csns-popup-buttons">' +
    148                         '<button type="button" id="save-cart-confirm">' + lean_csns_ajax.i18n.save_button + '</button>' +
    149                         '<button type="button" class="button-secondary" onclick="lean_csns.popup.close()">' + lean_csns_ajax.i18n.cancel_button + '</button>' +
     299                        '<button type="button" id="save-cart-confirm">' + lean_csns_params.i18n.save_button + '</button>' +
     300                        '<button type="button" class="button-secondary" onclick="lean_csns.popup.close()">' + lean_csns_params.i18n.cancel_button + '</button>' +
    150301                        '</div>';
    151302            lean_csns.popup.open('save', content);
     
    167318           
    168319            if (!name) {
    169                 alert(lean_csns_ajax.i18n.cart_name_required);
     320                alert(lean_csns_params.i18n.cart_name_required);
    170321                nameInput.focus();
    171322                return;
     
    175326           
    176327            $.ajax({
    177                 url: lean_csns_ajax.ajax_url,
     328                url: lean_csns_params.ajax_url,
    178329                type: 'POST',
    179330                data: {
    180331                    action: 'lean_csns_save_cart',
    181332                    name: name,
    182                     nonce: lean_csns_ajax.nonce
     333                    nonce: lean_csns_params.nonce
    183334                },
    184335                success: function(response) {
  • lean-cart-share-and-save/trunk/includes/class-assets-manager.php

    r3367807 r3377797  
    7373     */
    7474    public function enqueue_frontend_assets() {
    75         if (!is_cart()) {
     75        // Check if this is ANY type of cart page
     76        $is_on_cart_page = is_cart() || has_block('woocommerce/cart');
     77
     78        // Only load on cart pages
     79        if (!$is_on_cart_page) {
    7680            return;
    7781        }
     
    8084        wp_enqueue_style('lean-csns-frontend');
    8185       
    82         // Localize script with AJAX data
    83         wp_localize_script('lean-csns-frontend', 'lean_csns_ajax', [
     86        // Get buttons HTML from single source of truth
     87        $buttons_html = Base::get_instance()->get_buttons_html();
     88       
     89        // Localize script with parameters for frontend
     90        wp_localize_script('lean-csns-frontend', 'lean_csns_params', [
    8491            'ajax_url' => admin_url('admin-ajax.php'),
    8592            'nonce' => wp_create_nonce('lean_csns_nonce'),
     93            'buttons_html' => $buttons_html, // Pre-rendered button HTML
    8694            'i18n' => [
    8795                'share_title' => __('Share Your Cart', 'lean-cart-share-and-save'),
  • lean-cart-share-and-save/trunk/includes/class-base.php

    r3367807 r3377797  
    5151        // Frontend hooks
    5252        add_action('woocommerce_cart_coupon', [$this, 'add_cart_buttons']);
     53        add_action('wp_footer', [$this, 'render_popup_template']);
    5354       
    5455        // My Account integration
     
    6263   
    6364    /**
    64      * Add cart share/save buttons to cart page
     65     * Add cart share/save buttons to cart page (classic themes)
    6566     */
    6667    public function add_cart_buttons() {
     68        echo $this->get_buttons_html();
     69    }
     70   
     71    /**
     72     * Get buttons HTML (single source of truth)
     73     * Used by both classic themes and Cart Blocks
     74     *
     75     * @return string Button HTML or empty string if no buttons should show
     76     */
     77    public function get_buttons_html() {
    6778        $share_enabled = lean_csns_get_option('cart_share.enable', '1');
    6879        $save_enabled = lean_csns_get_option('cart_save.enable', '1');
    6980       
    7081        if (!$share_enabled && !$save_enabled) {
     82            return '';
     83        }
     84       
     85        $html = '<div class="lean-csns-buttons-wrapper">';
     86       
     87        if ($share_enabled) {
     88            $html .= '<button type="button" class="wp-element-button button lean-csns-share-btn">' . esc_html(__('Share Cart', 'lean-cart-share-and-save')) . '</button>';
     89        }
     90       
     91        if ($save_enabled && is_user_logged_in()) {
     92            $html .= '<button type="button" class="wp-element-button button lean-csns-save-btn">' . esc_html(__('Save Cart', 'lean-cart-share-and-save')) . '</button>';
     93        }
     94       
     95        $html .= '</div>';
     96       
     97        return $html;
     98    }
     99   
     100    /**
     101     * Render popup template in footer (for both classic and block carts)
     102     */
     103    public function render_popup_template() {
     104        // Only render on pages where WooCommerce is active
     105        if (!function_exists('WC') || !WC()->cart) {
    71106            return;
    72107        }
    73108       
    74         echo '<div class="lean-csns-buttons-wrapper">';
    75        
    76         if ($share_enabled) {
    77             echo '<button type="button" class="button lean-csns-share-btn">' . esc_html(__('Share Cart', 'lean-cart-share-and-save')) . '</button>';
    78         }
    79        
    80         if ($save_enabled && is_user_logged_in()) {
    81             echo '<button type="button" class="button lean-csns-save-btn">' . esc_html(__('Save Cart', 'lean-cart-share-and-save')) . '</button>';
    82         }
    83        
    84         echo '</div>';
    85        
    86         // Include popup template
    87109        include LEAN_CSNS_PL_DIR . 'templates/popup.php';
    88110    }
  • lean-cart-share-and-save/trunk/includes/class-settings-page.php

    r3367807 r3377797  
    134134            'lean-csns-settings',
    135135            'lean_csns_data_section',
    136             ['key' => 'data_management.delete_on_uninstall', 'description' => __('Remove all saved & shared carts and plugin settings when the plugin is deleted (unchecked by default). <br> This helps keep your database clean if you no longer plan to use the plugin.', 'lean-cart-share-and-save')]
     136            ['key' => 'data_management.delete_on_uninstall', 'description' => __('Remove all saved & shared carts and plugin settings when the plugin is deleted.<br> This helps keep your database clean if you no longer plan to use the plugin.', 'lean-cart-share-and-save')]
    137137        );
    138138    }
  • lean-cart-share-and-save/trunk/lean-cart-share-and-save.php

    r3373310 r3377797  
    33 * Plugin Name: Lean Cart Share and Save for WooCommerce
    44 * Plugin URI:
    5  * Description: Lightweight cart sharing and saving for WooCommerce
    6  * Version: 1.0.2
    7  * Author: AZPlugins
    8  * Author URI:
     5 * Description: Lightweight cart sharing and saving for WooCommerce. Fully compatible with FSE themes and WooCommerce Cart Blocks.
     6 * Version: 1.0.3
     7 * Author: LeanPlugins
     8 * Author URI: https://leanplugins.com/
    99 * License: GPLv2 or later
    1010 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    2020
    2121// Define plugin constants
    22 define('LEAN_CSNS_VERSION', '1.0.2');
     22define('LEAN_CSNS_VERSION', '1.0.3');
    2323define('LEAN_CSNS_DB_VERSION', '1.0.0');
    2424define('LEAN_CSNS_PL_FILE', __FILE__);
  • lean-cart-share-and-save/trunk/readme.txt

    r3373332 r3377797  
    55Tested up to: 6.8
    66Requires PHP: 7.4
    7 Stable tag: 1.0.2
     7Stable tag: 1.0.3
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    3030* **Cart Saving**: Allow logged-in users to save carts with custom names 
    3131* **WooCommerce Integration**: Seamlessly integrates with your existing WooCommerce store
     32* **FSE & Block Cart Support**: Works perfectly with both classic themes and modern Full Site Editing (FSE) themes with WooCommerce Cart Blocks
    3233* **My Account Integration**: Saved carts appear in customer My Account area
    3334* **Flexible Settings**: Configure share expiry, enable/disable features
     
    103104No, the plugin is designed to be lightweight and only loads assets when needed. It uses efficient database queries and follows WordPress best practices.
    104105
     106= Does it work with FSE (Full Site Editing) themes and WooCommerce Cart Blocks? =
     107
     108Yes! The plugin fully supports both classic WooCommerce themes and modern FSE themes using WooCommerce Cart Blocks. The buttons automatically appear in both classic and block cart pages.
     109
    105110= Can I customize the appearance of the share/save buttons? =
    106111
     
    119124Go to Settings → Permalinks in your WordPress admin and click "Save Changes" (no need to change anything). This refreshes WordPress URL rules.
    120125
     126== Screenshots ==
     127
     1281. Plugin Settings page
     1292. Share Cart and Save Cart buttons on classic WooCommerce cart page
     1303. Share Cart and Save Cart buttons on FSE theme with WooCommerce Cart Block - works seamlessly with modern block-based cart pages
     1314. Cart sharing popup with generated shareable URL
     1325. Cart saving popup with custom name input
     1336. Saved carts displayed in My Account area
     134
    121135== Changelog ==
     136
     137= 1.0.3 =
     138* New: Compatibility with FSE (Full Site Editing) themes and WooCommerce Cart Blocks
     139
     140= 1.0.2 =
     141* Improved: Enhanced compatibility and performance
     142
    122143= 1.0.1 =
    123 - Improved: Code optimizations and security enhancements
     144* Improved: Code optimizations and security enhancements
    124145
    125146= 1.0.0 =
Note: See TracChangeset for help on using the changeset viewer.