wordPress-使用underscore 模板创建动态 HTML

场景:产品编辑页面,属性面板,颜色变体属性,自定义功能开发,允许对颜色单独绑定图片走廊。

比如:白色款式已经有三张图片了,这时,要新增新一张图片,这时可以利用Underscore 模板创建动态 HTML,嵌入原来包裹标签img的div中。具体步骤:

underscore模板定义及注意点

function add_product_color_gallery_field4() {
    // 输出模板定义(确保在DOM中)
    ?>
    <script type="text/html" id="tmpl-color-gallery-preview">
        <img src="{{ data.url }}" 
             style="max-width:80px; margin:5px;" 
             data-id="{{ data.id }}" 
             alt="Preview Image">
    </script>
    <?php
    // 加载 JavaScript
    wp_enqueue_script('product-color');
}

注意1:上面的模板语法是:{{ data.url }}

而不是:<%= data.url %>

众所周知,Underscore.js 默认使用 ERB 风格模板<%= value %>,但这种语法与 PHP 的 ASP 风格标签(<% %>)冲突。当 PHP 的asp_tags选项启用时,服务器会误解析这些模板标记,导致前端渲染失败。

因此,为避免冲突,WordPress 采用了 Mustache 风格的模板语法{{ value }}。这种语法与 PHP 标签无冲突,确保了在各种 PHP 配置下的兼容性。

体现在通过 wp.template() 函数对其进行了封装,具体在wp-util.js文件里:

wp.template = _.memoize(function ( id ) {
    var compiled,
        options = {
            evaluate:    /<#([\s\S]+?)#>/g,
            interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
            escape:      /\{\{([^\}]+?)\}\}(?!\})/g,
            variable:    'data'
        };
    return function ( data ) {
        if ( ! document.getElementById( 'tmpl-' + id ) ) {
            throw new Error( 'Template not found: ' + '#tmpl-' + id );
        }
        compiled = compiled || _.template( $( '#tmpl-' + id ).html(),  options );
        return compiled( data );
    };
});

注意2:数据通过变量data访问。上面代码段variable: ‘data’,意味着渲染模板时,传入的数据对象会被绑定到一个名为 data 的变量上,模板内的所有表达式都通过这个变量访问数据。如下:

{{ data.url }}

如果直接用{{ url }} 访问,浏览器会发生错误提示:Error: url is not defined。这是个不起眼的坑,我排查这个坑费了一下午时间!!

注意3:上面代码document.getElementById( ‘tmpl-‘ + id )可知:WordPress 约定使用 id=”tmpl-…” 格式命名模板。

在 JavaScript 中使用模板进行编译、渲染

//product-color.js
(function ($, wp) {
    // 确保 wp-util.js 已加载并配置 Underscore
    $(document).ready(function () {
        // 获取模板
        const tpl = wp.template('color-gallery-preview');
        if (typeof tpl !== 'function') {
            console.error('模板未找到');
            return;
        }
        // 测试渲染
        const data1 = {
            url: 'http://localhost/wp-content/uploads/2025/05/air-force-1-07-02.avif',
            id: 1388
        };
        try {
            const testHTML = tpl(data1);
            console.log('渲染结果:', testHTML);
        } catch (error) {
            console.error('模板渲染失败:', error);
        }
    });
})(jQuery, wp);

注意1:获取模板是通过:wp.template函数调用,且省略 “tmpl-” 前缀。而wp.template函数依赖于wp-util.js。所以引入注册product-color.js自定义文件时,需依赖wp-util,如下:

function admin_register_script() {
    wp_register_script(
        'product-color',
        get_template_directory_uri().'/js/shop/product-color.js',
        array( 'jquery', 'wp-util', 'underscore' ), // 依赖 wp-util underscore
        filemtime(get_template_directory().'/js/shop/product-color.js'),
        true);
}
//加载后台管理页面时,触发 admin_enqueue_scripts 钩子
add_action( 'admin_enqueue_scripts', 'admin_register_script' );

最后测试结果如下: