Changeset 3377797
- Timestamp:
- 10/14/2025 02:34:14 AM (6 months ago)
- Location:
- lean-cart-share-and-save
- Files:
-
- 3 added
- 1 deleted
- 15 edited
- 1 copied
-
assets/screenshot-3.jpg (deleted)
-
assets/screenshot-3.png (added)
-
assets/screenshot-4.jpg (modified) (previous)
-
assets/screenshot-5.png (added)
-
assets/screenshot-6.png (added)
-
tags/1.0.3 (copied) (copied from lean-cart-share-and-save/trunk)
-
tags/1.0.3/assets/css/frontend.css (modified) (1 diff)
-
tags/1.0.3/assets/js/frontend.js (modified) (8 diffs)
-
tags/1.0.3/includes/class-assets-manager.php (modified) (2 diffs)
-
tags/1.0.3/includes/class-base.php (modified) (2 diffs)
-
tags/1.0.3/includes/class-settings-page.php (modified) (1 diff)
-
tags/1.0.3/lean-cart-share-and-save.php (modified) (2 diffs)
-
tags/1.0.3/readme.txt (modified) (4 diffs)
-
trunk/assets/css/frontend.css (modified) (1 diff)
-
trunk/assets/js/frontend.js (modified) (8 diffs)
-
trunk/includes/class-assets-manager.php (modified) (2 diffs)
-
trunk/includes/class-base.php (modified) (2 diffs)
-
trunk/includes/class-settings-page.php (modified) (1 diff)
-
trunk/lean-cart-share-and-save.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
lean-cart-share-and-save/tags/1.0.3/assets/css/frontend.css
r3373310 r3377797 17 17 } 18 18 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; 21 22 } 22 23 -
lean-cart-share-and-save/tags/1.0.3/assets/js/frontend.js
r3367807 r3377797 44 44 if (navigator.clipboard && navigator.clipboard.writeText) { 45 45 navigator.clipboard.writeText(text).then(function() { 46 alert(lean_csns_ ajax.i18n.link_copied);46 alert(lean_csns_params.i18n.link_copied); 47 47 }).catch(function() { 48 48 lean_csns.utils.fallbackCopyTextToClipboard(text); … … 70 70 try { 71 71 document.execCommand('copy'); 72 alert(lean_csns_ ajax.i18n.link_copied);72 alert(lean_csns_params.i18n.link_copied); 73 73 } catch (err) { 74 74 alert('Failed to copy link'); … … 99 99 }; 100 100 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 101 249 $(document).ready(function() { 250 251 // Initialize Cart Block detection for FSE themes 252 cartBlockDetection.init(); 102 253 103 254 /** … … 111 262 112 263 $.ajax({ 113 url: lean_csns_ ajax.ajax_url,264 url: lean_csns_params.ajax_url, 114 265 type: 'POST', 115 266 data: { 116 267 action: 'lean_csns_share_cart', 117 nonce: lean_csns_ ajax.nonce268 nonce: lean_csns_params.nonce 118 269 }, 119 270 success: function(response) { … … 121 272 122 273 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>' + 124 275 '<input type="url" value="' + response.url + '" readonly>' + 125 276 '<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>' + 128 279 '</div>'; 129 280 lean_csns.popup.open('share', content); … … 143 294 */ 144 295 $(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">' + 147 298 '<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>' + 150 301 '</div>'; 151 302 lean_csns.popup.open('save', content); … … 167 318 168 319 if (!name) { 169 alert(lean_csns_ ajax.i18n.cart_name_required);320 alert(lean_csns_params.i18n.cart_name_required); 170 321 nameInput.focus(); 171 322 return; … … 175 326 176 327 $.ajax({ 177 url: lean_csns_ ajax.ajax_url,328 url: lean_csns_params.ajax_url, 178 329 type: 'POST', 179 330 data: { 180 331 action: 'lean_csns_save_cart', 181 332 name: name, 182 nonce: lean_csns_ ajax.nonce333 nonce: lean_csns_params.nonce 183 334 }, 184 335 success: function(response) { -
lean-cart-share-and-save/tags/1.0.3/includes/class-assets-manager.php
r3367807 r3377797 73 73 */ 74 74 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) { 76 80 return; 77 81 } … … 80 84 wp_enqueue_style('lean-csns-frontend'); 81 85 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', [ 84 91 'ajax_url' => admin_url('admin-ajax.php'), 85 92 'nonce' => wp_create_nonce('lean_csns_nonce'), 93 'buttons_html' => $buttons_html, // Pre-rendered button HTML 86 94 'i18n' => [ 87 95 '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 51 51 // Frontend hooks 52 52 add_action('woocommerce_cart_coupon', [$this, 'add_cart_buttons']); 53 add_action('wp_footer', [$this, 'render_popup_template']); 53 54 54 55 // My Account integration … … 62 63 63 64 /** 64 * Add cart share/save buttons to cart page 65 * Add cart share/save buttons to cart page (classic themes) 65 66 */ 66 67 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() { 67 78 $share_enabled = lean_csns_get_option('cart_share.enable', '1'); 68 79 $save_enabled = lean_csns_get_option('cart_save.enable', '1'); 69 80 70 81 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) { 71 106 return; 72 107 } 73 108 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 template87 109 include LEAN_CSNS_PL_DIR . 'templates/popup.php'; 88 110 } -
lean-cart-share-and-save/tags/1.0.3/includes/class-settings-page.php
r3367807 r3377797 134 134 'lean-csns-settings', 135 135 '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')] 137 137 ); 138 138 } -
lean-cart-share-and-save/tags/1.0.3/lean-cart-share-and-save.php
r3373310 r3377797 3 3 * Plugin Name: Lean Cart Share and Save for WooCommerce 4 4 * Plugin URI: 5 * Description: Lightweight cart sharing and saving for WooCommerce 6 * Version: 1.0. 27 * Author: AZPlugins8 * 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/ 9 9 * License: GPLv2 or later 10 10 * License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 20 20 21 21 // Define plugin constants 22 define('LEAN_CSNS_VERSION', '1.0. 2');22 define('LEAN_CSNS_VERSION', '1.0.3'); 23 23 define('LEAN_CSNS_DB_VERSION', '1.0.0'); 24 24 define('LEAN_CSNS_PL_FILE', __FILE__); -
lean-cart-share-and-save/tags/1.0.3/readme.txt
r3373332 r3377797 5 5 Tested up to: 6.8 6 6 Requires PHP: 7.4 7 Stable tag: 1.0. 27 Stable tag: 1.0.3 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 30 30 * **Cart Saving**: Allow logged-in users to save carts with custom names 31 31 * **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 32 33 * **My Account Integration**: Saved carts appear in customer My Account area 33 34 * **Flexible Settings**: Configure share expiry, enable/disable features … … 103 104 No, the plugin is designed to be lightweight and only loads assets when needed. It uses efficient database queries and follows WordPress best practices. 104 105 106 = Does it work with FSE (Full Site Editing) themes and WooCommerce Cart Blocks? = 107 108 Yes! 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 105 110 = Can I customize the appearance of the share/save buttons? = 106 111 … … 119 124 Go to Settings → Permalinks in your WordPress admin and click "Save Changes" (no need to change anything). This refreshes WordPress URL rules. 120 125 126 == Screenshots == 127 128 1. Plugin Settings page 129 2. Share Cart and Save Cart buttons on classic WooCommerce cart page 130 3. Share Cart and Save Cart buttons on FSE theme with WooCommerce Cart Block - works seamlessly with modern block-based cart pages 131 4. Cart sharing popup with generated shareable URL 132 5. Cart saving popup with custom name input 133 6. Saved carts displayed in My Account area 134 121 135 == 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 122 143 = 1.0.1 = 123 -Improved: Code optimizations and security enhancements144 * Improved: Code optimizations and security enhancements 124 145 125 146 = 1.0.0 = -
lean-cart-share-and-save/trunk/assets/css/frontend.css
r3373310 r3377797 17 17 } 18 18 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; 21 22 } 22 23 -
lean-cart-share-and-save/trunk/assets/js/frontend.js
r3367807 r3377797 44 44 if (navigator.clipboard && navigator.clipboard.writeText) { 45 45 navigator.clipboard.writeText(text).then(function() { 46 alert(lean_csns_ ajax.i18n.link_copied);46 alert(lean_csns_params.i18n.link_copied); 47 47 }).catch(function() { 48 48 lean_csns.utils.fallbackCopyTextToClipboard(text); … … 70 70 try { 71 71 document.execCommand('copy'); 72 alert(lean_csns_ ajax.i18n.link_copied);72 alert(lean_csns_params.i18n.link_copied); 73 73 } catch (err) { 74 74 alert('Failed to copy link'); … … 99 99 }; 100 100 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 101 249 $(document).ready(function() { 250 251 // Initialize Cart Block detection for FSE themes 252 cartBlockDetection.init(); 102 253 103 254 /** … … 111 262 112 263 $.ajax({ 113 url: lean_csns_ ajax.ajax_url,264 url: lean_csns_params.ajax_url, 114 265 type: 'POST', 115 266 data: { 116 267 action: 'lean_csns_share_cart', 117 nonce: lean_csns_ ajax.nonce268 nonce: lean_csns_params.nonce 118 269 }, 119 270 success: function(response) { … … 121 272 122 273 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>' + 124 275 '<input type="url" value="' + response.url + '" readonly>' + 125 276 '<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>' + 128 279 '</div>'; 129 280 lean_csns.popup.open('share', content); … … 143 294 */ 144 295 $(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">' + 147 298 '<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>' + 150 301 '</div>'; 151 302 lean_csns.popup.open('save', content); … … 167 318 168 319 if (!name) { 169 alert(lean_csns_ ajax.i18n.cart_name_required);320 alert(lean_csns_params.i18n.cart_name_required); 170 321 nameInput.focus(); 171 322 return; … … 175 326 176 327 $.ajax({ 177 url: lean_csns_ ajax.ajax_url,328 url: lean_csns_params.ajax_url, 178 329 type: 'POST', 179 330 data: { 180 331 action: 'lean_csns_save_cart', 181 332 name: name, 182 nonce: lean_csns_ ajax.nonce333 nonce: lean_csns_params.nonce 183 334 }, 184 335 success: function(response) { -
lean-cart-share-and-save/trunk/includes/class-assets-manager.php
r3367807 r3377797 73 73 */ 74 74 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) { 76 80 return; 77 81 } … … 80 84 wp_enqueue_style('lean-csns-frontend'); 81 85 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', [ 84 91 'ajax_url' => admin_url('admin-ajax.php'), 85 92 'nonce' => wp_create_nonce('lean_csns_nonce'), 93 'buttons_html' => $buttons_html, // Pre-rendered button HTML 86 94 'i18n' => [ 87 95 'share_title' => __('Share Your Cart', 'lean-cart-share-and-save'), -
lean-cart-share-and-save/trunk/includes/class-base.php
r3367807 r3377797 51 51 // Frontend hooks 52 52 add_action('woocommerce_cart_coupon', [$this, 'add_cart_buttons']); 53 add_action('wp_footer', [$this, 'render_popup_template']); 53 54 54 55 // My Account integration … … 62 63 63 64 /** 64 * Add cart share/save buttons to cart page 65 * Add cart share/save buttons to cart page (classic themes) 65 66 */ 66 67 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() { 67 78 $share_enabled = lean_csns_get_option('cart_share.enable', '1'); 68 79 $save_enabled = lean_csns_get_option('cart_save.enable', '1'); 69 80 70 81 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) { 71 106 return; 72 107 } 73 108 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 template87 109 include LEAN_CSNS_PL_DIR . 'templates/popup.php'; 88 110 } -
lean-cart-share-and-save/trunk/includes/class-settings-page.php
r3367807 r3377797 134 134 'lean-csns-settings', 135 135 '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')] 137 137 ); 138 138 } -
lean-cart-share-and-save/trunk/lean-cart-share-and-save.php
r3373310 r3377797 3 3 * Plugin Name: Lean Cart Share and Save for WooCommerce 4 4 * Plugin URI: 5 * Description: Lightweight cart sharing and saving for WooCommerce 6 * Version: 1.0. 27 * Author: AZPlugins8 * 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/ 9 9 * License: GPLv2 or later 10 10 * License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 20 20 21 21 // Define plugin constants 22 define('LEAN_CSNS_VERSION', '1.0. 2');22 define('LEAN_CSNS_VERSION', '1.0.3'); 23 23 define('LEAN_CSNS_DB_VERSION', '1.0.0'); 24 24 define('LEAN_CSNS_PL_FILE', __FILE__); -
lean-cart-share-and-save/trunk/readme.txt
r3373332 r3377797 5 5 Tested up to: 6.8 6 6 Requires PHP: 7.4 7 Stable tag: 1.0. 27 Stable tag: 1.0.3 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 30 30 * **Cart Saving**: Allow logged-in users to save carts with custom names 31 31 * **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 32 33 * **My Account Integration**: Saved carts appear in customer My Account area 33 34 * **Flexible Settings**: Configure share expiry, enable/disable features … … 103 104 No, the plugin is designed to be lightweight and only loads assets when needed. It uses efficient database queries and follows WordPress best practices. 104 105 106 = Does it work with FSE (Full Site Editing) themes and WooCommerce Cart Blocks? = 107 108 Yes! 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 105 110 = Can I customize the appearance of the share/save buttons? = 106 111 … … 119 124 Go to Settings → Permalinks in your WordPress admin and click "Save Changes" (no need to change anything). This refreshes WordPress URL rules. 120 125 126 == Screenshots == 127 128 1. Plugin Settings page 129 2. Share Cart and Save Cart buttons on classic WooCommerce cart page 130 3. Share Cart and Save Cart buttons on FSE theme with WooCommerce Cart Block - works seamlessly with modern block-based cart pages 131 4. Cart sharing popup with generated shareable URL 132 5. Cart saving popup with custom name input 133 6. Saved carts displayed in My Account area 134 121 135 == 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 122 143 = 1.0.1 = 123 -Improved: Code optimizations and security enhancements144 * Improved: Code optimizations and security enhancements 124 145 125 146 = 1.0.0 =
Note: See TracChangeset
for help on using the changeset viewer.