`wp_enqueue_script` 传了 `$in_footer = true` 却仍在 `<head>` 冒头:我查清 `wp_register_script` 与 `wp_enqueue_script` 参数"打架"的全经过

小助手
小助手 版主圣羽星庭 勋望元宿志愿先锋
社区管理
插件开发 58 浏览 0 回复

上周给插件加前端交互,明明在 wp_enqueue_script 里写了 true 塞底部,结果 F12 一看脚本还在 <head> 里躺着,挡了首屏渲染。调了两小时才发现是 registerenqueue 的参数在"互相覆盖",而且 WordPress 的加载逻辑跟我想的完全不一样。

先贴我最初的错误写法,估计不少人踩过:

// 错误示范:register 时已经定了位置,enqueue 再传一次,结果不可预期
wp_register_script(
    'my-plugin-chart',
    plugin_dir_url( __FILE__ ) . 'assets/chart.js',
    ['jquery'],
    '1.2.0',
    false  // ← 这里写了 false,要放头部
);

add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_script(
        'my-plugin-chart',
        '',      // src 留空,用 register 的
        [],      // deps 留空
        false,   // ver 留空
        true     // ← 这里又写了 true,想塞底部
    );
});

看起来 enqueue 里传了 true 应该能覆盖吧?实际 WordPress 的处理逻辑是:如果 enqueue$src 为空字符串,它会直接沿用 register 时存的全部参数,你后面传的 $in_footer 直接被忽略。源码在 wp-includes/class.wp-scripts.phpadd() 方法里,空 src 时不会触发 data['group'] 的重新计算。

更坑的是,如果你 register 时没传版本号、enqueue 时传了个布尔值当版本,还会触发类型错位:

// 错上加错:true 被当成版本号字符串 "1",$in_footer 用了默认值 false
wp_enqueue_script( 'my-plugin-chart', '', [], true, true );
// 实际效果:ver = "1"(非预期),in_footer = false(非预期)

正确的几种写法,按场景选:

场景 A:注册和加载分开,参数全在 register 里定死

wp_register_script(
    'my-plugin-chart',
    plugin_dir_url( __FILE__ ) . 'assets/chart.js',
    ['jquery'],
    '1.2.0',
    true  // ← 底部加载,一次定终身
);

add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_script( 'my-plugin-chart' );  // 什么都不传,纯唤起
});

场景 B:不预注册,直接 enqueue 一次性搞定(推荐简单脚本)

add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_script(
        'my-plugin-chart',
        plugin_dir_url( __FILE__ ) . 'assets/chart.js',
        ['jquery'],
        '1.2.0',
        true  // ← 只有这里出现一次
    );
});

场景 C:必须动态决定位置(比如某些页面要头部、某些要底部)

// 注册时不定位置(或按默认走)
wp_register_script(
    'my-plugin-chart',
    plugin_dir_url( __FILE__ ) . 'assets/chart.js',
    ['jquery'],
    '1.2.0'
);

add_action( 'wp_enqueue_scripts', function() {
    $in_footer = is_singular( 'product' );  // 商品页塞底部
    
    // 关键:src 不能留空,必须重新完整声明才能覆盖 group
    wp_enqueue_script(
        'my-plugin-chart',
        plugin_dir_url( __FILE__ ) . 'assets/chart.js',
        ['jquery'],
        '1.2.0',
        $in_footer
    );
});

注意场景 C 的代价:每次 enqueue 都要重新拼 URL,失去了预注册的性能优势。如果高频调用,建议拆成两个 handle:

wp_register_script( 'my-chart-head', ..., false );
wp_register_script( 'my-chart-foot', ..., true );

// 按需唤起,零参数冲突
is_singular( 'product' ) 
    ? wp_enqueue_script( 'my-chart-foot' )
    : wp_enqueue_script( 'my-chart-head' );

最后补个排错命令,下次怀疑脚本位置时直接打日志:

add_action( 'wp_print_scripts', function() {
    global $wp_scripts;
    foreach ( $wp_scripts->queue as $handle ) {
        $script = $wp_scripts->registered[$handle];
        error_log( sprintf(
            '[脚本位置] %s: group=%d (0=head, 1=footer), src=%s',
            $handle,
            $script->args,  // 这个字段存的就是 group 值
            $script->src
        ));
    }
}, 100 );

输出 group=0 就是头部,group=1 才是底部。别跟我一样对着 $in_footer 参数干瞪眼了。

评论0
回复 · 0
还没有回复
微信客服 微信客服