搜索全站
主题 12 分钟阅读

WordPress 子主题标准制作步骤:style.css + functions.php 从零做

改父主题怕升级覆盖?做一个子主题就行。本文从零走一遍:style.css 的 Template 声明、functions.php 的正确加载方式、目录结构、截图与启用验证,附常见失效原因排查。

U
UFO_PF 2018-06-25 · 阅读 12 分钟
Wo 主题
阅读提示
本文约 4,430 字,预计阅读 12 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:直接改父主题,迟早要还

「在 functions.php 末尾加段代码」「把 single.php 里那行标题换掉」——直接改父主题是最快的改法,也是最贵的一种。父主题一升级,你的改动被覆盖,站点回到出厂状态;更糟的是有些改动升级后只覆盖一半,页面变成「新旧混合」的怪样子,排查成本远高于当初省下的时间。

子主题(Child Theme)就是为了解决这个问题:它继承父主题的全部功能与模板,你只写「不一样的那部分」。升级父主题时,子主题目录不受影响。对使用商业主题(Astra、GeneratePress、OceanWP、Kadence 等)的站点来说,子主题几乎是标配。

原理分析:WordPress 怎么把两个主题拼起来

WordPress 用两个常量区分父与子:

概念 父主题 子主题
目录常量 TEMPLATEPATH / get_template_directory() STYLESHEETPATH / get_stylesheet_directory()
URI 常量 get_template_directory_uri() get_stylesheet_directory_uri()
识别依据 当前启用主题的 style.css Template: 字段指向父主题目录名

识别的关键是 style.css 头部里的 Template:——它必须填父主题目录的文件夹名(如 astra),不是主题名(如「Astra」)。填错的表现是:后台里子主题显示为「损坏的主题」,提示「父主题缺失」。

加载顺序上有个重要细节:子主题的 functions.php 会先于父主题加载(详见 子主题与父主题 functions.php 执行顺序),而模板文件是子主题优先。样式表则不会自动加载——父主题的 style.css 需要你显式引入,这正是新手最容易踩的第一个坑:启用子主题后站点变成无样式的裸 HTML。

保姆级实操

第一步:建目录与 style.css

cd wp-content/themes
mkdir astra-child

wp-content/themes/astra-child/style.css:

/*
Theme Name: Astra Child
Theme URI: https://mimangfei.com/themes/astra-child
Description: Astra 的子主题,用于放置自定义样式与模板。
Author: 迷忙飞
Author URI: https://mimangfei.com
Template: astra
Version: 1.0.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: astra-child
*/

只有 Theme Name 和 Template 是必需的,其余按项目补。Template 的值与你看到的父主题目录名完全一致(区分大小写):

ls wp-content/themes | grep -i astra

第二步:写 functions.php 加载父主题样式

现代写法(推荐,支持依赖与缓存控制):

<?php
add_action( 'wp_enqueue_scripts', 'astra_child_enqueue_styles' );

function astra_child_enqueue_styles() {
    $parent = wp_get_theme( 'astra' );

    wp_enqueue_style(
        'astra-parent-style',
        get_template_directory_uri() . '/style.css',
        array(),
        $parent ? $parent->get( 'Version' ) : null
    );

    wp_enqueue_style(
        'astra-child-style',
        get_stylesheet_uri(),
        array( 'astra-parent-style' ),
        wp_get_theme()->get( 'Version' )
    );
}

关键点:子主题样式的第三个参数(依赖)填父主题样式的句柄,保证 CSS 输出顺序是「父在前、子在后」,这样你的规则才能覆盖父主题的同名规则。

第三步:确认父主题样式句柄(进阶)

如果父主题已经用某个句柄注册了主样式,重复注册会输出两份。更好的做法是查清父主题的句柄,把子样式挂在它后面:

grep -rn "wp_enqueue_style" wp-content/themes/astra/functions.php | head

或者在运行时打印:

add_action( 'wp_print_styles', function() {
    global $wp_styles;
    if ( isset( $_GET['debug_styles'] ) ) {
        echo '<pre>' . esc_html( implode( "\n", array_keys( $wp_styles->registered ) ) ) . '</pre>';
    }
} );

拿到父主题句柄(如 astra-theme-css)后:

wp_enqueue_style(
    'astra-child-style',
    get_stylesheet_uri(),
    array( 'astra-theme-css' ),
    wp_get_theme()->get( 'Version' )
);

第四步:加截图(可选但强烈建议)

做一张 1200×900 的 screenshot.png 放进子主题目录。没有它,后台主题列表里显示为一个灰色占位块,多个主题并存时很难分辨。

第五步:启用并验证

wp theme activate astra-child
wp theme list

验证三件事:

  1. 前台样式是否正常(若「裸奔」,多半是 Template 写错或父样式未加载);
  2. 子主题的 style.css 是否真的生效(临时加一条 body { outline: 1px solid red; } 测试);
  3. 后台「外观 → 主题」里子主题是否显示为「活动」,且父主题标记为「父主题」。

第六步:放第一个模板覆盖

比如想改文章页,把父主题的 single.php 复制到子主题同路径再改:

cp wp-content/themes/astra/single.php wp-content/themes/astra-child/single.php

覆盖的具体规则(哪些文件能覆盖、get_template_part 的差异)见 子主题覆盖模板文件规则。

第七步:区块主题(FSE)子主题的特殊写法

若父主题是区块主题(如 Twenty Twenty-Four),子主题结构与经典主题不同:

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "settings": {
    "color": {
      "palette": [
        { "slug": "brand", "color": "#2563eb", "name": "品牌蓝" }
      ]
    }
  },
  "styles": {
    "elements": {
      "link": { "color": { "text": "var(--wp--preset--color--brand)" } }
    }
  }
}

区块子主题的 theme.json 会与父主题合并(子主题的同名设置覆盖父主题),模板则放在 templates/ 与 parts/ 目录下按同名覆盖,不需要 functions.php 加载样式——全局样式由核心自动生成。

常见踩坑

  1. Template 填了主题名而不是目录名:后台提示父主题缺失,子主题无法启用。
  2. 启用后站点无样式:只写了 style.css 没写 functions.php,父主题样式没被引入。
  3. 用 @import 加载父样式:老教程常见写法,@import 会阻塞渲染且无法并行加载,已被官方不推荐。
  4. 子样式覆盖不了父样式:依赖没写,输出顺序反了;或父主题用了更高优先级的选择器,需要提高子主题选择器权重。
  5. 改了子主题样式没生效:浏览器或 CDN 缓存了旧 CSS,版本号未更新。
  6. 案例:某企业站做了子主题,上线第二天首页样式全丢。排查发现 style.css 里 Template: Astra 首字母大写,Windows 本地环境目录不区分大小写所以能用,部署到 Linux 服务器后匹配不到目录,WordPress 判定父主题缺失并回退到默认主题。改成小写 astra 后恢复——这类问题在本地永远测不出来。
  7. 把整个父主题复制进子主题:那就不是子主题了,等于维护两份代码,升级优势全部消失。
  8. 子主题目录名与父主题相同:目录冲突,Template 指向自己,出现循环引用。

总结

子主题的最小可用集合只有两个文件:style.css(含 Template)与 functions.php(加载父样式)。做完后按顺序验证:后台能识别、前台有样式、子主题 CSS 优先级更高。之后每加一个改动,都问自己一句「这个改动放在子主题里能不能实现」——能用钩子实现的绝不覆盖模板,能覆盖模板的绝不改父主题。加载样式的更多细节见 子主题加载父主题样式。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。