本文约 5,183 字,预计阅读 13 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:解压主题包后,二十多个 php 文件看不懂
下载一个主题解压开,根目录躺着 index.php、functions.php、header.php、footer.php、single.php、page.php、archive.php、404.php、comments.php、searchform.php,还有 inc/、template-parts/、assets/ 三个目录。想改首页 Banner 却不知道该动哪个文件,于是每个都打开看一遍,最后在 header.php 里改了半天,发现首页用的其实是 front-page.php。
理解文件结构不是为了背目录,而是为了知道”改一个地方应该去哪个文件”,以及”新建的文件 WordPress 认不认”。
原理分析:三类文件,三种身份
主题目录里的文件按身份可以分成三类:
| 类型 | 文件 | 作用 |
|---|---|---|
| 必需文件 | style.css、index.php |
缺一个后台就识别不出主题 |
| 功能文件 | functions.php、screenshot.png、rtl.css |
由 WordPress 按约定名自动加载 |
| 模板文件 | single.php、page.php、archive.php 等 |
由模板层级按请求类型挑选 |
style.css 的头部注释是主题的”身份证”,WP_Theme 类靠它识别主题:
/*
Theme Name: 迷忙飞基础主题
Theme URI: https://mimangfei.com
Author: mimangfei
Author URI: https://mimangfei.com
Description: 一个用于演示主题结构的极简主题
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: mimangfei-basic
Tags: blog, one-column, custom-logo
*/
子主题与父主题的区别就在这段注释里:多一行 Template: 父主题目录名。functions.php 则是主题唯一的”自动加载入口”,它在 WordPress 初始化早期被包含进来,主题所有的 add_theme_support、菜单注册、脚本加载都写在这里。
模板文件之间不是孤立的,它们通过一套”包含函数”拼装成完整页面:
// 典型 single.php 的骨架
get_header(); // 引入 header.php
?>
<main id="primary" class="site-main">
<?php
while ( have_posts() ) :
the_post();
get_template_part( 'template-parts/content', 'single' ); // 引入 content-single.php
the_post_navigation();
if ( comments_open() || get_comments_number() ) {
comments_template(); // 引入 comments.php
}
endwhile;
?>
</main>
<?php
get_sidebar(); // 引入 sidebar.php
get_footer(); // 引入 footer.php
保姆级实操
第 1 步:搭一个最小可运行主题
只有两个文件也能成为一个主题。新建 wp-content/themes/mmf-basic/style.css(写入上面的头部注释)和 index.php:
<?php
/**
* 兜底模板:所有请求最终都会落到这里
*/
get_header();
?>
<main id="primary" class="site-main">
<?php if ( have_posts() ) : ?>
<?php while ( have_posts() ) : the_post(); ?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<div class="entry-summary"><?php the_excerpt(); ?></div>
</article>
<?php endwhile; ?>
<?php the_posts_pagination(); ?>
<?php else : ?>
<p><?php esc_html_e( '还没有发布任何内容。', 'mimangfei-basic' ); ?></p>
<?php endif; ?>
</main>
<?php
get_footer();
再到后台启用它。能显示文章列表,说明结构理解到位了。
第 2 步:补齐通用零件
按需新建,不必一次做全:
| 文件 | 何时需要 | 调用方式 |
|---|---|---|
header.php |
几乎必须 | get_header() |
footer.php |
几乎必须 | get_footer() |
sidebar.php |
有侧边栏 | get_sidebar(),可传参调用 sidebar-shop.php |
searchform.php |
覆盖默认搜索框 | get_search_form() |
comments.php |
需要评论区 | comments_template() |
404.php |
自定义 404 | 自动匹配 |
front-page.php |
静态首页专用布局 | 自动匹配,优先级最高 |
带后缀的变体用参数调用是这套结构的通用约定:get_header( 'shop' ) 会去找 header-shop.php,找不到再退回 header.php。这条规则对 get_footer()、get_sidebar()、get_template_part() 都成立。
第 3 步:按内容类型拆分列表与详情
index.php 兜底(必须有)
├── home.php 文章列表首页
├── front-page.php 静态首页(优先级高于 home.php)
├── single.php 文章详情
│ └── single-{post_type}.php 自定义类型详情
├── page.php 页面
│ └── page-{slug}.php 指定别名页面
├── archive.php 归档兜底
│ ├── category.php / category-{slug}.php
│ ├── tag.php / tag-{slug}.php
│ ├── author.php
│ ├── date.php
│ └── archive-{post_type}.php
├── search.php 搜索结果
├── attachment.php 附件页
└── 404.php
具体匹配规则见WordPress 模板层级图解,这里只需记住一条:index.php 是最后兜底,缺了它主题不可用。
第 4 步:把可复用片段放进 template-parts/
template-parts/ 不是 WordPress 的硬性约定,而是官方主题(Twenty 系列)带起来的行业惯例。把文章卡片、分页、面包屑这类片段拆进去,再用 get_template_part() 引入,比在每个模板里复制粘贴好维护。
第 5 步:给目录加说明文件与预览图
mmf-basic/
├── style.css 主题身份证 + 主样式
├── functions.php 功能注册入口
├── index.php 兜底模板
├── rtl.css 从右向左语言补充样式(可选)
├── screenshot.png 主题缩略图,建议 1200×900
├── readme.txt 面向 wordpress.org 的说明
├── assets/ css / js / images
├── inc/ 辅助函数(自定义器、区块等)
├── template-parts/ 可复用模板片段
└── page-templates/ 自定义页面模板
screenshot.png 建议 1200×900 像素,太大会拖慢后台主题页加载。子目录一层足够,不要把 inc/ 再套三层——找文件的时间成本比”结构优雅”重要。
常见踩坑
- 缺
index.php。 后台主题列表里直接不显示,或提示The theme is missing the index.php file。 style.css头部注释格式写错。 少了*/、用了中文冒号、头部前面有多余空行,都会导致WP_Theme解析失败,主题显示为无名。- 目录名带中文或空格。
我的主题/在部分主机上会让get_template_directory_uri()生成的 URL 出现编码问题,一律用小写英文加连字符。 - 把业务逻辑全塞进
functions.php。 换主题就全没了。帖子类型、短代码这类应放插件,划分原则见functions.php 与插件职责划分。 header.php末尾忘了wp_head()。 插件的样式、统计代码、SEO 标签全部注入失败。- 案例: 某学员新建
single-product.php想改产品详情页,改完前台毫无变化。排查发现他装的是子目录里的主题,文件被放到了wp-content/themes/child/single-product.php之外的wp-content/根目录。更隐蔽的一类情况是文件放对了但文件名大小写不符——Linux 服务器上Single-Product.php与single-product.php是两个文件,模板层级查的是小写。 - 在
style.css里@import一堆子样式。 每个@import都是一次串行请求,应改到functions.php里用wp_enqueue_style()并行加载。
总结
记住三条就够:一、style.css + index.php 是主题存在的最低条件,前者提供身份信息,后者提供兜底;二、functions.php 是唯一的自动加载入口,只放与外观相关的注册逻辑;三、其余 php 文件都是模板零件,通过 get_header() / get_template_part() 这类包含函数拼装,命名规则统一为 {基础名}-{变体}.php,找不到变体就退回基础名。按这三条理一遍任何主题,都能在五分钟内定位到该改的文件。
