返回博客
技术 2025年3月13日 11 分钟阅读 · 2680 字

WordPress 主题开发入门到进阶

从模板层次到自定义区块,构建专业级 WordPress 主题

#WordPress #主题开发 #PHP #模板
本文由 AI 辅助生成,经人工审核发布

WordPress 主题决定了站点的视觉呈现与交互体验。一个优秀的主题不仅是”好看的皮肤”,更是结构清晰、可维护、可扩展的前端工程。本文将从模板层次结构讲起,逐步覆盖主题开发的核心知识点,帮助你从零构建一个专业级 WordPress 主题。

一、主题的基本结构

一个最小化的主题只需要两个文件:style.cssindex.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.phphome.phpindex.php
文章详情single-{post-type}.phpsingle.phpindex.php
页面custom-template.phppage-{slug}.phppage-{id}.phppage.phpindex.php
分类归档category-{slug}.phpcategory-{id}.phpcategory.phparchive.phpindex.php
标签归档tag-{slug}.phptag.phparchive.phpindex.php
作者页author-{nicename}.phpauthor.phparchive.phpindex.php
搜索结果search.phpindex.php
404404.phpindex.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}.phppost-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.phparchive-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/postsGET获取文章列表
/wp-json/wp/v2/posts/{id}GET获取单篇文章
/wp-json/wp/v2/categoriesGET获取分类列表
/wp-json/wp/v2/pagesGET获取页面列表

示例:在前端用 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 编码规范与安全实践,你的主题才能经得起生产环境的考验。