贝博恩创新科技网

Theme Developer 教程,从零开始学吗?

WordPress 主题开发终极指南

这份教程将带你从零开始,构建一个名为 MyAwesomeTheme 的 WordPress 主题,我们将涵盖从基础文件结构到高级功能(如自定义izer、小工具、自定义文章类型)的所有内容。

Theme Developer 教程,从零开始学吗?-图1
(图片来源网络,侵删)

第一部分:准备工作与基础结构

环境准备

在开始之前,请确保你拥有一个本地或线上的 WordPress 开发环境,推荐使用以下工具:

  • 本地服务器环境:
    • XAMPP / WAMP / MAMP: 一键搭建 Apache, MySQL, PHP 环境的经典选择。
    • Local (by Flywheel): 强烈推荐!专为 WordPress 设计,管理多个站点非常方便。
  • 代码编辑器:
    • Visual Studio Code (VS Code): 免费、强大,拥有丰富的 WordPress 插件支持。
    • Sublime Text / Atom: 也是不错的选择。

创建主题文件夹

在你的 WordPress 安装目录下的 wp-content/themes/ 文件夹中,创建一个新的主题文件夹,我们将其命名为 my-awesome-theme

/wp-content/
└── /themes/
    └── /my-awesome-theme/

必需的文件:style.cssindex.php

每个 WordPress 主题至少需要这两个文件。

style.css - 主题的“身份证”

这是 WordPress 识别你的主题的核心文件,它必须在文件顶部包含一个特殊的注释块,称为“主题头标”。

Theme Developer 教程,从零开始学吗?-图2
(图片来源网络,侵删)

my-awesome-theme 文件夹中创建 style.css 文件,并填入以下内容:

/*
Theme Name: My Awesome Theme
Theme URI: https://example.com/my-awesome-theme
Author: Your Name
Author URI: https://example.com
Description: A modern, responsive theme for my blog.
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: myawesome
*/
/* 在这里添加你的 CSS 样式 */
body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    line-height: 1.6;
    margin: 0;
    padding: 0;
    background-color: #f4f4f4;
    color: #333;
}
  • Theme Name: 主题在后台显示的名称。
  • Text Domain: 用于主题的国际化(翻译),非常重要。

index.php - 主题的“骨架”

这是当没有其他更具体的模板文件(如单篇文章页面 single.php)时,WordPress 默认用来显示内容的文件,它只是一个空的占位符。

my-awesome-theme 文件夹中创建 index.php 文件,内容如下:

<?php
// 这行代码是必须的,它告诉 WordPress 这个文件是一个模板
get_header();
?>
<div id="primary" class="content-area">
    <main id="main" class="site-main">
        <?php if ( have_posts() ) : ?>
            <?php if ( is_home() && ! is_front_page() ) : ?>
                <header>
                    <h1 class="page-title screen-reader-text"><?php single_post_title(); ?></h1>
                </header>
            <?php endif; ?>
            <?php
            // 开始循环:遍历并显示每一篇文章
            while ( have_posts() ) : the_post();
                get_template_part( 'template-parts/content', get_post_format() );
            endwhile;
            // 文章分页导航
            the_posts_navigation();
        else :
            // 如果没有找到文章,显示这个内容
            get_template_part( 'template-parts/content', 'none' );
        endif;
        ?>
    </main><!-- #main -->
</div><!-- #primary -->
<?php
get_sidebar();
get_footer();
?>

代码解释:

Theme Developer 教程,从零开始学吗?-图3
(图片来源网络,侵删)
  • get_header(): 加载 header.php 文件(我们稍后会创建)。
  • have_posts(): 检查是否有文章可以显示。
  • while ( have_posts() ) : the_post();: The Loop (主循环),WordPress 的核心,它会为每一篇文章设置数据,让你可以在循环内调用文章信息(如标题、内容)。
  • get_template_part(): 一个强大的函数,用于加载可重用的模板片段,我们这里会创建一个 content.php 文件来显示文章内容。
  • the_posts_navigation(): 显示“上一页”/“下一页”的分页链接。
  • get_template_part( 'template-parts/content', 'none' ): 如果没有文章,加载一个“未找到内容”的模板。
  • get_sidebar(): 加载 sidebar.php 文件。
  • get_footer(): 加载 footer.php 文件。

第二部分:构建模板文件

现在我们来创建上面代码中引用的其他文件。

header.php - 网站头部

创建 header.php 文件,包含网站的 <head> 部分和页眉内容。

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo( 'charset' ); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <?php wp_head(); // 必须保留,用于加载 WordPress 自动添加的CSS、JS等 ?>
</head>
<body <?php body_class(); ?>>
<?php wp_body_open(); // WordPress 5.2+ 推荐使用 ?>
<header id="masthead" class="site-header">
    <div class="site-branding">
        <?php
        if ( has_custom_logo() ) {
            the_custom_logo();
        } else {
            // 如果没有自定义Logo,显示网站标题
            ?>
            <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
            <p class="site-description"><?php bloginfo( 'description' ); ?></p>
            <?php
        }
        ?>
    </div><!-- .site-branding -->
    <nav id="site-navigation" class="main-navigation">
        <?php
        wp_nav_menu( array(
            'theme_location' => 'primary', // 我们稍后会注册这个菜单位置
            'menu_class'     => 'main-menu',
        ) );
        ?>
    </nav><!-- #site-navigation -->
</header><!-- #masthead -->
  • wp_head(): 极其重要! WordPress 和许多插件通过这个钩子来添加 CSS、JavaScript、meta 标签等,没有它,你的网站会出问题。
  • body_class(): 为 <body> 标签添加动态的 CSS 类,例如根据当前页面(首页、文章页、分类页等)添加不同的类,方便样式定制。
  • wp_nav_menu(): 用于显示 WordPress 自定义菜单,我们需要先在 functions.php 中注册菜单位置。

footer.php - 网站页脚

创建 footer.php 文件。

<footer id="colophon" class="site-footer">
    <div class="site-info">
        &copy; <?php echo date('Y'); ?> <?php bloginfo( 'name' ); ?>. All Rights Reserved.
    </div><!-- .site-info -->
</footer><!-- #colophon -->
<?php wp_footer(); // 同样必须保留,用于加载JS等 ?>
</body>
</html>
  • wp_footer(): 和 wp_head() 一样重要,许多脚本(如 jQuery)都在这里加载。

sidebar.php - 侧边栏

创建 sidebar.php 文件。

<aside id="secondary" class="widget-area">
    <?php if ( is_active_sidebar( 'sidebar-1' ) ) : ?>
        <?php dynamic_sidebar( 'sidebar-1' ); ?>
    <?php endif; ?>
</aside><!-- #secondary -->

functions.php - 主题的“大脑”

这是主题中最重要的 PHP 文件之一,它不是一个模板,而是用来声明主题的功能、支持特性、加载脚本和样式等。

创建 functions.php 文件,并添加以下功能:

<?php
/**
 * 主题功能文件
 */
// 1. 启用主题特色图片(文章缩略图)
add_theme_support( 'post-thumbnails' );
// 2. 注册导航菜单
register_nav_menus( array(
    'primary' => '主导航菜单',
    'footer'  => '页脚菜单',
) );
// 3. 注册侧边栏
function myawesome_widgets_init() {
    register_sidebar( array(
        'name'          => '主侧边栏',
        'id'            => 'sidebar-1',
        'description'   => '拖拽小工具到这里。',
        'before_widget' => '<section id="%1$s" class="widget %2$s">',
        'after_widget'  => '</section>',
        'before_title'  => '<h2 class="widget-title">',
        'after_title'   => '</h2>',
    ) );
}
add_action( 'widgets_init', 'myawesome_widgets_init' );
// 4. 加载主题样式表
function myawesome_enqueue_styles() {
    // 加载父主题样式(如果有的话)
    // wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
    // 加载主题主样式表
    wp_enqueue_style( 'myawesome-style', get_stylesheet_uri(), array(), '1.0.0' );
}
add_action( 'wp_enqueue_scripts', 'myawesome_enqueue_styles' );
// 5. 加载主题 JavaScript 文件
function myawesome_enqueue_scripts() {
    // 加载一个自定义的 JS 文件,假设它放在 /js/ 目录下
    wp_enqueue_script( 'myawesome-main-script', get_template_directory_uri() . '/js/main.js', array( 'jquery' ), '1.0.0', true );
    // true 表示脚本加载到页脚
}
add_action( 'wp_enqueue_scripts', 'myawesome_enqueue_scripts' );

template-parts/content.php - 文章内容模板

创建 template-parts 文件夹,然后在其中创建 content.php 文件,这个文件负责在循环中显示单篇文章。

<?php
/**
 * 模板部分:用于显示文章内容的通用模板
 *
 * @package MyAwesomeTheme
 */
?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php
        if ( is_singular() ) :
            the_title( '<h1 class="entry-title">', '</h1>' );
        else :
            the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
        endif;
        if ( 'post' === get_post_type() ) :
            ?>
            <div class="entry-meta">
                <?php
                myawesome_posted_on();
                myawesome_posted_by();
                ?>
            </div><!-- .entry-meta -->
        <?php endif; ?>
    </header><!-- .entry-header -->
    <?php myawesome_post_thumbnail(); ?>
    <div class="entry-content">
        <?php
        the_content( sprintf(
            wp_kses(
                /* translators: %s: Name of current post. Only visible to screen readers */
                __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'myawesome' ),
                array(
                    'span' => array(
                        'class' => array(),
                    ),
                )
            ),
            get_the_title()
        ) );
        wp_link_pages( array(
            'before' => '<div class="page-links">' . __( 'Pages:', 'myawesome' ),
            'after'  => '</div>',
        ) );
        ?>
    </div><!-- .entry-content -->
    <footer class="entry-footer">
        <?php myawesome_entry_footer(); ?>
    </footer><!-- .entry-footer -->
</article><!-- #post-<?php the_ID(); ?> -->

这个文件引用了一些我们还没定义的函数(myawesome_posted_on, myawesome_post_thumbnail 等),我们将在 functions.php 中添加这些辅助函数。


第三部分:高级功能与优化

functions.php 中添加辅助函数

将以下函数添加到你的 functions.php 文件末尾。

// 辅助函数:显示文章发布时间
function myawesome_posted_on() {
    $time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>';
    if ( get_the_time( 'U' ) !== get_the_modified_time( 'U' ) ) {
        $time_string = '<time class="entry-date published" datetime="%1$s">%2$s</time> <time class="updated" datetime="%3$s">%4$s</time>';
    }
    $time_string = sprintf( $time_string,
        esc_attr( get_the_date( 'c' ) ),
        esc_html( get_the_date() ),
        esc_attr( get_the_modified_date( 'c' ) ),
        esc_html( get_the_modified_date() )
    );
    $posted_on = sprintf(
        /* translators: %s: post date. */
        esc_html_x( 'Posted on %s', 'post date', 'myawesome' ),
        '<a href="' . esc_url( get_permalink() ) . '" rel="bookmark">' . $time_string . '</a>'
    );
    echo '<span class="posted-on">' . $posted_on . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
// 辅助函数:显示文章作者
function myawesome_posted_by() {
    $byline = sprintf(
        /* translators: %s: post author. */
        esc_html_x( 'by %s', 'post author', 'myawesome' ),
        '<span class="author vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '">' . esc_html( get_the_author() ) . '</a></span>'
    );
    echo '<span class="byline"> ' . $byline . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
// 辅助函数:显示文章特色图片
function myawesome_post_thumbnail() {
    if ( post_password_required() || is_attachment() || ! has_post_thumbnail() ) {
        return;
    }
    if ( is_singular() ) :
        ?>
        <div class="post-thumbnail">
            <?php the_post_thumbnail(); ?>
        </div><!-- .post-thumbnail -->
    <?php else : ?>
        <a class="post-thumbnail" href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1">
            <?php
            the_post_thumbnail( 'post-thumbnail', array(
                'alt' => the_title_attribute( array(
                    'echo' => false,
                ) ),
            ) );
            ?>
        </a>
    <?php endif; // End is_singular().
}
// 辅助函数:显示文章底部的元信息(分类、标签等)
function myawesome_entry_footer() {
    // 隐藏分类和标签。
    if ( 'post' === get_post_type() ) {
        /* translators: used between list items, there is a space after the comma */
        $categories_list = get_the_category_list( esc_html__( ', ', 'myawesome' ) );
        if ( $categories_list ) {
            /* translators: 1: list of categories. */
            printf( '<span class="cat-links">' . esc_html__( 'Posted in %1$s', 'myawesome' ) . '</span>', $categories_list ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        }
        /* translators: used between list items, there is a space after the comma */
        $tags_list = get_the_tag_list( '', esc_html_x( ', ', 'list item separator', 'myawesome' ) );
        if ( $tags_list ) {
            /* translators: 1: list of tags. */
            printf( '<span class="tags-links">' . esc_html__( 'Tagged %1$s', 'myawesome' ) . '</span>', $tags_list ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        }
    }
    if ( ! is_single() && ! post_password_required() && ( comments_open() || get_comments_number() ) ) {
        echo '<span class="comments-link">';
        comments_popup_link(
            sprintf(
                wp_kses(
                    /* translators: %s: post title. */
                    __( 'Leave a Comment<span class="screen-reader-text"> on %s</span>', 'myawesome' ),
                    array(
                        'span' => array(
                            'class' => array(),
                        ),
                    )
                ),
                get_the_title()
            )
        );
        echo '</span>';
    }
    edit_post_link(
        sprintf(
            wp_kses(
                /* translators: %s: post title. */
                __( 'Edit <span class="screen-reader-text">%s</span>', 'myawesome' ),
                array(
                    'span' => array(
                        'class' => array(),
                    ),
                )
            ),
            get_the_title()
        ),
        '<span class="edit-link">',
        '</span>'
    );
}

创建 php - 页面未找到模板

创建 php 文件,当用户访问一个不存在的页面时显示。

<?php
/**
 * 404模板
 *
 * @package MyAwesomeTheme
 */
get_header();
?>
<div id="primary" class="content-area">
    <main id="main" class="site-main">
        <section class="error-404 not-found">
            <header class="page-header">
                <h1 class="page-title"><?php esc_html_e( 'Oops! That page can&rsquo;t be found.', 'myawesome' ); ?></h1>
            </header><!-- .page-header -->
            <div class="page-content">
                <p><?php esc_html_e( 'It looks like nothing was found at this location. Maybe try one of the links below or a search?', 'myawesome' ); ?></p>
                <?php get_search_form(); ?>
            </div><!-- .page-content -->
        </section><!-- .error-404 -->
    </main><!-- #main -->
</div><!-- #primary -->
<?php
get_footer();

创建 page.php - 页面模板

WordPress 的“页面”(Page,如“关于我们”、“联系方式”)和“文章”(Post)是分开的。page.php 用于显示所有页面。

你可以复制 index.php 的内容,然后稍作修改,我们的主题结构很简单,index.phppage.php 的逻辑几乎一样,所以我们可以让 page.php 直接使用 index.php 的内容。

page.php 中只写一行代码:

<?php
// 页面模板
get_template_part( 'index' );

get_template_part( 'index' ) 会加载 index.php 文件。

创建 single.php - 单篇文章模板

当用户点击一篇文章的标题进入文章详情页时,single.php 会被调用。

创建 single.php 文件,内容如下:

<?php
/**
 * 单篇文章模板
 *
 * @package MyAwesomeTheme
 */
get_header();
?>
<div id="primary" class="content-area">
    <main id="main" class="site-main">
        <?php
        while ( have_posts() ) :
            the_post();
            get_template_part( 'template-parts/content', get_post_format() );
            // 如果启用了评论,则加载评论模板
            if ( comments_open() || get_comments_number() ) :
                comments_template();
            endif;
        endwhile; // End of the loop.
        ?>
    </main><!-- #main -->
</div><!-- #primary -->
<?php
get_sidebar();
get_footer();

这个模板和 index.php 很像,但关键区别在于:

  1. 它不包含 the_posts_navigation(),因为单篇文章没有“上一页/下一页”的分页需求。
  2. 它加载了 comments_template(),以显示文章的评论部分。

第四部分:激活主题与最终步骤

激活主题

  1. 通过 FTP 或文件管理器,将整个 my-awesome-theme 文件夹上传到你的 WordPress 网站的 /wp-content/themes/ 目录下。
  2. 登录你的 WordPress 后台。
  3. 导航到 外观 -> 主题
  4. 你会看到 "My Awesome Theme",点击 “激活” 按钮。

设置菜单

  1. 在后台,导航到 外观 -> 菜单
  2. 创建一个新菜单,主导航”。
  3. 添加你想要的页面(如“首页”、“关于我们”、“联系”)或文章链接到菜单中。
  4. 在菜单设置下,找到 “主题位置”,将你刚创建的菜单分配给 “主导航菜单”
  5. 保存菜单

设置侧边栏小工具

  1. 在后台,导航到 外观 -> 小工具
  2. 你会看到一个名为“主侧边栏”的 widget 区域。
  3. 从左侧可用的小工具列表中,拖拽你想要的小工具(如“分类目录”、“近期文章”、“文本”等)到“主侧边栏”区域。
  4. 保存小工具

添加一些样式

现在你的主题已经可以运行了,但看起来可能很朴素,打开 style.css 文件,在主题头标下方添加一些 CSS 来美化它,为文章、导航、侧边栏添加一些边距、颜色和布局。

进阶学习方向

你已经成功创建了一个基础的 WordPress 主题!接下来可以探索:

  • WordPress Customizer (主题定制器): 使用 add_action('customize_register', ...)functions.php 中添加选项,让用户可以在后台自定义颜色、Logo、标题等。
  • 自定义文章类型: 创建“作品集”、“服务”、“团队”等不同于文章和页面的内容类型。
  • 自定义小工具: 创建你自己的小工具,用于在侧边栏或页脚中显示特定内容。
  • 主题选项页面: 创建一个完整的后台页面来管理主题的设置。
  • 响应式设计: 使用媒体查询让你的网站在各种设备上(手机、平板、桌面)都能良好显示。

推荐资源

祝你开发愉快!

分享:
扫描分享到社交APP
上一篇
下一篇