几乎所有 WordPress 教程都会告诉你:改主题之前先建子主题。但很少有人解释为什么,也很少有人说清楚什么时候其实没必要。
结果就是两种极端:有人改一行 CSS 也要建个子主题,有人直接改父主题然后某天更新一下,改动全没了。
一、子主题到底解决什么问题
一句话:主题更新时,你的改动不会被覆盖。
机制的实质:子主题是一个只有几行配置的小主题,它「继承」父主题的所有功能,但允许你只覆盖你想改的那几个文件。
WordPress 渲染页面时的规则是:
- 先找子主题里有没有这个模板文件
- 有 → 用子主题的
- 没有 → 用父主题的
所以你只在子主题里放你改过的文件,其他的自动走父主题。父主题更新时,它改的是自己的文件,你放在子主题里的文件不受影响。
二、什么时候必须建子主题
必须建的情况
- 你要改主题的 PHP 模板文件(比如
single.php、archive.php、header.php) - 你要在
functions.php里加自定义代码(钩子、短代码、自定义函数) - 你用的是商业主题,且它会持续更新(绝大多数商业主题都会)
- 你要大量重写样式,而且希望这些样式在主题升级后依然存在
可以不建的情况
- 只改几行 CSS —— 用后台的「额外 CSS」(外观 → 自定义 → 额外CSS)就够了,这个存在数据库里,主题更新不受影响
- 你的主题是自己写的、不会更新 —— 那父子主题没区别
- 只装了插件来扩展功能,没动主题文件 —— 不需要
判断标准其实很简单:你会不会动主题的文件。会动,就建;不动,就不用。
三、手把手:5 分钟建一个子主题
方法一:手动建(最可靠,推荐)
在 /wp-content/themes/ 下新建一个文件夹,比如 inkwell-child,里面放两个文件。
style.css:
/* Theme Name: Inkwell Child Template: inkwell Version: 1.0 */
关键是 Template: inkwell 这一行——必须填父主题的文件夹名,不是主题名。这是最容易填错的地方,填错了子主题会报错或者不生效。
functions.php:
<?php
add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_style( 'parent-style',
get_template_directory_uri() . '/style.css' );
});
然后后台 → 外观 → 主题,启用这个子主题。
注意:启用子主题后,菜单、小工具、自定义器的设置可能需要重新配置一遍(因为 WordPress 是按主题名存储这些设置的)。这是正常现象,不是出错。
方法二:插件生成
装 Child Theme Configurator 插件,几步向导就生成好了。适合不想碰代码的。
缺点是可能生成一些多余代码,但对于「我就是想改点东西」的场景完全够用。
四、子主题里怎么覆盖父主题的文件
模板文件:同名覆盖
想改 single.php?在子主题里建一个同名文件,写你的版本。WordPress 会优先用你的。
最佳实践:不要从头写,把父主题的文件复制过来再改。这样能保证结构一致,不会漏掉父主题里的关键调用。
functions.php:是追加,不是覆盖
这是子主题机制里最容易误解的一点。
模板文件是「有就用你的,没有就用父的」,但 functions.php 不一样:WordPress 会先加载子主题的 functions.php,再加载父主题的。两个都会执行。
所以:
- ✅ 你可以在子主题的 functions.php 里新增函数
- ❌ 你不能通过「在子主题里定义同名函数」来覆盖父主题的函数——会报「函数重复声明」的致命错误
那父主题的函数怎么改?
三个办法,按优先级:
1. 用钩子(最优)——如果父主题的函数挂在某个钩子上,你可以 remove_action 掉它,再加自己的:
// 移除父主题的函数 remove_action( 'wp_head', 'parent_theme_function', 10 ); // 加自己的 add_action( 'wp_head', 'my_function', 10 );
2. 用 pluggable 函数——如果父主题的函数写成了 if ( ! function_exists( 'xxx' ) ) { ... } 这种形式,你只要在子主题里先定义同名函数,父主题就会跳过自己的版本。好的主题都会这么写。
3. 改父主题(下策)——实在没办法时只能改,但要在文件里写清楚注释,并且记住下次更新后要重新改。
五、几个真实的坑
坑 1:Template 填了主题名而不是文件夹名
父主题显示叫「Inkwell」,但文件夹叫 inkwell-master 或者 inkwell-v2。必须填文件夹名。
查文件夹名:FTP 进 /wp-content/themes/ 看,或者在主题详情页面的 URL 里能看到。
坑 2:父主题样式没加载,页面变裸
启用子主题后页面完全没有样式——functions.php 里没正确引入父主题的 CSS,或者引入顺序错了。
如果你的父主题用的是比较新的加载方式,光引 style.css 不够,可能需要:
add_action( 'wp_enqueue_scripts', function() {
$parent = 'parent-style';
wp_enqueue_style( $parent,
get_template_directory_uri() . '/style.css',
array(), wp_get_theme()->parent()->get('Version') );
wp_enqueue_style( 'child-style',
get_stylesheet_uri(), array( $parent ) );
});
关键是让自己的样式依赖父主题样式(第三个参数的 array($parent)),保证加载顺序。
坑 3:子主题启用后网站白屏
通常是 functions.php 有语法错误(少分号、多括号),或者函数名和父主题冲突。
排查:FTP 把子主题的 functions.php 改名,看网站是否恢复。恢复了就是它的问题。
坑 4:商业主题不让你用子主题
少数主题(尤其一些页面构建器配套的)用了特殊机制,子主题会出问题。这种情况看主题官方文档的说明——它们通常会提供自己的解决方案。
六、一个更轻的替代方案
如果你的改动只是「加一些函数」,其实还有个比子主题更轻的做法:装一个代码片段插件(比如 Code Snippets)。
它把你的自定义代码存在数据库里通过插件执行,跟主题完全解耦。换主题也不受影响。
优点:不用建子主题、后台就能改、可以为每段代码加注释和开关。
缺点:代码存在数据库,不能用 Git 管理;如果有语法错误,插件一般会帮你拦住不会白屏。
我的用法:功能性的代码(钩子、短代码)用 Code Snippets;涉及模板结构改动的用子主题。
最后
记住这一条就够了:只要你会动主题的 PHP 文件,就先建子主题。建一个五分钟,不建的代价是某天主题一更新,你花几小时做的定制全部消失——而且你可能过了一周才发现。
而如果只改 CSS,后台的「额外 CSS」就够了,别折腾。