下面我将从基本结构、常用函数、高级技巧到完整示例,为你详细讲解 WordPress 文章页模板。
WordPress 模板加载机制(如何找到文章页模板)
你需要理解 WordPress 是如何决定使用哪个文件来显示文章的,WordPress 会按照一个特定的优先级顺序来查找模板文件:
-
single-{post_type}.php(最高优先级)- 这是最精确的模板,如果你有一个自定义文章类型(
product),WordPress 会优先查找single-product.php,如果不存在,它会继续往下找。 - 对于默认的“文章”(Post),它会查找
single-post.php,如果这个文件存在,它会直接使用这个文件来显示所有文章。
- 这是最精确的模板,如果你有一个自定义文章类型(
-
single.phpsingle-{post_type}.php不存在,WordPress 就会查找通用的single.php文件,这是最常见、最基础的文章页模板。
-
singular.phpsingle.php也不存在,WordPress 会查找singular.php,这个模板不仅用于文章,也用于页面,是所有“单一”内容(single content)的回退模板。
-
index.php- 如果以上所有文件都不存在,WordPress 就会使用最基础的
index.php来显示内容。
- 如果以上所有文件都不存在,WordPress 就会使用最基础的
要自定义文章页,你只需要在主题根目录下创建一个 single.php 文件(或者 single-post.php)即可。
single.php 的基本结构
一个典型的 single.php 文件结构如下,它包含了 HTML 骨架和 WordPress 的主循环:
<?php
/**
* Template Name: 文章页模板 (可以省略,但加上是个好习惯)
* @package WordPress
* @subpackage Your_Theme_Name
*/
// get_header() 加载主题的 header.php 文件
get_header();
?>
<div id="primary" class="content-area">
<main id="main" class="site-main" role="main">
<?php
// WordPress 主循环
// 如果有文章,则循环显示
if ( have_posts() ) :
// 循环开始
while ( have_posts() ) : the_post();
// 加载文章内容模板部分
// 这是一个最佳实践,将单个文章的HTML结构放在一个单独的文件中
get_template_part( 'template-parts/content', get_post_format() );
// 循环结束
endwhile;
// 文章分页导航(上一篇文章/下一篇文章)
the_post_navigation();
else :
// 如果没有找到文章,加载没有内容的模板
get_template_part( 'template-parts/content', 'none' );
endif;
?>
</main><!-- #main -->
</div><!-- #primary -->
<?php
// get_sidebar() 加载主题的 sidebar.php 文件(如果需要侧边栏)
get_sidebar();
// get_footer() 加载主题的 footer.php 文件
get_footer();
?>
核心函数详解
在 single.php 的主循环中,我们使用了很多函数来获取和显示文章内容,以下是最常用的一些函数:
A. 文章标题和内容
the_title(): 显示文章的标题。the_title( '<h1 class="entry-title">', '</h1>' );// 可以给标题包裹上 HTML 标签和类名,这是最佳实践。
the_permalink(): 显示文章的永久链接(URL)。the_content(): 显示文章的完整内容(在后台编辑器中输入的正文)。the_content( '继续阅读 <span class="meta-nav">→</span>' );// 可以添加“阅读更多”链接的文本。
the_excerpt(): 显示文章的摘要,如果文章设置了摘要,则显示摘要;否则,会自动从内容中截取一部分。get_the_content(): 获取,但不直接显示,它返回一个字符串,你可以对这个字符串进行处理后再输出。
B. 元数据(文章信息)
元数据通常显示在标题下方,包含作者、发布日期、分类、标签等信息。
the_author(): 显示文章作者。the_time( get_option('date_format') ): 显示文章发布时间。get_option('date_format')会获取你在 WordPress 后台设置的时间格式。
the_category(', '): 显示文章所属的分类,多个分类用逗号隔开。the_tags(): 显示文章的标签。edit_post_link(): 显示“编辑”链接,只有登录的管理员才能看到。
显示元数据的最佳实践(通常放在一个 <div class="entry-meta"> 容器里):
<div class="entry-meta">
<?php
printf(
esc_html__( '发表于 %s', 'your-theme-textdomain' ),
'<a href="' . esc_url( get_permalink() ) . '" rel="bookmark">' . get_the_date() . '</a>'
);
?>
<?php
printf(
esc_html__( '作者 %s', 'your-theme-textdomain' ),
'<span class="author vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '">' . get_the_author() . '</a></span>'
);
?>
<?php
/* translators: used between list items, there is a space after the comma */
$categories_list = get_the_category_list( esc_html__( ', ', 'your-theme-textdomain' ) );
if ( $categories_list ) {
printf( /* translators: 1: list of categories. */
'<span class="cat-links">' . esc_html__( '分类: %1$s', 'your-theme-textdomain' ) . '</span>',
$categories_list
); // WPCS: XSS OK.
}
?>
</div>
C. 互动功能
comments_template(): 加载评论模板,这会引入comments.php文件来显示评论列表和评论表单。the_post_navigation(): 显示“上一篇/下一篇”文章的链接。
完整的 single.php 示例
这是一个功能完整、结构清晰的 single.php 示例,你可以直接基于它进行修改。
<?php
/**
* 文章页模板
*
* @package WordPress
* @subpackage Your_Theme_Name
*/
get_header(); ?>
<div id="primary" class="content-area">
<main id="main" class="site-main">
<?php if ( have_posts() ) : ?>
<?php /* 开始主循环 */ ?>
<?php while ( have_posts() ) : the_post(); ?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<!-- 文章标题 -->
<header class="entry-header">
<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
<!-- 文章元数据(发布时间、作者、分类等) -->
<div class="entry-meta">
<?php
your_theme_posted_on();
your_theme_posted_by();
?>
</div><!-- .entry-meta -->
</header><!-- .entry-header -->
<!-- 特色图片 -->
<?php if ( has_post_thumbnail() ) : ?>
<div class="post-thumbnail">
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail( 'large' ); ?>
</a>
</div>
<?php endif; ?>
<!-- 文章内容 -->
<div class="entry-content">
<?php
the_content(
sprintf(
wp_kses(
/* translators: %s: Name of current post. */
__( '继续阅读<span class="screen-reader-text"> "%s"</span>', 'your-theme-textdomain' ),
array(
'span' => array(
'class' => array(),
),
)
),
get_the_title()
)
);
wp_link_pages( array(
'before' => '<div class="page-links">' . esc_html__( '页面:', 'your-theme-textdomain' ),
'after' => '</div>',
) );
?>
</div><!-- .entry-content -->
<!-- 文章底部元数据(标签等) -->
<footer class="entry-footer">
<?php your_theme_entry_footer(); ?>
</footer><!-- .entry-footer -->
</article><!-- #post-<?php the_ID(); ?> -->
<?php // 文章导航 ?>
<?php the_post_navigation( array(
'prev_text' => '<span class="nav-subtitle">' . esc_html__( '上一篇:', 'your-theme-textdomain' ) . '</span> <span class="nav-title">%title</span>',
'next_text' => '<span class="nav-subtitle">' . esc_html__( '下一篇:', 'your-theme-textdomain' ) . '</span> <span class="nav-title">%title</span>',
) ); ?>
<?php // 如果评论是开启的,或者至少有一篇评论,则加载评论模板。 ?>
<?php if ( comments_open() || get_comments_number() ) : ?>
<?php comments_template(); ?>
<?php endif; ?>
<?php endwhile; // 循环结束 ?>
<?php else : // 如果没有文章 ?>
<?php get_template_part( 'template-parts/content', 'none' ); ?>
<?php endif; ?>
</main><!-- #main -->
</div><!-- #primary -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>
注意:上面的示例中用到了 your_theme_posted_on() 和 your_theme_entry_footer() 这两个函数,这些函数通常不会在 single.php 中直接写,而是放在 functions.php 中,以便在多个地方(如归档页)复用。
在 functions.php 中添加这两个函数:
// 在 functions.php 中添加
if ( ! function_exists( 'your_theme_posted_on' ) ) :
/**
* 显示文章的发布时间
*/
function your_theme_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( DATE_W3C ) ),
esc_html( get_the_date() ),
esc_attr( get_the_modified_date( DATE_W3C ) ),
esc_html( get_the_modified_date() )
);
$posted_on = sprintf(
/* translators: %s: post date. */
esc_html_x( '发布于 %s', 'post date', 'your-theme-textdomain' ),
'<a href="' . esc_url( get_permalink() ) . '" rel="bookmark">' . $time_string . '</a>'
);
echo '<span class="posted-on">' . $posted_on . '</span>'; // WPCS: XSS OK.
}
endif;
if ( ! function_exists( 'your_theme_entry_footer' ) ) :
/**
* 显示文章的底部元数据,如分类和标签
*/
function your_theme_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__( ', ', 'your-theme-textdomain' ) );
if ( $categories_list ) {
/* translators: 1: list of categories. */
printf( '<span class="cat-links">' . esc_html__( '分类: %1$s', 'your-theme-textdomain' ) . '</span>', $categories_list ); // WPCS: XSS OK.
}
/* translators: used between list items, there is a space after the comma */
$tags_list = get_the_tag_list( '', esc_html_x( ', ', 'list item separator', 'your-theme-textdomain' ) );
if ( $tags_list ) {
/* translators: 1: list of tags. */
printf( '<span class="tags-links">' . esc_html__( '标签: %1$s', 'your-theme-textdomain' ) . '</span>', $tags_list ); // WPCS: XSS OK.
}
}
if ( ! is_single() && ! post_password_required() && ( comments_open() || get_comments_number() ) ) {
echo '<span class="comments-link">';
comments_popup_link(
esc_html__( '发表评论', 'your-theme-textdomain' ),
esc_html__( '1 条评论', 'your-theme-textdomain' ),
esc_html__( '% 条评论', 'your-theme-textdomain' )
);
echo '</span>';
}
// 编辑文章链接
edit_post_link(
sprintf(
wp_kses(
/* translators: %s: Name of current post. */
__( '编辑 <span class="screen-reader-text">%s</span>', 'your-theme-textdomain' ),
array(
'span' => array(
'class' => array(),
),
)
),
get_the_title()
),
'<span class="edit-link">',
'</span>'
);
}
endif;
高级技巧
A. 使用 get_template_part() 进行模块化开发
正如基本结构中提到的,最佳实践是将单个文章的 HTML 结构(<article> 及其内部)放在一个单独的文件中。
- 在主题目录下创建
template-parts/content.php文件。 - 将
single.php中<article>及其内部的所有代码剪切并粘贴到content.php中。 - 在
single.php的循环中,用get_template_part( 'template-parts/content' );来调用它。
这样做的好处是:
- 代码复用:归档页(
archive.php)也可以使用这个content.php模板来显示文章列表项。 - 结构清晰:
single.php只负责页面的整体布局(header, main, footer),而content.php只负责文章内容的展示,职责分明。
B. 根据文章格式显示不同内容
WordPress 支持文章格式(如“ aside ”、“ gallery ”、“ video ”等),你可以为不同格式的文章创建不同的模板文件,
template-parts/content-aside.php:用于“日志”格式的文章。template-parts/content-gallery.php:用于“图库”格式的文章。template-parts/content.php:默认模板。
然后在 single.php 的循环中使用 get_template_part( 'template-parts/content', get_post_format() );,WordPress 会自动根据文章的格式选择正确的模板文件。
希望这份详细的指南能帮助你完全掌握 WordPress 文章页模板的开发!
