子主题是父主题的扩展版本。它允许你在无需直接编辑主题代码的情况下对现有主题进行修改。这些修改可能只是简单的颜色调整,也可能较为复杂,包括对父主题的定制化覆盖。
在本文中,你将了解什么是父主题与子主题,如何通过子主题创建自己的修改内容,以及父主题中哪些部分可以被覆盖。
什么是父主题与子主题?
父主题
所有主题——除非它们被明确定义为子主题——从技术层面来讲都属于父主题。也就是说,它们都是完整的主题,可以安装在 WordPress 中并启用。
父主题必须包含主题结构文档中列出的所有必需文件。除此之外,要让你的主题成为父主题,并不需要做任何特别处理。
子主题
默认情况下,子主题会包含其父主题的所有内容,包括设计风格及各类功能。同时,它还可以用于在不直接修改父主题文件的情况下对其进行定制,这样你(或使用该子主题的用户)依然能够获得父主题的更新,而不会丢失这些自定义设置。
子主题的优势包括:
- 让你的修改具备可移植性与可复制性。
- 将自定义设置与父主题分开管理。
- 让父主题可以更新,同时不会丢失你的自定义内容。
- 由于只需编写所需的代码,因此能够节省开发时间。
- 是开始开发完整主题的绝佳途径。
需要注意的是,如果在子主题中进行大量定制,最终可能会给管理带来麻烦。对于这类较为复杂的项目,通常更好的做法是复制原始主题并创建属于自己的完整/父主题。这需要根据具体情况来决定。
那孙主题呢?
目前还无法创建孙主题。标准的主题层级结构只有两层:父主题和子主题。
不过,在构建块主题时,网站前端还会存在其他层级(只不过它们不属于主题层级):
- WordPress 本身(默认的
theme.json) - 父主题
- 子主题
- 用户自定义设置(可以覆盖
theme.json、模板及样式规则)
从某种意义上说,用户自定义设置层可以视为一种“孙主题”。两者的主要区别在于,自定义更改是存储在数据库中而非文件系统中。
除此之外,目前并没有创建可安装的孙主题的标准方法。
如何创建子主题
让我们试着为 WordPress 自带的默认主题 Twenty Twenty-Four 创建一个子主题。
创建子主题文件夹
首先,你的子主题需要一个名称。你可以随意为其命名,但在本指南中,我们将其命名为“Grand Sunrise”。
接着,在 wp-content/themes 目录下创建一个新文件夹,文件夹名称使用下划线分隔的形式,即 grand-sunrise。
创建 style.css 文件
现在你需要创建一个名为 style.css 的文件。这是子主题存在的绝对必要文件。所有的 style.css 文件都必须包含文件头以及 主样式表文档中规定的必要字段(如果你还没有阅读过该文档,请务必查看)。
正如主样式表文档中所提到的,要声明一个主题为子主题,还需要一个额外的字段。你必须在 style.css 的文件头中添加 Template 字段:
/**
* Theme Name: Grand Sunrise
* Template: twentytwentyfour
* ...其他字段
*/Template 字段有一个注意事项:它的值必须与 wp-content/themes 目录下父主题的文件夹名称完全一致。由于 Twenty Twenty-Four 主题的文件夹位于 wp-content/themes/twentytwentyfour,因此 Template 的值必须是 twentytwentyfour。
安装并启用子主题
如果你当前所处的开发环境中的主题尚未放在 wp-content/themes 目录下,那么现在就需要将其移至此目录。根据你的设置,有多种方法可选,最简单的方法是将主题打包为 ZIP 文件,然后通过 WordPress 管理后台的外观 > 主题 > 添加新主题路径将其上传到测试站点。
如需了解如何向 WordPress 添加主题的更多信息,请阅读 WordPress 文档网站上的添加新主题文章。
主题安装完成后,进入 WordPress 管理后台的外观 > 主题页面,找到你的主题,然后点击截图中所示的启用链接:

由于你还没有对主题进行任何自定义,它看起来会与父主题没有区别。但你已经成功创建了一个子主题。
自定义你的子主题
在自定义子主题时,本手册中介绍的所有功能都可以使用。不过还有几点需要注意,这些内容将在后续章节中介绍。
加载 style.css 文件
这是可选步骤,对于块主题来说通常并不需要,因为它们的样式处理一般是通过theme.json来实现的。但如果你正在构建传统主题,这一步往往是必要的。无论如何,只有当你希望确保 style.css 中的 CSS 代码能够被加载时,才需要执行此步骤。
在继续学习本节内容之前,请务必先阅读包含资源文档,该文档详细介绍了如何加载 style.css。在文档中,你将了解到如何通过 wp_enqueue_style()函数在合适的钩子点上加载样式表(请注意,子主题的加载顺序在父主题之前)。
理想的加载样式表的方式是让父主题同时加载自身的 style.css 和子主题的 style.css。但并非所有主题都会这样做。因此,你必须查看父主题的代码,了解它加载了哪些样式表。每个主题的情况都不同,没有固定规则。
如果父主题已经加载了这两种样式表,那么子主题就无需做任何操作,其样式表会自动被加载。
对于 Twenty Twenty-Four 主题来说,它根本不加载任何样式表。因此,你需要通过 functions.php 文件来加载自己的 style.css,代码示例如下:
add_action( 'wp_enqueue_scripts', 'grand_sunrise_enqueue_styles' );
function grand_sunrise_enqueue_styles() {
wp_enqueue_style(
'grand-sunrise-style',
get_stylesheet_uri()
);
}如果你使用的父主题只加载自身的样式表,你也可以使用上述代码来加载子主题的 style.css。
如果父主题仅加载当前激活主题的样式表,比如通过 get_stylesheet_uri() 来加载,那么它也会加载子主题的样式表。在这种情况下,你可能还需要通过 functions.php 文件来加载父主题的样式表,代码如下:
add_action( 'wp_enqueue_scripts', 'grand_sunrise_enqueue_styles' );
function grand_sunrise_enqueue_styles() {
wp_enqueue_style(
'grand-sunrise-parent-style',
get_parent_theme_file_uri( 'style.css' )
);
}模板、部件与样式规则
在创建子主题时,你可以通过在子主题中添加同名文件来覆盖父主题中现有的任何模板、部件或样式规则。注意:样式规则也必须拥有相同的已注册 Slug 字段。
你还可以在子主题中添加全新的模板、部件和样式规则,即使父主题中不存在这些内容。要了解更多关于这些功能的信息,请参阅手册中的以下文章:
使用 functions.php 文件
与模板和样式规则不同,子主题的 functions.php 文件并不会覆盖父主题的 functions.php 文件。实际上,这两个文件都会被加载,且子主题的文件会在父主题之前被加载。
这样一来,子主题的 functions.php 文件就提供了一种巧妙且不会出问题的方法,用于修改父主题或 WordPress 的功能。
假设你想在主题中添加一个 PHP 函数,最快的方法就是打开其 functions.php 文件并将函数放入其中。但这并不是良好的做法——下次主题更新时,你的函数就会消失!
更好的做法是创建一个子主题,然后将自定义代码添加到子主题的 functions.php 文件中。这样,该函数依然能够实现相同的功能,而且不会受到父主题后续更新的影响。
请勿直接从父主题的 functions.php 文件复制代码到子主题中,因为这很可能会导致由于函数名称重复而出现的致命错误。
要了解更多关于 functions.php 的信息,请查看自定义功能文档。
引用或包含其他文件
有时你需要在主题中包含或使用自定义文件。此时,你需要确保使用能够根据子主题的目录结构返回正确目录路径或 URI 的函数。
例如,如果你想通过 functions.php 文件包含另一个 PHP 文件,可以使用 get_theme_file_path() 函数。以下代码片段展示了如何从子主题的 /inc 文件夹中包含 functions-helpers.php 文件:
require_once get_theme_file_path( 'inc/functions-helpers.php' );要了解更多关于包含文件的信息,请阅读自定义功能文档。
当你需要通过 URL 引用文件,比如图片或样式表时,必须使用不同的函数:get_theme_file_uri()。下面是一个示例,演示了如何在使用 <img> HTML 标签时引用主题的 /assets/images 文件夹中的 bunny.jpg 文件:
<?php $image = get_theme_file_uri( 'assets/images/bunny.jpg' ); ?>
<img src="<?php echo esc_url( $image ); ?>" alt="" />要了解更多关于包含脚本、样式、图片及其他资源的信息,请参阅包含资源文档。
国际化
与父主题一样,子主题也可以实现国际化,从而支持多种语言。要了解更多信息,请阅读主题手册中的国际化文档。
正如国际化文档中所述,最大的变化在于,你必须创建一个唯一的文本域,并在手动加载翻译文件时使用 load_child_theme_textdomain() 而非 load_theme_textdomain()。