咳咳,各位听众,早上好中午好晚上好!今天咱们来聊聊 WordPress 里面一个挺重要的函数——comments_template()
。这哥们儿负责加载评论模板,让咱们的博客文章能热热闹闹地展示评论,跟用户互动。
咱们不绕弯子,直接开始扒它的源码,看看它到底是怎么运作的。
1. comments_template()
的基本用法
首先,comments_template()
的基本用法很简单,通常放在 single.php
或者类似的模板文件中:
<?php
comments_template();
?>
就这么一行代码,它就能把评论模板加载进来,是不是很神奇?接下来咱们要做的就是揭开这层神秘的面纱。
2. 源码分析:从入口开始
comments_template()
函数定义在 /wp-includes/comment-template.php
文件里。我们打开这个文件,找到 comments_template()
函数的定义:
function comments_template( $template = '', $separate_comments = false ) {
global $wp_query, $withcomments, $post, $wpdb, $id, $comment, $user_login, $user_identity, $overridden_cpage;
if ( ! ( is_singular() && ( have_comments() || 'open' == $post->comment_status ) ) ) {
return;
}
$req = get_option( 'require_name_email' );
if ( in_array( $wp_query->query_vars['pagename'], get_option( 'close_comments_on_old_posts' ) ) && is_singular() ) {
$closed = true;
} else {
$closed = false;
}
$default_comments_page = get_option( 'default_comments_page' );
if ( get_query_var( 'cpage' ) ) {
$cpage = get_query_var( 'cpage' );
} elseif ( 'oldest' === $default_comments_page ) {
$cpage = 1;
} else {
$cpage = $wp_query->max_num_comment_pages;
}
$overridden_cpage = $cpage;
if ( ! defined( 'COMMENTS_TEMPLATE' ) ) {
define( 'COMMENTS_TEMPLATE', true );
}
$include = apply_filters( 'comments_template', './comments.php', $template, $separate_comments );
if ( empty( $include ) ) {
return;
}
if ( ! locate_template( array( $include ), true, false ) ) {
// just in case, load it directly if it is in the same
// directory and readable.
if ( ! is_readable( ABSPATH . WPINC . '/theme-compat/comments.php' ) ) {
return;
}
require( ABSPATH . WPINC . '/theme-compat/comments.php' );
}
}
看起来有点长,别怕,咱们一步一步来。
2.1 前置条件检查
if ( ! ( is_singular() && ( have_comments() || 'open' == $post->comment_status ) ) ) {
return;
}
这段代码是第一个检查点。它确保了以下几点:
is_singular()
: 当前页面是一个文章、页面或者自定义文章类型页面。 如果不是单页面,那就不需要加载评论了嘛。have_comments() || 'open' == $post->comment_status
: 要么已经有评论了,要么文章的评论状态是开放的。 如果既没有评论,也不允许评论,那也没必要加载评论模板。
如果这两个条件都不满足,函数就直接 return
了,啥也不干。
2.2 获取配置信息
$req = get_option( 'require_name_email' );
if ( in_array( $wp_query->query_vars['pagename'], get_option( 'close_comments_on_old_posts' ) ) && is_singular() ) {
$closed = true;
} else {
$closed = false;
}
$default_comments_page = get_option( 'default_comments_page' );
这里获取了一些配置信息:
require_name_email
: 是否要求评论者填写姓名和邮箱。 这个配置在后续模板中会用到。close_comments_on_old_posts
: 是否在旧文章上关闭评论。 如果当前文章属于这个配置里的,$closed
就会被设置为true
。default_comments_page
: 默认评论显示方式(最新在前还是最老在前)。
这些配置信息会在评论模板中使用,控制评论的显示和行为。
2.3 处理分页
if ( get_query_var( 'cpage' ) ) {
$cpage = get_query_var( 'cpage' );
} elseif ( 'oldest' === $default_comments_page ) {
$cpage = 1;
} else {
$cpage = $wp_query->max_num_comment_pages;
}
$overridden_cpage = $cpage;
这段代码处理评论的分页。
get_query_var( 'cpage' )
: 尝试从 URL 中获取cpage
参数,这个参数表示当前评论页码。- 如果没有
cpage
参数,就根据default_comments_page
的值来决定$cpage
的值。 如果是 "oldest",就设置为 1,否则设置为最大评论页码。 $overridden_cpage
变量用来保存当前的评论页码。
2.4 定义常量
if ( ! defined( 'COMMENTS_TEMPLATE' ) ) {
define( 'COMMENTS_TEMPLATE', true );
}
这行代码定义了一个常量 COMMENTS_TEMPLATE
,防止评论模板被多次加载。
2.5 关键步骤:寻找评论模板
$include = apply_filters( 'comments_template', './comments.php', $template, $separate_comments );
if ( empty( $include ) ) {
return;
}
if ( ! locate_template( array( $include ), true, false ) ) {
// just in case, load it directly if it is in the same
// directory and readable.
if ( ! is_readable( ABSPATH . WPINC . '/theme-compat/comments.php' ) ) {
return;
}
require( ABSPATH . WPINC . '/theme-compat/comments.php' );
}
这部分代码是整个函数的核心。
-
apply_filters( 'comments_template', './comments.php', $template, $separate_comments )
: 这是一个过滤器钩子。 允许开发者通过comments_template
过滤器来修改默认的评论模板路径。 默认情况下,$include
的值是./comments.php
,表示在当前主题目录下寻找comments.php
文件。$template
和$separate_comments
是传递给过滤器的参数,开发者可以根据这些参数来动态地选择评论模板。 -
locate_template( array( $include ), true, false )
: 这个函数是 WordPress 查找模板文件的关键。 它会在以下路径中查找comments.php
文件:- 当前主题目录
- 父主题目录 (如果存在)
true
参数表示如果找到模板文件,就直接加载它。false
参数表示不返回模板文件的路径,而是直接加载。 -
如果
locate_template()
找不到comments.php
文件,就尝试加载 WordPress 默认的评论模板/wp-includes/theme-compat/comments.php
。 这是一个备用方案,确保即使主题没有提供评论模板,也能显示评论。
3. locate_template()
函数的深入分析
locate_template()
函数定义在 /wp-includes/template.php
文件中。 让我们看看它的源码:
function locate_template( $template_names, $load = false, $require_once = true ) {
$located = false;
foreach ( (array) $template_names as $template_name ) {
if ( ! $template_name ) {
continue;
}
if ( file_exists( STYLESHEETPATH . '/' . $template_name ) ) {
$located = STYLESHEETPATH . '/' . $template_name;
break;
} elseif ( file_exists( TEMPLATEPATH . '/' . $template_name ) ) {
$located = TEMPLATEPATH . '/' . $template_name;
break;
} elseif ( file_exists( ABSPATH . WPINC . '/theme-compat/' . $template_name ) ) {
$located = ABSPATH . WPINC . '/theme-compat/' . $template_name;
break;
}
}
if ( ( $load ) && '' != $located ) {
load_template( $located, $require_once );
}
return $located;
}
这个函数接收一个模板名称数组 $template_names
,然后依次在以下路径中查找模板文件:
- 当前主题目录 (STYLESHEETPATH): 这是首选路径。 如果当前主题提供了模板文件,就优先使用它。
- 父主题目录 (TEMPLATEPATH): 如果当前主题没有提供模板文件,就尝试在父主题中查找。 这允许子主题继承父主题的模板。
- WordPress 默认模板目录 (ABSPATH . WPINC . ‘/theme-compat/’): 如果当前主题和父主题都没有提供模板文件,就使用 WordPress 默认的模板。
如果找到模板文件,$located
变量就会被设置为模板文件的路径,并且循环会 break
。
如果 $load
参数为 true
,load_template()
函数就会被调用,加载模板文件。 $require_once
参数控制是否使用 require_once
加载模板文件。
最后,函数返回 $located
变量,表示找到的模板文件的路径。
4. load_template()
函数的简单介绍
load_template()
函数定义在 /wp-includes/template.php
文件中。 它的作用很简单,就是加载模板文件。
function load_template( $_template_file, $require_once = true, $args = array() ) {
global $posts, $post, $wp_did_template_redirect, $wp_query, $wp_rewrite, $wpdb, $wp_locale, $wp_admin_bar;
if ( is_array( $args ) ) {
extract( $args, EXTR_SKIP );
}
if ( $require_once ) {
require_once( $_template_file );
} else {
require( $_template_file );
}
}
这个函数接收一个模板文件路径 $_template_file
和一个 require_once
参数。
extract( $args, EXTR_SKIP )
: 如果$args
参数是一个数组,它会将数组中的键值对提取为变量,方便在模板中使用。EXTR_SKIP
表示如果变量已经存在,就跳过。require_once( $_template_file )
或require( $_template_file )
: 根据$require_once
参数的值,使用require_once
或require
加载模板文件。require_once
确保模板文件只被加载一次,防止重复定义。
5. 评论模板文件 (comments.php) 的内容
现在我们知道了 comments_template()
函数是如何加载评论模板的,接下来让我们看看评论模板文件 (通常是 comments.php
) 的内容。
comments.php
文件通常包含以下几个部分:
- 评论表单: 允许用户提交评论。
- 评论列表: 显示已有的评论。
- 一些辅助函数和逻辑: 例如,检查是否允许评论,显示评论分页等等。
一个简单的 comments.php
文件可能看起来像这样:
<?php
/**
* The template for displaying comments
*
* This is the template that displays the area of the page that contains both the current comments
* and the comment form.
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*
* @package WordPress
* @subpackage Twenty_Twenty_One
* @since Twenty Twenty-One 1.0
*/
/*
* If the current post is protected by a password and
* the visitor has not yet entered the password we will
* return early without loading the comments.
*/
if ( post_password_required() ) {
return;
}
?>
<div id="comments" class="comments-area default-max-width <?php echo get_option( 'show_avatars' ) ? 'show-avatars' : ''; ?>">
<?php
if ( have_comments() ) :
?>
<h2 class="comments-title">
<?php
$comments_number = get_comments_number();
if ( '1' === $comments_number ) {
/* translators: %s: Post title. */
printf( esc_html__( 'One thought on “%s”', 'twentytwentyone' ), esc_html( get_the_title() ) );
} else {
printf(
/* translators: 1: Number of comments, 2: Post title. */
esc_html( _nx(
'%1$s thought on “%2$s”',
'%1$s thoughts on “%2$s”',
$comments_number,
'comments title',
'twentytwentyone'
) ),
esc_html( number_format_i18n( $comments_number ) ),
esc_html( get_the_title() )
);
}
?>
</h2><!-- .comments-title -->
<?php the_comments_navigation(); ?>
<ol class="comment-list">
<?php
wp_list_comments(
array(
'style' => 'ol',
'short_ping' => true,
'avatar_size' => 42,
)
);
?>
</ol><!-- .comment-list -->
<?php the_comments_navigation(); ?>
<?php
// If comments are closed and there are comments, let's leave a little note, shall we?
if ( ! comments_open() ) :
?>
<p class="no-comments"><?php esc_html_e( 'Comments are closed.', 'twentytwentyone' ); ?></p>
<?php
endif;
endif; // Check for have_comments().
?>
<?php comment_form(); ?>
</div><!-- #comments -->
这个例子使用了 wp_list_comments()
函数来显示评论列表,comment_form()
函数来显示评论表单。 这些函数都是 WordPress 提供的,可以方便地在评论模板中使用。
6. 重要函数总结
为了方便大家理解,我们把上面提到的重要函数总结一下:
函数名 | 作用 |
---|---|
comments_template() |
加载评论模板。 它会检查当前页面是否允许评论,然后根据配置信息和主题文件,找到合适的评论模板文件并加载它。 |
locate_template() |
查找模板文件。 它会在当前主题目录、父主题目录和 WordPress 默认模板目录中查找指定的模板文件。 |
load_template() |
加载模板文件。 它会使用 require_once 或 require 加载指定的模板文件,并且可以将一个数组提取为变量,方便在模板中使用。 |
wp_list_comments() |
显示评论列表。 它会根据传入的参数,格式化评论列表的显示方式,例如,显示头像、分页等等。 |
comment_form() |
显示评论表单。 它会根据配置信息,生成一个评论表单,允许用户提交评论。 |
7. 自定义评论模板
理解了 comments_template()
函数的运作方式,我们就可以自定义评论模板了。
- 创建一个
comments.php
文件: 在你的主题目录下创建一个comments.php
文件。 - 修改
comments.php
文件: 在comments.php
文件中,你可以使用 HTML、CSS 和 PHP 代码来定制评论的显示方式和行为。 你可以使用wp_list_comments()
函数来显示评论列表,comment_form()
函数来显示评论表单。 -
使用过滤器钩子: 你可以使用
comments_template
过滤器钩子来修改默认的评论模板路径。 例如,你可以创建一个名为comments-custom.php
的评论模板,然后使用以下代码来加载它:add_filter( 'comments_template', 'my_custom_comments_template' ); function my_custom_comments_template( $template ) { return dirname( __FILE__ ) . '/comments-custom.php'; }
这段代码会将默认的评论模板路径修改为
comments-custom.php
。
8. 总结
comments_template()
函数是 WordPress 中一个非常重要的函数,它负责加载评论模板,让咱们的博客文章能热热闹闹地展示评论,跟用户互动。 通过深入分析它的源码,我们了解了它的运作方式,以及如何自定义评论模板。 希望今天的讲座能帮助大家更好地理解 WordPress 的模板机制。
好了,今天的讲座就到这里。 谢谢大家! 有什么问题,欢迎提问。