WordPress 主题开发入门到进阶
从模板层次到自定义区块,构建专业级 WordPress 主题
WordPress 主题决定了站点的视觉呈现与交互体验。一个优秀的主题不仅是”好看的皮肤”,更是结构清晰、可维护、可扩展的前端工程。本文将从模板层次结构讲起,逐步覆盖主题开发的核心知识点,帮助你从零构建一个专业级 WordPress 主题。
一、主题的基本结构
一个最小化的主题只需要两个文件:style.css 和 index.php。但一个规范的主题通常包含以下结构:
my-theme/
├── style.css # 主题元信息与样式
├── functions.php # 主题功能定义
├── index.php # 主模板(兜底)
├── header.php # 头部
├── footer.php # 底部
├── sidebar.php # 侧边栏
├── single.php # 文章详情
├── page.php # 页面详情
├── archive.php # 归档列表
├── search.php # 搜索结果
├── 404.php # 404 页面
├── front-page.php # 首页
├── template-parts/ # 模板片段
│ ├── post-card.php
│ └── pagination.php
├── assets/
│ ├── css/
│ ├── js/
│ └── images/
└── screenshot.png # 主题缩略图(后台展示用)
style.css 顶部必须包含主题元信息:
/*
Theme Name: My Theme
Theme URI: https://example.com/my-theme
Author: Your Name
Description: 一个现代 WordPress 主题
Version: 1.0.0
License: GPL v2 or later
Text Domain: my-theme
*/
二、模板层次结构
WordPress 有一套精确的模板层次(Template Hierarchy):根据当前请求类型,按优先级查找最匹配的模板文件,找不到则向上一级回退,最终回退到 index.php。
核心层次如下(从高到低):
| 请求类型 | 模板文件(优先级从高到低) |
|---|---|
| 首页 | front-page.php → home.php → index.php |
| 文章详情 | single-{post-type}.php → single.php → index.php |
| 页面 | custom-template.php → page-{slug}.php → page-{id}.php → page.php → index.php |
| 分类归档 | category-{slug}.php → category-{id}.php → category.php → archive.php → index.php |
| 标签归档 | tag-{slug}.php → tag.php → archive.php → index.php |
| 作者页 | author-{nicename}.php → author.php → archive.php → index.php |
| 搜索结果 | search.php → index.php |
| 404 | 404.php → index.php |
利用这个层次,可以针对特定分类、特定文章类型创建专用模板,实现精细化展示。
三、functions.php 配置
functions.php 是主题的”控制中心”,用于注册功能、挂载钩子、加载资源。它的行为类似一个小型插件:主题激活时自动加载。
3.1 基础设置
<?php
// functions.php
// 设置内容宽度
if ( ! isset( $content_width ) ) {
$content_width = 1200;
}
// 主题功能支持
function my_theme_setup() {
// 标题标签由 WordPress 自动生成
add_theme_support( 'title-tag' );
// 文章特色图片
add_theme_support( 'post-thumbnails' );
// 自动生成 RSS 链接
add_theme_support( 'automatic-feed-links' );
// HTML5 标记
add_theme_support( 'html5', array( 'search-form', 'comment-form', 'gallery', 'caption' ) );
// 自定义Logo
add_theme_support( 'custom-logo', array(
'height' => 60,
'width' => 240,
'flex-height' => true,
) );
// 注册导航菜单
register_nav_menus( array(
'primary' => __( '主菜单', 'my-theme' ),
'footer' => __( '底部菜单', 'my-theme' ),
) );
}
add_action( 'after_setup_theme', 'my_theme_setup' );
3.2 加载 CSS 与 JavaScript
function my_theme_assets() {
// 主题样式
wp_enqueue_style( 'my-theme-style', get_stylesheet_uri(), array(), '1.0.0' );
// 自定义 CSS
wp_enqueue_style( 'my-theme-main', get_template_directory_uri() . '/assets/css/main.css', array(), '1.0.0' );
// 主脚本
wp_enqueue_script( 'my-theme-main', get_template_directory_uri() . '/assets/js/main.js', array(), '1.0.0', true );
// 传递数据给 JS
wp_localize_script( 'my-theme-main', 'myTheme', array(
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'my_theme_nonce' ),
) );
}
add_action( 'wp_enqueue_scripts', 'my_theme_assets' );
使用 wp_enqueue_script 而不是直接 <script> 标签,可以避免重复加载、管理依赖关系,并自动处理版本缓存。
四、模板片段与循环
4.1 The Loop
WordPress 的核心是循环(The Loop),它遍历当前请求的文章列表:
<?php
// index.php
get_header(); ?>
<main class="content">
<?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="meta">
<?php the_date(); ?> · <?php the_author(); ?>
</div>
<?php if ( has_post_thumbnail() ) : ?>
<a href="<?php the_permalink(); ?>"><?php the_post_thumbnail( 'medium' ); ?></a>
<?php endif; ?>
<div class="excerpt"><?php the_excerpt(); ?></div>
</article>
<?php endwhile; ?>
<?php the_posts_pagination( array( 'mid_size' => 2 ) ); ?>
<?php else : ?>
<p>暂无内容</p>
<?php endif; ?>
</main>
<?php get_sidebar(); ?>
<?php get_footer(); ?>
4.2 模板片段复用
用 get_template_part() 把可复用的片段抽到 template-parts/ 目录:
// 在循环中
while ( have_posts() ) : the_post();
get_template_part( 'template-parts/post-card', get_post_type() );
endwhile;
WordPress 会按优先级查找 post-card-{post-type}.php → post-card.php,方便为不同文章类型定制卡片样式。
五、自定义菜单与侧边栏
5.1 导航菜单
菜单在 functions.php 中注册后(见 3.1),在前端显示:
<?php
wp_nav_menu( array(
'theme_location' => 'primary',
'container' => 'nav',
'container_class' => 'main-nav',
'menu_class' => 'menu',
'depth' => 2,
'fallback_cb' => '__return_empty_string',
) );
?>
5.2 注册侧边栏
function my_theme_widgets() {
register_sidebar( array(
'name' => __( '主侧边栏', 'my-theme' ),
'id' => 'sidebar-1',
'description' => __( '显示在文章与归档页右侧', 'my-theme' ),
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
) );
}
add_action( 'widgets_init', 'my_theme_widgets' );
在模板中显示侧边栏:
<?php if ( is_active_sidebar( 'sidebar-1' ) ) : ?>
<aside class="sidebar">
<?php dynamic_sidebar( 'sidebar-1' ); ?>
</aside>
<?php endif; ?>
六、自定义文章类型
WordPress 默认只有”文章”和”页面”两种内容类型。当需要管理其他类型的内容(如作品集、产品、课程)时,可以注册自定义文章类型(Custom Post Type,CPT)。
function my_theme_register_cpt() {
register_post_type( 'portfolio', array(
'labels' => array(
'name' => '作品',
'singular_name' => '作品',
'add_new_item' => '添加新作品',
'edit_item' => '编辑作品',
),
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-portfolio',
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields' ),
'rewrite' => array( 'slug' => 'works' ),
'show_in_rest' => true, // 启用 Gutenberg 编辑器
) );
// 为作品注册分类法
register_taxonomy( 'portfolio_category', 'portfolio', array(
'labels' => array( 'name' => '作品分类' ),
'hierarchical' => true,
'show_in_rest' => true,
) );
}
add_action( 'init', 'my_theme_register_cpt' );
注册后,后台左侧菜单会出现”作品”入口。记得在 Settings > Permalinks 刷新固定链接规则,否则前端会 404。
为 CPT 创建专属模板:single-portfolio.php、archive-portfolio.php。
七、WP_Query 查询
WP_Query 是 WordPress 的核心查询类,用于按条件检索文章:
// 查询最新 6 篇"作品"类型文章
$query = new WP_Query( array(
'post_type' => 'portfolio',
'posts_per_page' => 6,
'orderby' => 'date',
'order' => 'DESC',
'tax_query' => array(
array(
'taxonomy' => 'portfolio_category',
'field' => 'slug',
'terms' => 'web',
),
),
'meta_query' => array(
array(
'key' => 'featured',
'value' => '1',
'compare' => '=',
),
),
) );
if ( $query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
get_template_part( 'template-parts/portfolio-card' );
endwhile;
wp_reset_postdata(); // 恢复全局 $post
endif;
常用参数对照:
| 参数 | 作用 |
|---|---|
post_type | 文章类型 |
posts_per_page | 每页数量,-1 为全部 |
orderby | 排序字段(date / rand / meta_value 等) |
tax_query | 按分类法过滤 |
meta_query | 按自定义字段过滤 |
date_query | 按日期过滤 |
paged | 分页页码(首页用 get_query_var('paged')) |
注意:自定义查询后务必调用 wp_reset_postdata(),否则后续模板的全局 $post 会被污染。
八、区块编辑器(Gutenberg)适配
WordPress 5.0 起默认使用 Gutenberg 区块编辑器。主题需要声明对宽幅内容与样式的支持。
8.1 基础支持
function my_theme_gutenberg_support() {
// 宽幅对齐
add_theme_support( 'align-wide' );
// 响应式内嵌
add_theme_support( 'responsive-embeds' );
// 编辑器样式
add_theme_support( 'editor-styles' );
add_editor_style( 'assets/css/editor-style.css' );
// 调色板
add_theme_support( 'editor-color-palette', array(
array(
'name' => '主色',
'slug' => 'primary',
'color' => '#2563eb',
),
array(
'name' => '强调色',
'slug' => 'accent',
'color' => '#f59e0b',
),
) );
// 字号预设
add_theme_support( 'editor-font-sizes', array(
array( 'name' => '小', 'slug' => 'small', 'size' => 14 ),
array( 'name' => '中', 'slug' => 'medium', 'size' => 18 ),
array( 'name' => '大', 'slug' => 'large', 'size' => 24 ),
) );
}
add_action( 'after_setup_theme', 'my_theme_gutenberg_support' );
8.2 区块样式变体
可以为内置区块注册额外样式:
function my_theme_block_styles() {
register_block_style( 'core/button', array(
'name' => 'rounded',
'label' => '圆角',
) );
register_block_style( 'core/quote', array(
'name' => 'large-quote',
'label' => '大引用',
) );
}
add_action( 'init', 'my_theme_block_styles' );
用户在编辑器中选中区块时可以切换这些样式,前端需要为对应类名(.is-style-rounded)编写 CSS。
8.3 自定义区块模式(Block Pattern)
Block Pattern 是一组预设的区块组合,用户一键插入即可使用:
function my_theme_register_patterns() {
register_block_pattern(
'my-theme/hero-section',
array(
'title' => '首页 Hero 区块',
'description' => '带标题、描述与按钮的横幅',
'categories' => array( 'hero' ),
'content' => '<!-- wp:group {"align":"full","className":"hero"} -->
<section class="wp-block-group alignfull hero">
<!-- wp:heading {"level":1} -->
<h1>欢迎来到我们的网站</h1>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>用 WordPress 构建专业站点</p>
<!-- /wp:paragraph -->
<!-- wp:buttons -->
<div class="wp-block-buttons"><!-- wp:button -->
<div class="wp-block-button"><a class="wp-block-button__link" href="#">开始使用</a></div>
<!-- /wp:button --></div>
<!-- /wp:buttons -->
</section>
<!-- /wp:group -->',
)
);
}
add_action( 'init', 'my_theme_register_patterns' );
九、REST API 集成
WordPress 自 4.7 起内置 REST API,主题可以利用它构建无刷新交互或 Headless 架构。
9.1 默认端点
| 端点 | 方法 | 作用 |
|---|---|---|
/wp-json/wp/v2/posts | GET | 获取文章列表 |
/wp-json/wp/v2/posts/{id} | GET | 获取单篇文章 |
/wp-json/wp/v2/categories | GET | 获取分类列表 |
/wp-json/wp/v2/pages | GET | 获取页面列表 |
示例:在前端用 JS 加载更多文章:
async function loadMore( page ) {
const res = await fetch( `${myTheme.apiBase}/wp/v2/posts?page=${page}&_embed` );
const posts = await res.json();
posts.forEach( post => {
document.querySelector('.post-list').insertAdjacentHTML(
'beforeend',
`<article><h2>${post.title.rendered}</h2>${post.excerpt.rendered}</article>`
);
});
}
9.2 注册自定义端点
如果主题需要提供特殊数据(如推荐文章、统计数据),可以注册自定义端点:
function my_theme_register_routes() {
register_rest_route( 'my-theme/v1', '/featured', array(
'methods' => 'GET',
'callback' => 'my_theme_get_featured',
'permission_callback' => '__return_true',
) );
}
add_action( 'rest_api_init', 'my_theme_register_routes' );
function my_theme_get_featured( WP_REST_Request $request ) {
$query = new WP_Query( array(
'post_type' => 'portfolio',
'posts_per_page' => 3,
'meta_key' => 'featured',
'meta_value' => '1',
) );
$data = array();
while ( $query->have_posts() ) {
$query->the_post();
$data[] = array(
'id' => get_the_ID(),
'title' => get_the_title(),
'link' => get_permalink(),
'image' => get_the_post_thumbnail_url( null, 'large' ),
);
}
wp_reset_postdata();
return rest_ensure_response( $data );
}
9.3 在 CPT 中暴露自定义字段
默认 REST API 只返回标准字段。要把自定义字段加入响应:
register_post_type( 'portfolio', array(
'show_in_rest' => true,
'rest_base' => 'portfolios',
) );
// 注册字段
register_rest_field( 'portfolio', 'client_name', array(
'get_callback' => function( $post ) {
return get_post_meta( $post['id'], 'client_name', true );
},
'update_callback' => function( $value, $post ) {
update_post_meta( $post->ID, 'client_name', $value );
},
'schema' => array( 'type' => 'string' ),
) );
十、主题最佳实践
| 实践 | 说明 |
|---|---|
| 国际化 | 所有字符串用 __() / _e() 包裹,Text Domain 配套 |
| 数据转义 | 输出时用 esc_html() / esc_attr() / esc_url() 防注入 |
| 隔离逻辑 | 复杂业务逻辑放到插件,主题只负责展示 |
| 子主题 | 提供可扩展性,用 get_template_directory_uri() 区分父子主题 |
| 前端依赖 | 用 wp_enqueue_* 加载资源,不要硬编码 <link> / <script> |
| 性能 | 图片用 srcset、脚本 defer、避免主查询外的冗余查询 |
子主题示例(style.css):
/*
Theme Name: My Child Theme
Template: my-theme
*/
// 子主题 functions.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' ), '1.0.0' );
} );
结语
WordPress 主题开发是一个从”组装模板”到”工程化构建”的过程。本文覆盖的核心要点:
- 模板层次决定请求分发,善用专用模板文件实现差异化展示;
- functions.php 是功能入口,挂载钩子、加载资源、注册功能;
- CPT 与 WP_Query 让 WordPress 不只是博客,可以管理任意结构化内容;
- Gutenberg 适配让主题与现代编辑器无缝协作;
- REST API 打通了 WordPress 与前端框架,为 Headless 架构提供可能。
建议从修改一个已有主题(如 Twenty Twenty-Five)入手,逐步添加自定义功能,比从零开始更高效。遵守 WordPress 编码规范与安全实践,你的主题才能经得起生产环境的考验。