WordPress 子主题怎么做:十分钟建完,别改错文件

· wordpress · 阅读 12
摘要

子主题是 WordPress 里投入产出比最高的一个操作。十分钟能建完,之后所有的改动都不会在主题升级时丢掉。 但做错的方式也特别多,我见过把父主题整个拷一份来改的,也见过子主题建完样式加载了两遍的。 最少两个文件 子主题目录放在 wp-c

子主题是 WordPress 里投入产出比最高的一个操作。十分钟能建完,之后所有的改动都不会在主题升级时丢掉。

但做错的方式也特别多,我见过把父主题整个拷一份来改的,也见过子主题建完样式加载了两遍的。

最少两个文件

子主题目录放在 wp-content/themes/my-child/,里面两个文件就够:

style.css

/*
Theme Name: 我的子主题
Template: parent-theme-folder-name
Version: 1.0.0
*/

Template 这一行是关键,填的是父主题的目录名,不是 Theme Name。这俩经常不一样。

比如父主题头部写 Theme Name: Twenty Twenty-Four,目录叫 twentytwentyfour。这里要填 twentytwentyfour。填错的话,后台主题列表里子主题压根不出现。

functions.php

<?php
add_action('wp_enqueue_scripts', function() {
    wp_enqueue_style('parent-style', get_template_directory_uri() . '/style.css');
    wp_enqueue_style('child-style', get_stylesheet_uri(), array('parent-style'));
});

两行 enqueue,父主题一份、子主题一份,依赖关系写清楚。

为什么子主题的样式容易加载不上

这里有个反直觉的地方:WordPress 不会自动加载父主题的 style.css。

子主题激活后,get_stylesheet_uri() 指向的是子主题的 style.css。父主题那份样式——如果父主题自己也是通过 get_stylesheet_uri() 加载的——这时候指向的变成了子主题目录。

结果就是:子主题干干净净,父主题样式全没了。

所以上面那段 functions.php 几乎是必须的。不写,页面会变成一个没有样式的裸 HTML。

我第一次做子主题就撞了这个,当时以为哪儿配错了,折腾一晚上。

子主题能覆盖什么,不能覆盖什么

能覆盖的:

  • 任意模板文件 —— 子主题里放同名文件,优先于父主题
  • CSS —— 放子主题 style.css
  • functions.php 里加函数 —— 但这是追加,不是覆盖

不能覆盖的:

  • 父主题的 functions.php —— 子主题的同名文件是额外加载的,两份都会跑
  • 父主题用 require_once 引入的类 —— 已经定义了,子主题同名函数会直接报错

第二条是个典型陷阱。父主题里定义了 function my_theme_setup(),你在子主题里也定义一个同名函数,站点直接白屏,报「Cannot redeclare」。

正确做法是加 if (!function_exists(...)) 之类的判断,或者干脆换个函数名、用钩子去改行为。

覆盖单个模板的正确姿势

父主题的 header.php 里有一处你不喜欢,想改。

错误做法:把整个 header.php 拷到子主题,改那一处。

后果是父主题升级时给 header.php 打了安全补丁、加了新功能,你的子主题里还是旧版,全被跳过。而且没人会记得这回事。

正确做法视情况分两种:

如果改动很小,优先找钩子。父主题在模板里留了 do_action('before_header') 之类的挂点,就用钩子插内容,完全不碰模板文件。

如果没有钩子,确实得拷文件,那就拷最小的那个。别拷 header.php 这种几百行的,先看看能不能只拷 template-parts/header/nav.php 这种拆出来的小部件。

拷完在文件顶部加一行注释,写上父主题的版本号:

<?php /* 基于父主题 3.2.1 的 header.php 修改 */ ?>

这行注释的唯一作用是给未来的自己留证据。下次父主题升到 4.0,你知道这个文件需要重新比对。

子主题里的 functions.php 加载顺序

父主题的 functions.php 先加载,子主题的后加载。

这个顺序有实际意义:如果父主题用了 add_action('init', ...),子主题可以 remove_action('init', ...) 把它摘掉,再挂一个新的。反过来不行。

所以子主题能干的事比想象中多。父主题默认行为不喜欢,很多时候不用改文件,摘掉钩子重新挂一个就够了。

建完记得做的三件事

  1. 后台「外观 → 主题」里确认子主题出现了,激活它,前台看样式是否正常
  2. 随便改一处 CSS,刷新看是否生效——验证子主题的样式确实在加载
  3. 把父主题的目录名、版本号记进项目文档。父主题升级前,得知道哪些文件被覆盖过

第三条看起来是流程要求,实际上救过我好几次。父主题一次大版本升级把 header.php 重写了,我覆盖的那份还在用旧结构,前台导航栏的间距全乱。查了半小时才想起来是自己拷过。