本文约 3,384 字,预计阅读 9 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:改与不改之间的两难
直接改父主题文件,见效最快,代价是下一次主题升级把所有改动冲掉;不改吧,需求又实实在在摆在那儿。更麻烦的是,很多站是接手别人的项目,前任改过哪些文件没有任何记录,你一升级,改动消失了都不知道消失的是啥。
子主题就是解决这个矛盾的官方方案:父主题照常升级,你的改动单独存放在子主题目录里。但”建个 style.css 就完事”是常见误解——样式排队没写对会变成无样式页面,模板覆写路径错了会静默失效,函数覆写更要先确认父主题是否支持。
原理分析:子主题靠什么被识别、按什么顺序加载
WordPress 通过子主题 style.css 头注释里的 Template: 字段识别父主题,值是父主题的目录名(不是主题名)。Theme Name 是子主题自己的名字,两者别搞混。
加载顺序有个关键特性:子主题的 functions.php 先于父主题加载。这一点决定了两件事:其一,子主题里不能直接执行依赖父主题函数的代码(应挂到钩子上延迟执行);其二,子主题要移除父主题注册的 action,必须延迟到父主题注册之后。
样式加载则相反:核心不会自动引入父主题 style.css,需要子主题显式 wp_enqueue_style() 排队父主题样式表,再把子主题自己的样式排在它之后(通过 $deps 依赖参数保证顺序)。
模板覆写靠目录查找顺序:核心先查子主题目录,命中即用,未命中才用父主题的。所以”复制同名文件到子主题”就能覆盖,不需要任何额外声明。
| 改动类型 | 推荐方式 | 说明 |
|---|---|---|
| 少量样式 | 子主题 style.css 或额外 CSS |
简单直接 |
| 单个模板结构 | 复制同名文件到子主题 | 路径与文件名必须完全一致 |
| 局部片段 | 复制 template-parts/ 下对应文件 |
优先于复制整页模板 |
| 一两个函数 | 用 action/filter,不覆写 | 维护成本最低 |
| 父主题可插拔函数 | 子主题定义同名函数 | 需父主题用 function_exists() 包裹 |
| 新增功能 | 子主题 functions.php |
挂到合适的钩子上 |
保姆级实操
- 建目录:在
wp-content/themes/下新建目录,名字建议父主题-child,全小写无空格。 - 写
style.css:头注释至少包含Theme Name与Template,Template的值必须是父主题目录名。 - 写
functions.php:排队父主题样式(用get_template_directory_uri())与子主题样式(用get_stylesheet_directory_uri()),后者依赖前者。 - 用 WP-CLI 生成骨架:
wp scaffold child-theme会自动生成带正确头注释与排队代码的目录,省去手抄出错。 - 覆写模板:从父主题复制文件到子主题相同相对路径,例如父主题的
template-parts/content.php对应子主题的template-parts/content.php。 - 优先用钩子:能挂
add_filter解决的绝不复制模板,升级时改动面越小越好。 - 启用并核对:后台”外观 → 主题”里确认父主题仍在列表里(父主题缺失会导致子主题报错),前台检查样式是否正常加载。
/*
Theme Name: Lumen Child
Theme URI: https://mimangfei.com/
Description: lumen-mimangfei 的子主题
Author: mimangfei
Template: lumen-mimangfei
Version: 1.0.0
Text Domain: lumen-child
*/
/* 子主题样式写在这里,或放到独立文件由 functions.php 排队 */
.site-header {
position: sticky;
top: 0;
z-index: 100;
}
<?php
// 子主题 functions.php
add_action( 'wp_enqueue_scripts', 'mimangfei_child_enqueue' );
function mimangfei_child_enqueue() {
$parent = 'lumen-parent-style';
// 父主题样式:注意用 get_template_directory_uri()
wp_enqueue_style(
$parent,
get_template_directory_uri() . '/style.css',
array(),
wp_get_theme( 'lumen-mimangfei' )->get( 'Version' )
);
// 子主题样式:依赖父主题样式,保证顺序
wp_enqueue_style(
'lumen-child-style',
get_stylesheet_directory_uri() . '/style.css',
array( $parent ),
wp_get_theme()->get( 'Version' )
);
}
// 依赖父主题常量的代码必须延迟执行
add_action( 'after_setup_theme', 'mimangfei_child_setup', 20 );
function mimangfei_child_setup() {
add_theme_support( 'post-thumbnails' );
add_image_size( 'lumen-child-card', 600, 450, true );
}
# 用 WP-CLI 生成子主题骨架(自动写对 Template 与排队代码)
wp scaffold child-theme lumen-child --parent_theme=lumen-mimangfei --activate
# 确认父子主题都在
wp theme list
# 切换到子主题
wp theme activate lumen-child
常见踩坑
Template:写了主题显示名而不是目录名,后台直接提示父主题缺失。- 只排队了子主题样式、忘了父主题样式,前台变成纯文本无样式页面。
- 子主题样式没有声明对父主题的依赖,加载顺序颠倒,覆盖失效。
- 在子主题顶层直接调用父主题里定义的函数,因加载顺序导致
Call to undefined function。 - 案例:某站在子主题
functions.php里直接写remove_action( 'wp_head', 'lumen_head_meta' ),刷新后 meta 依然输出。原因是子主题functions.php先加载,此时父主题还没注册该 action。把移除逻辑包进after_setup_theme(优先级 20)后一次生效。 - 覆写的模板文件放错路径(如少了
template-parts/一层),前台静默使用父主题文件,改了没反应。 - 直接删掉父主题,以为子主题能独立运行。
总结
子主题的三条铁律:Template: 填目录名、父主题样式必须显式排队、依赖父主题的代码必须延迟执行。改动优先级为:钩子 > 局部模板片段 > 整页模板 > 直接改父主题。行动清单:① 用 wp scaffold child-theme 起骨架;② 父主题样式用 get_template_directory_uri();③ 子主题样式声明依赖;④ 覆写文件保持相同相对路径;⑤ 父主题永远保留在目录里。延伸阅读 WordPress 模板层级、lumen-mimangfei 主题升级备份 与 主题自定义 CSS 放置位置。
