搜索全站
主题 21 分钟阅读

搭建自己长期维护的WordPress主题基线:从子主题到自有主题

每次建站都从头改一遍主题,效率极低。本文给出一条可复用的演进路线:先用子主题沉淀改动,再抽公共层,最后用 Underscores 或块主题建立自有基线,附目录结构与初始化代码。

U
UFO_PF 2020-06-28 · 阅读 21 分钟
搭建 主题
阅读提示
本文约 8,228 字,预计阅读 21 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:第五个站点,还在重复第一次的工作

接手第五个客户的建站需求时,我发现自己在做和第一个站点完全相同的事:装同一套主题、改同一批 CSS 变量、加同一段 wp_head 清理代码、写同一个产品 CPT。前面四个站点的经验,一点都没沉淀下来——它们分散在四个主题目录里,格式各不相同,复制粘贴时还要逐个改函数名前缀。

问题出在没有「基线」。基线不是某个具体主题,而是一套你自己认可的最小可用起点:目录怎么分、变量怎么命名、哪些功能放主题哪些放插件、版本怎么管理。有了它,新站点只需要做「业务差异化」的部分,重复劳动被压缩到接近零。

对独立开发者和小团队来说,这条路的终点不是做出一个能卖的商业主题,而是做出一个「只有自己需要维护、但足够通用」的内部基线。它的代码量不需要大,关键是结构稳定、边界清晰。

原理分析:三种形态的边界在哪里

WordPress 主题的自定义有三种形态,成本和自由度差异很大:

形态 自由度 维护成本 适合阶段
子主题(Child Theme) 低,只能覆盖父主题有的东西 中,需跟随父主题更新 1–3 个站点,快速交付
起始主题改造(_s / 块主题) 高,一切自己控 中高,无父主题更新负担 3 个站点以上
从零写(style.css + index.php) 最高 高,所有细节自己兜 有特殊架构需求

判断的关键维度是「父主题更新时你要做多少事」。子主题的痛点是模板覆盖——父主题一更新,你复制出去改过的 header.php 就得重新合并(这部分成本怎么量化,可以参考二次开发成本评估的思路)。起始主题则没有这个问题,因为你就是父主题。

另一个必须提前想清楚的边界:什么该放主题,什么该放插件。判断标准很简单——换主题后还需要的,放插件;换主题就不需要的,放主题。按这个标准,CPT 声明、自定义字段定义、短代码、业务相关的钩子都应该进插件;模板、样式、区块样式变体才属于主题。这条边界守住了,将来换主题的代价会小一个数量级。

技术选型上,2026 年的现实是:块主题(theme.json + 区块模板)是 WordPress 官方明确的方向,新项目建议直接上块主题;经典主题 + 子主题仍在大量存量站点上使用,维护类项目沿用即可。

保姆级实操

步骤 1:第一阶段,用子主题沉淀改动

cd wp-content/themes
wp scaffold child-theme mmf-base --parent_theme=twentytwentyfour \
  --theme_name="Mimangfei Base" --author="Mimangfei" --author_uri=https://mimangfei.com/

生成的结构里,style.css 头部必须有 Template: twentytwentyfour 这一行,这是子主题唯一的身份标识。functions.php 里加载父主题样式的方式要用 wp_enqueue_style() 带父主题 handle:

<?php
add_action( 'wp_enqueue_scripts', 'mmf_child_enqueue' );
function mmf_child_enqueue() {
    wp_enqueue_style(
        'parent-style',
        get_template_directory_uri() . '/style.css',
        array(),
        wp_get_theme( 'twentytwentyfour' )->get( 'Version' )
    );
    wp_enqueue_style(
        'child-style',
        get_stylesheet_directory_uri() . '/style.css',
        array( 'parent-style' ),
        wp_get_theme()->get( 'Version' )
    );
}

这个阶段的核心纪律:只覆盖必要的模板文件,其余全用钩子。能写进 functions.php 的改动,就不要复制模板文件出来改。

步骤 2:把通用改动抽成「功能插件」

建一个不属于任何主题的功能插件,承载换主题也要带走的逻辑:

wp-content/plugins/mmf-core/
├── mmf-core.php
├── inc/
│   ├── post-types.php      # CPT 与分类法
│   ├── shortcodes.php      # 短代码兼容层
│   ├── meta.php            # 自定义字段读取函数
│   └── cleanup.php         # 前台资源精简
└── README.md
<?php
/**
 * Plugin Name: MMF Core
 * Description: 站点核心内容模型与通用逻辑,与主题解耦
 * Version: 1.0.0
 */

require_once __DIR__ . '/inc/post-types.php';
require_once __DIR__ . '/inc/shortcodes.php';
require_once __DIR__ . '/inc/meta.php';
require_once __DIR__ . '/inc/cleanup.php';

这样切到任意主题,业务逻辑都不丢。

步骤 3:第二阶段,用起始主题建自有基线

Underscores(_s)是 Automattic 维护的经典主题起始模板,用 WP-CLI 可以直接生成:

cd wp-content/themes
wp scaffold _s mmf-base --theme_name="Mimangfei Base" \
  --author="Mimangfei" --author_uri=https://mimangfei.com/ --activate

生成后按自己的习惯重排目录:

mmf-base/
├── style.css
├── theme.json                 # 块主题用;经典主题删掉
├── functions.php              # 只做 require,不写逻辑
├── inc/
│   ├── setup.php              # add_theme_support 与 register_nav_menus
│   ├── enqueue.php            # 脚本样式
│   ├── template-tags.php      # 模板辅助函数
│   └── blocks.php             # 区块样式变体与模式
├── template-parts/
│   ├── content.php
│   ├── content-product.php
│   └── hero.php
├── patterns/                  # 区块模式(块主题)
├── parts/                     # 模板部件(块主题)
├── templates/                 # 区块模板(块主题)
└── CHANGELOG.md

functions.php 保持极简,只负责装配:

<?php
define( 'MMF_THEME_VERSION', '1.0.0' );

require_once get_template_directory() . '/inc/setup.php';
require_once get_template_directory() . '/inc/enqueue.php';
require_once get_template_directory() . '/inc/template-tags.php';
require_once get_template_directory() . '/inc/blocks.php';

步骤 4:块主题路线,用 theme.json 做唯一配置源

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 2,
  "settings": {
    "appearanceTools": true,
    "layout": { "contentSize": "720px", "wideSize": "1200px" },
    "color": {
      "palette": [
        { "slug": "brand",   "color": "#1a5fd0", "name": "品牌蓝" },
        { "slug": "ink",     "color": "#1c1f23", "name": "正文黑" },
        { "slug": "muted",   "color": "#6b7280", "name": "辅助灰" },
        { "slug": "surface", "color": "#f5f7fa", "name": "浅底" }
      ]
    },
    "typography": {
      "fluid": true,
      "fontSizes": [
        { "slug": "small", "size": "0.875rem", "name": "辅助" },
        { "slug": "body",  "size": "1.0625rem", "name": "正文" },
        { "slug": "large", "size": "1.5rem", "name": "小标题" },
        { "slug": "xl",    "size": "2.25rem", "name": "大标题" }
      ]
    },
    "spacing": { "units": ["px", "rem", "em", "%"] }
  },
  "styles": {
    "typography": { "fontFamily": "system-ui, -apple-system, 'PingFang SC', 'Microsoft YaHei', sans-serif" }
  }
}

把颜色、字号、间距全部声明在这里,编辑器与前台自动同步,后续所有站点的视觉基线就统一了。中文字体栈里带上 PingFang SC 与 Microsoft YaHei 是必须的。

步骤 5:注册区块样式变体与模式,减少重复排版

<?php
add_action( 'init', 'mmf_register_block_patterns' );
function mmf_register_block_patterns() {
    register_block_pattern_category( 'mmf', array(
        'label' => 'MMF 布局',
    ) );

    register_block_pattern( 'mmf/product-card', array(
        'title'       => '产品卡片',
        'categories'  => array( 'mmf' ),
        'description' => '图文产品卡片,含标题、摘要与按钮',
        'content'     => '<!-- wp:group {"className":"mmf-card"} -->
<div class="wp-block-group mmf-card">
<!-- wp:image {"sizeSlug":"large"} /-->
<!-- wp:heading {"level":3} --><h3 class="wp-block-heading">产品名称</h3><!-- /wp:heading -->
<!-- wp:paragraph --><p>一句话介绍产品核心能力。</p><!-- /wp:paragraph -->
<!-- wp:buttons --><div class="wp-block-buttons"><!-- wp:button --><div class="wp-block-button"><a class="wp-block-button__link wp-element-button">查看详情</a></div><!-- /wp:button --></div><!-- /wp:buttons -->
</div>
<!-- /wp:group -->',
    ) );
}

区块模式的 content 是块标记的序列化字符串,从编辑器里复制现成布局再包一层最稳妥,手写容易漏闭合注释。

步骤 6:必备的基线支撑声明

<?php
add_action( 'after_setup_theme', 'mmf_theme_setup' );
function mmf_theme_setup() {
    load_theme_textdomain( 'mmf-base', get_template_directory() . '/languages' );

    add_theme_support( 'title-tag' );
    add_theme_support( 'post-thumbnails' );
    add_theme_support( 'responsive-embeds' );
    add_theme_support( 'html5', array(
        'search-form', 'comment-form', 'comment-list', 'gallery', 'caption', 'style', 'script',
    ) );
    add_theme_support( 'wp-block-styles' );
    add_theme_support( 'editor-styles' );
    add_editor_style( 'assets/css/editor.css' );

    register_nav_menus( array(
        'primary' => '主导航',
        'footer'  => '页脚导航',
    ) );

    add_image_size( 'mmf-card', 480, 320, true );
    add_image_size( 'mmf-wide', 1200, 600, true );
}

这几项缺一会在后续踩坑:没有 title-tag 标题结构失控;没有 responsive-embeds 嵌入视频不自适应;没有 wp-body-open(模板里要调用)很多插件注入失效。

常见踩坑

  1. functions.php 里塞满业务逻辑:几百行堆在一起,后期无法拆分。一开始就按 inc/ 分文件。
  2. 子主题里复制模板文件成瘾:复制越多,父主题更新越痛。能用钩子解决的绝不复制。
  3. get_template_directory() 与 get_stylesheet_directory() 混用:子主题场景下前者指向父主题,后者指向子主题,加载子主题资源必须用后者。
  4. 块主题里同时写 theme.json 和大量自定义 CSS:两处定义颜色会导致编辑器与前台不一致。样式来源要唯一。
  5. 案例: 某团队把 CPT 声明写在自研主题里,三个站点共用同一套代码。后来要给其中一个站点换设计,发现换主题会让 400 多个产品页 404,只能把整套主题复制一份再改,从此维护成本翻倍。教训:CPT 必须在第一版就放进功能插件。
  6. 没有 load_theme_textdomain():后期做多语言或翻译时全部字符串要返工。
  7. 版本号写死在多个文件:应定义 MMF_THEME_VERSION 常量统一引用,发版只改一处。

总结

主题基线的演进路线是:子主题(快速交付,严格控制模板覆盖)→ 功能插件(把换主题也要带走的东西抽出来)→ 起始主题自建基线(去掉父主题依赖)→ 块主题 + theme.json 统一配置源。

三个必须守住的边界:业务逻辑进插件、视觉与模板进主题、版本与变更记录跟代码走(版本号管理规范见 自己维护主题的版本管理与变更记录)。基线建成后,新站点的启动时间能从两三天压到几小时。后续做企业站时,可直接在此基础上按 企业站产品中心CPT搭建教程 扩展业务模块。

U
UFO_PF作者

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

留下你的想法

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