| @@ -390,8 +390,17 @@ | ||
| 390 | 390 | require_once KING_ADDONS_PATH . 'includes/wishlist/Wishlist_Frontend.php'; |
| 391 | 391 | require_once KING_ADDONS_PATH . 'includes/wishlist/Wishlist_WooCommerce.php'; |
| 392 | 392 | require_once KING_ADDONS_PATH . 'includes/wishlist/Wishlist_Module.php'; |
| 393 | 393 | $this->wishlist_module = new Wishlist_Module(); |
| 394 | + } else { | |
| 395 | + // Extension off: still expire leftover guest cookies so public caches work. | |
| 396 | + require_once KING_ADDONS_PATH . 'includes/wishlist/Wishlist_Session.php'; | |
| 397 | + add_action('send_headers', static function () { | |
| 398 | + if (is_admin()) { | |
| 399 | + return; | |
| 400 | + } | |
| 401 | + \King_Addons\Wishlist\Wishlist_Session::expire_if_present(); | |
| 402 | + }); | |
| 394 | 403 | } |
| 395 | 404 | |
| 396 | 405 | // Dynamic Posts Grid AJAX Helper - Initialize regardless of Elementor compatibility |
| 397 | 406 | // This is needed for AJAX functionality to work even when PRO version is disabled |
| @@ -590,12 +599,12 @@ | ||
| 590 | 599 | style="border-left: 4px solid #0071e3;padding: 10px 15px;"> |
| 591 | 600 | <p style="font-size: 15px; margin:0; display: flex; align-items: center;"> |
| 592 | 601 | <span> |
| 593 | 602 | Get <strong style="font-weight: 700;">4,000+</strong> premium templates and sections, |
| 594 | - <strong style="font-weight: 700;">80+</strong> widgets, | |
| 603 | + <strong style="font-weight: 700;">100+</strong> widgets, | |
| 595 | 604 | <strong style="font-weight: 700;">200+</strong> advanced features, |
| 596 | 605 | and AI tools for Elementor. |
| 597 | - From $<strong style="font-weight: 700;">4</strong>/mo, billed annually. | |
| 606 | + From $<strong style="font-weight: 700;">6.99</strong>/mo. | |
| 598 | 607 | </span> |
| 599 | 608 | </p> |
| 600 | 609 | <p style="font-size: 14px; opacity: 0.6;">Trusted by 20,000+ users</p> |
| 601 | 610 | <p style="display: flex;"> |
| @@ -1746,16 +1755,19 @@ | ||
| 1746 | 1755 | $image = esc_url($args['image']); |
| 1747 | 1756 | $network = $args['network']; |
| 1748 | 1757 | |
| 1749 | 1758 | $get_whatsapp_url = function ($a) { |
| 1750 | - if ('yes' === $a['show_whatsapp_title'] && 'yes' === $a['show_whatsapp_excerpt']) { | |
| 1751 | - return 'https://api.whatsapp.com/send?text=*' . $a['title'] . '*%0a' . $a['text'] . '%0a' . $a['url']; | |
| 1752 | - } elseif ('yes' === $a['show_whatsapp_title']) { | |
| 1753 | - return 'https://api.whatsapp.com/send?text=*' . $a['title'] . '*%0a' . $a['url']; | |
| 1754 | - } elseif ('yes' === $a['show_whatsapp_excerpt']) { | |
| 1755 | - return 'https://api.whatsapp.com/send?text=*' . $a['text'] . '%0a' . $a['url']; | |
| 1759 | + $parts = []; | |
| 1760 | + if ('yes' === $a['show_whatsapp_title'] && $a['title'] !== '') { | |
| 1761 | + $parts[] = '*' . $a['title'] . '*'; | |
| 1756 | 1762 | } |
| 1757 | - return 'https://api.whatsapp.com/send?text=' . $a['url']; | |
| 1763 | + if ('yes' === $a['show_whatsapp_excerpt'] && $a['text'] !== '') { | |
| 1764 | + $parts[] = $a['text']; | |
| 1765 | + } | |
| 1766 | + if ($a['url'] !== '') { | |
| 1767 | + $parts[] = $a['url']; | |
| 1768 | + } | |
| 1769 | + return 'https://api.whatsapp.com/send?text=' . rawurlencode(implode("\n", $parts)); | |
| 1758 | 1770 | }; |
| 1759 | 1771 | |
| 1760 | 1772 | $networks_map = [ |
| 1761 | 1773 | 'facebook-f' => [ |
| @@ -1847,10 +1859,17 @@ | ||
| 1847 | 1859 | $share_url = $networks_map[$network]['url']; |
| 1848 | 1860 | $network_title = $networks_map[$network]['title']; |
| 1849 | 1861 | $icon_category = $networks_map[$network]['icon']; |
| 1850 | 1862 | |
| 1851 | - $output = '<a href="' . esc_url($share_url) . '" class="king-addons-share-icon king-addons-share-' . esc_attr($network) . '" target="_blank">'; | |
| 1863 | + // esc_url() strips encoded newlines (%0A), which concatenates WhatsApp title and URL. | |
| 1864 | + if ('whatsapp' === $network && str_starts_with($share_url, 'https://api.whatsapp.com/send?text=')) { | |
| 1865 | + $href = esc_attr($share_url); | |
| 1866 | + } else { | |
| 1867 | + $href = esc_url($share_url); | |
| 1868 | + } | |
| 1852 | 1869 | |
| 1870 | + $output = '<a href="' . $href . '" class="king-addons-share-icon king-addons-share-' . esc_attr($network) . '" target="_blank">'; | |
| 1871 | + | |
| 1853 | 1872 | if ('yes' === $args['tooltip']) { |
| 1854 | 1873 | $output .= '<span class="king-addons-share-tooltip king-addons-tooltip">' . esc_html($network_title) . '</span>'; |
| 1855 | 1874 | } |
| 1856 | 1875 | |
| @@ -2486,8 +2505,103 @@ | ||
| 2486 | 2505 | $value = $fallback; |
| 2487 | 2506 | } |
| 2488 | 2507 | |
| 2489 | 2508 | return (string) (0 + $value); |
| 2509 | + } | |
| 2510 | + | |
| 2511 | + /** | |
| 2512 | + * Swiper breakpoints use viewport width, so a desktop page with a ~600px | |
| 2513 | + * content column still shows 3–5 cards and crushes the text. Print a helper | |
| 2514 | + * that clamps slidesPerView to the carousel's own width. | |
| 2515 | + */ | |
| 2516 | + public static function printFitSlidesHelper(): void | |
| 2517 | + { | |
| 2518 | + static $printed = false; | |
| 2519 | + if ($printed) { | |
| 2520 | + return; | |
| 2521 | + } | |
| 2522 | + $printed = true; | |
| 2523 | + // Avoid && in this snippet: the_content encodes ampersands and would | |
| 2524 | + // turn the helper into invalid JavaScript. | |
| 2525 | + wp_print_inline_script_tag(<<<'JS' | |
| 2526 | +window.kingAddonsFitSlidesPerView = function (el, desired, minWidth, space) { | |
| 2527 | + desired = parseFloat(desired) || 1; | |
| 2528 | + minWidth = parseFloat(minWidth) || 240; | |
| 2529 | + space = parseFloat(space) || 0; | |
| 2530 | + if (!el) { | |
| 2531 | + return Math.max(1, desired); | |
| 2532 | + } | |
| 2533 | + var width = el.clientWidth || 0; | |
| 2534 | + if (width <= 0) { | |
| 2535 | + return Math.max(1, desired); | |
| 2536 | + } | |
| 2537 | + var maxFit = Math.max(1, Math.floor((width + space) / (minWidth + space))); | |
| 2538 | + return Math.min(desired, maxFit); | |
| 2539 | +}; | |
| 2540 | +window.kingAddonsBindFitSlides = function (swiper, el, minWidth) { | |
| 2541 | + if (!swiper) { | |
| 2542 | + return; | |
| 2543 | + } | |
| 2544 | + if (!el) { | |
| 2545 | + return; | |
| 2546 | + } | |
| 2547 | + if (typeof swiper.params === 'undefined') { | |
| 2548 | + return; | |
| 2549 | + } | |
| 2550 | + minWidth = parseFloat(minWidth) || 240; | |
| 2551 | + var apply = function () { | |
| 2552 | + var passed = swiper.passedParams || {}; | |
| 2553 | + var bpKey = swiper.currentBreakpoint; | |
| 2554 | + var fromBp = null; | |
| 2555 | + if (bpKey) { | |
| 2556 | + if (passed.breakpoints) { | |
| 2557 | + fromBp = passed.breakpoints[bpKey] || null; | |
| 2558 | + } | |
| 2559 | + } | |
| 2560 | + var desiredRaw = passed.slidesPerView; | |
| 2561 | + if (fromBp) { | |
| 2562 | + if (typeof fromBp.slidesPerView !== 'undefined') { | |
| 2563 | + desiredRaw = fromBp.slidesPerView; | |
| 2564 | + } | |
| 2565 | + } | |
| 2566 | + var desired = parseFloat(desiredRaw) || 1; | |
| 2567 | + var spaceRaw = swiper.params.spaceBetween; | |
| 2568 | + if (fromBp) { | |
| 2569 | + if (typeof fromBp.spaceBetween !== 'undefined') { | |
| 2570 | + spaceRaw = fromBp.spaceBetween; | |
| 2571 | + } | |
| 2572 | + } | |
| 2573 | + var space = parseFloat(spaceRaw) || 0; | |
| 2574 | + var next = window.kingAddonsFitSlidesPerView(el, desired, minWidth, space); | |
| 2575 | + if (swiper.params.slidesPerView !== next) { | |
| 2576 | + swiper.params.slidesPerView = next; | |
| 2577 | + if (typeof swiper.update === 'function') { | |
| 2578 | + swiper.update(); | |
| 2579 | + } | |
| 2580 | + } | |
| 2581 | + }; | |
| 2582 | + apply(); | |
| 2583 | + if (typeof swiper.on === 'function') { | |
| 2584 | + swiper.on('breakpoint', apply); | |
| 2585 | + } | |
| 2586 | + if (window.ResizeObserver) { | |
| 2587 | + new ResizeObserver(apply).observe(el); | |
| 2588 | + } else { | |
| 2589 | + window.addEventListener('resize', apply); | |
| 2590 | + } | |
| 2591 | +}; | |
| 2592 | +JS | |
| 2593 | + ); | |
| 2594 | + } | |
| 2595 | + | |
| 2596 | + /** | |
| 2597 | + * Wrap an inline `new Swiper(...)` so slidesPerView is clamped to the container. | |
| 2598 | + */ | |
| 2599 | + public static function wrapFitSwiper(string $selector, string $js_swiper, int $min_slide = 240): string | |
| 2600 | + { | |
| 2601 | + $sel = wp_json_encode($selector); | |
| 2602 | + $min = (string) max(1, $min_slide); | |
| 2603 | + return '(function(){var el=document.querySelector(' . $sel . ');if(!el){return;}if(typeof Swiper==="undefined"){return;}var sw=' . $js_swiper . ';if(typeof kingAddonsBindFitSlides==="function"){kingAddonsBindFitSlides(sw,el,' . $min . ');}})()'; | |
| 2490 | 2604 | } |
| 2491 | 2605 | |
| 2492 | 2606 | public static function getAttachmentImageHTML(array $settings, string $size_key, int $attachment_id): string |
| 2493 | 2607 | { |