WooCommerce Blocks结账页添加希腊专属动态免运费提示遇插件时机问题
WooCommerce Blocks结账页添加希腊专属免运费提示文本问题解决
需求说明
- 在WooCommerce Blocks结账页面的配送方式列表下方添加动态提示文本(示例:"Add x € to your basket to receive free shipping!")
- 仅当配送国家为希腊时显示该文本
- 根据URL路径切换希腊语、英语、德语三种语言版本
原实现问题
编写的JavaScript代码在浏览器控制台运行正常,但封装为WordPress插件后因执行时机不匹配无法生效:
原插件PHP代码
<?php /** * Plugin Name: Custom Shipping Note Greece * Description: Shows a free shipping message on WooCommerce checkout when shipping to Greece, with GR/EN/DE support. * Version: 1.0 * Author: xxxx * Text Domain: custom-shipping-note-greece */ if ( ! defined( 'ABSPATH' ) ) { exit; } add_action( 'wp_footer', function() { if ( ! function_exists( 'is_checkout' ) ) return; if ( ! is_checkout() || is_order_received_page() ) return; ?> <style> #free-shipping-note { margin-top: 12px; font-weight: 600; font-size: 14px; color: #1a1a1a; } #free-shipping-note.muted { color: #666; font-weight: 500; } </style> <script> /* .js SCRIPT GOES HERE*/ </script> <?php });
原JavaScript代码
(function(){ const FREE_THRESHOLD = 50; const LANG_TEXTS = { gr: { calculating: 'Υπολογισμός διαφοράς δωρεάν αποστολής...', free: 'Δικαιούστε δωρεάν αποστολή!', add: diff => 'Προσθέστε ' + diff + ' στο καλάθι σας για να λάβετε δωρεάν αποστολή!' }, en: { calculating: 'Calculating free-shipping difference...', free: 'You qualify for free shipping!', add: diff => 'Add ' + diff + ' to your basket to receive free shipping!' }, de: { calculating: 'Berechnung des kostenlosen Versandunterschieds...', free: 'Sie qualifizieren sich für kostenlosen Versand!', add: diff => 'Fügen Sie ' + diff + ' Ihrem Warenkorb hinzu, um kostenlosen Versand zu erhalten!' } }; function getLang(){ const path = window.location.pathname; if (path.startsWith('/en/')) return 'en'; if (path.startsWith('/de/')) return 'de'; return 'gr'; } function formatMoney(num){ return Number(num).toFixed(2).replace('.', ',') + ' €'; } function getSubtotal(){ const rows = document.querySelectorAll('.wc-block-components-totals-item'); for (let row of rows){ const label = row.querySelector('.wc-block-components-totals-item__label'); const valueEl = row.querySelector('.wc-block-components-totals-item__value'); if (!label || !valueEl) continue; if (label.textContent.trim() === 'Υποσύνολο' || label.textContent.trim() === 'Subtotal' || label.textContent.trim() === 'Zwischensumme'){ const text = valueEl.textContent.replace(/[^\d,\.]/g,''); const val = text.replace('.', '').replace(',', '.'); return parseFloat(val) || 0; } } return 0; } function getShippingCountry(){ const shippingEl = document.querySelector('#shipping-country'); if (shippingEl) return shippingEl.value.toUpperCase(); const billingEl = document.querySelector('#billing-country'); return billingEl ? billingEl.value.toUpperCase() : null; } function insertNote(){ const shippingContainer = document.querySelector('.wc-block-components-shipping-rates-control'); if (!shippingContainer) return null; let note = document.querySelector('#free-shipping-note'); if (!note){ note = document.createElement('div'); note.id = 'free-shipping-note'; note.style.marginTop = '12px'; note.style.fontWeight = '600'; note.style.fontSize = '14px'; shippingContainer.insertAdjacentElement('afterend', note); } return note; } function updateNote(){ const lang = getLang(); const country = getShippingCountry(); if (country !== 'GR'){ const note = document.querySelector('#free-shipping-note'); if (note) note.style.display = 'none'; return; } const note = insertNote(); if (!note) return; note.style.display = 'block'; const subtotal = getSubtotal(); if (!subtotal) { note.textContent = LANG_TEXTS[lang].calculating; return; } if (subtotal >= FREE_THRESHOLD){ note.textContent = LANG_TEXTS[lang].free; } else { const diff = FREE_THRESHOLD - subtotal; note.textContent = LANG_TEXTS[lang].add(formatMoney(diff)); } } function observeChanges(){ const shippingContainer = document.querySelector('.wc-block-components-shipping-rates-control'); if (shippingContainer){ const observer = new MutationObserver(updateNote); observer.observe(shippingContainer, {childList:true, subtree:true}); } const shippingEl = document.querySelector('#shipping-country'); if (shippingEl) shippingEl.addEventListener('change', updateNote); const billingEl = document.querySelector('#billing-country'); if (billingEl) billingEl.addEventListener('change', updateNote); const sameAsBilling = document.querySelector('#ship-to-different-address-checkbox'); if (sameAsBilling) sameAsBilling.addEventListener('change', updateNote); } const interval = setInterval(()=>{ if (document.querySelector('.wc-block-components-shipping-rates-control')){ clearInterval(interval); observeChanges(); updateNote(); } }, 200); })();
正确解决方案
由于WooCommerce Blocks基于React的渲染机制,传统wp_footer注入脚本的方式无法准确匹配DOM加载与数据更新时机,正确方案是构建WooCommerce结账块扩展,核心实现思路:
- 注册自定义块扩展,挂载到结账页面的配送费率控件区域
- 利用WooCommerce官方提供的状态管理API,监听购物车小计、配送国家等核心数据变化
- 根据当前语言(从URL路径判断)和配送国家,动态渲染对应的免运费提示文本
内容的提问来源于stack exchange,提问作者strangeattractor
相关产品推荐
相关产品推荐

