子主题:为什么不要直接改别人的主题

作者: admin 分类: wordpress主题制作教程 发布时间: 2026-11-06 18:53

一个我后悔了三年的决定

我现在这个站用的主题,最早不是我自己写的。

它来自另一个站——一个物理教学网站,主题目录叫 jiaoxueshiping。我把它复制过来,改名成 caogenbj,然后开始改。

改 header、改 footer、改 CSS、加功能、修 bug。改得很顺手,因为文件就在那儿,打开就能编辑。

三年后我才发现,这个做法有个隐形成本:我再也拿不到上游的更新了。

不是说上游一定有好东西,而是说——从我把文件复制过来那一刻起,这条线就断了。以后上游修了一个安全漏洞,我不知道;加了一个新特性,我也用不上。这个主题彻底变成了”我一个人的分支”,它所有的问题都得我自己扛。

更具体的证据:我这次排查的时候,在 index.php 里发现一处背景图地址写的是:

background: url(http://www.caogenbj.com/wp-content/themes/jiaoxueshiping/notice_bg.gif)

目录早就改名成 caogenbj 了,这个路径还在指向老名字,所以那张图一直是 404。这就是”复制后直接改”留下的化石。

如果当初用的是子主题,这类问题根本不会存在——因为父主题的文件你一个字都不用动。

子主题到底解决了什么

一句话:把”我要改的”和”别人写的”分开存放。

父主题(原来的主题)保持原样,一个字节不改。你所有修改都放在子主题目录里。WordPress 加载时,先去子主题找文件,找不到再去父主题找。

这个机制叫模板覆盖。它有两个直接好处:

  1. 父主题可以更新。更新只覆盖父主题目录,你的子主题安然无恙;
  2. 改动一目了然。打开子主题目录,看到的就是你改过的东西,不用在几万行代码里找”我到底动了哪儿”。

怎么建一个子主题

两个文件就够。

第一个是 style.css,放在 wp-content/themes/caogenbj-child/ 下:

/*
Theme Name:   Caogenbj Child
Template:     caogenbj
Version:      1.0
*/

/* 下面写你自己的样式,会覆盖父主题 */

关键就是 Template: 那一行,值必须严格等于父主题的目录名。caogenbj 是目录名,不是 Theme Name。写错了,后台会提示”父主题不存在”。

第二个是 functions.php:

<?php
// 把父主题的样式表挂进来
add_action( 'wp_enqueue_scripts', function () {
    wp_enqueue_style(
        'caogenbj-parent',
        get_template_directory_uri() . '/style.css'
    );
} );

注意这里用的是 get_template_directory_uri()——它指向父主题。这个函数名很容易记反,下面单独说。

四个必须记住的对应关系

子主题只有四个函数容易搞混,但搞混了就是白屏或者样式全丢。做成一张表:

你要拿的东西 用哪个函数 指向
子主题的目录路径 get_stylesheet_directory() 子主题
子主题的 URL get_stylesheet_directory_uri() 子主题
父主题的目录路径 get_template_directory() 父主题
父主题的 URL get_template_directory_uri() 父主题

记法:stylesheet 是你现在用的(子),template 是你继承的(父)。

为什么这么命名?因为 WordPress 早期只有”当前主题”一个概念,管它叫 stylesheet;后来有了父子关系,”当前主题”变成子主题,但函数名没改。

这里有个真实的坑:你在子主题的 functions.php 里写 get_stylesheet_directory() . '/inc/seo.php',结果这个文件放在父主题里——那就 include 不到,直接报错。反过来也一样。所以每写一次,都要问自己一句:这个文件到底在谁的目录里?

functions.php 的加载顺序

这是子主题最反直觉的一点:子主题的 functions.php 先加载,父主题的后加载。

为什么这重要?因为如果父主题里写的是:

function my_setup() { ... }
add_action( 'after_setup_theme', 'my_setup' );

你想在子主题里”覆盖”这个函数,直接定义同名函数是不行的——PHP 会报 Cannot redeclare。正确做法是先用 remove_action 摘掉,再挂自己的:

<?php
add_action( 'after_setup_theme', function () {
    remove_action( 'after_setup_theme', 'my_setup' );
    // 然后 add_action 你自己的
}, 20 );

那个 20 是为了让”摘”这个动作发生在父主题已经挂上之后。因为子主题先加载,如果你在文件顶层直接 remove_action,父主题还没执行到 add_action 那一行,摘了个空。

这个顺序问题,是子主题新手最常踩的坑,没有之一。

哪些文件能覆盖,哪些不能

能覆盖的:所有模板文件。header.php、footer.php、index.php、single.php、page.php、category.php、searchform.php、sidebar.php……你把同名文件放进子主题,WordPress 就优先用你的。

不能覆盖的:父主题的 functions.php。子主题的 functions.php 是追加执行,不是替换。父主题的函数照样全部生效。

还有一类容易忽略的:父主题用 get_template_part() 加载的片段。这些片段默认从父主题找,除非你传了 get_stylesheet_directory() 或者它内部用了 locate_template()。locate_template() 会自动先找子主题,所以父主题作者如果用对了函数,你覆盖片段就能生效;如果硬写 include,你就覆盖不了。

这就是”主题写得好不好用”的分水岭之一。

我的建议

如果你现在正在改一个别人的主题,我的建议是:

  1. 新项目,一定用子主题。成本只有两个文件,收益是”以后还能更新”;
  2. 已经在直接改的,别急着迁。把现在的改动一条条搬进子主题,工作量不小,而且容易漏。除非你打算长期维护这个站;
  3. 自己从零写的主题,不需要子主题。子主题是为”改别人的东西”设计的,自己的主题直接改就行。

我这个站就属于第二种。现在迁不迁?我暂时没迁——因为我改造的幅度已经太大了,几乎是重写,迁成子主题的意义不大。但我把这个决定记下来了:下次建站,从第一天就用子主题。

小结

一句话记住:子主题不是”更高级的写法”,是”给自己留退路”。改别人的主题,两个文件就能留。

下一篇聊性能:脚本、图片、缓存,哪些是主题该管的,哪些不该。

本系列导航

相关文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Powered by 草根站长笔记 © 2015-2026 草根站长笔记 Inc.版权所有,禁止转载