WordPress 常用函数:模板调用与函数手册用法
模板里该写 the_title() 还是 get_the_title(),这个问题几乎每周都会冒出来。一句话答案:the_ 开头的是直接输出,get_ 开头的是返回字符串。前者不返回值,后者不输出。搞混的结果通常很直观——标题跑到页面最顶上、或者链接里显示一片空白。
一、the_ 与 get_ 的分水岭
| 函数 | 行为 | 返回值 | 典型用法 |
|---|---|---|---|
| the_title() | 直接 echo 到当前位置 | 无 | 循环内输出标题 |
| get_the_title() | 返回字符串 | string | 拼接、比较、塞进变量 |
| the_content() | 输出并执行 the_content 过滤器 | 无 | 正文区 |
| get_the_content() | 返回原始内容,不跑过滤器 | string | 二次处理、截取摘要 |
| get_permalink() | 返回永久链接 | string | 拼 href 属性 |
最关键的一行差别在 the_content() 和 get_the_content():前者会执行 the_content 过滤器,短代码、自动段落、图片懒加载、插件插入的广告都会生效;后者拿到的是数据库里的原始字符串,短代码会原样显示成 这样的文本。要用后者又想让短代码生效,得手动补一句 echo apply_filters( 'the_content', get_the_content() );,但这等于绕了一圈,不如直接用前者。
二、五个高频函数的具体差别
the_title() 的三个参数
签名是 the_title( $before, $after, $display )。第三个参数传 false 时它就不输出了,转而返回字符串,等价于 get_the_title()。所以在循环外想拿标题又不想自己拼 echo,可以直接 the_title( '', '', false )。
在循环外调用必须显式传 post ID:the_title( '<h2>', '</h2>', true, 128 )。不传的话它读的是全局 $post,很容易输出成上一篇文章的标题,这种「标题对不上内容」的问题在自定义循环里特别常见。
the_content() 只能在循环内用
它依赖全局 $post。在循环外想输出某篇文章正文,必须先用 setup_postdata(),用完再 wp_reset_postdata()。少了重置这一步,后面的查询会拿到错乱的全局变量,表现为侧边栏显示成当前文章的信息。
get_permalink() 与 get_the_ID()
get_permalink() 接受文章 ID 或 WP_Post 对象,不传参数就用当前文章。注意分类和标签不能用它,得用 get_term_link();作者页用 get_author_posts_url()。用错函数不会报错,只会返回一个 404 链接,这种问题靠肉眼几乎看不出来。
get_the_ID() 返回当前循环里的文章 ID,循环外返回 false。它最常见的用途是给 get_post_meta()、get_the_post_thumbnail() 传参。
WP_Query:自己写循环
先补一个容易被忽略的细节:WP_Query 的 category_name 参数用的是别名(slug),不是分类名;cat 参数才是分类 ID。想按多个分类取交集,用 category__in 传 ID 数组;想按自定义字段筛,用 meta_query。参数写错时它不会报错,只会安静地返回空列表,所以第一次写完循环先 var_dump( $q->request ); 看一眼实际执行的 SQL,比反复改参数快。
$q = new WP_Query( array(
'post_type' => 'post',
'posts_per_page' => 6,
'category_name' => 'jishuziliao',
'meta_key' => '_thumbnail_id',
'orderby' => 'date',
'order' => 'DESC',
'no_found_rows' => true,
) );
if ( $q->have_posts() ) {
while ( $q->have_posts() ) {
$q->the_post();
echo '<h3><a href="' . esc_url( get_permalink() ) . '">'
. esc_html( get_the_title() ) . '</a></h3>';
}
wp_reset_postdata();
} else {
echo '<p>暂无内容</p>';
}
no_found_rows 设为 true 会跳过 SQL 里的 SQL_CALC_FOUND_ROWS,不需要分页时能省一次全表统计。不要用 query_posts(),它会覆盖主查询,导致分页错乱、条件判断失效,是主题里最该删掉的函数之一。
三、函数写在模板的哪个位置
| 文件 | 必须调用的函数 | 漏掉会怎样 |
|---|---|---|
| header.php | wp_head()、body_class()、language_attributes() | 插件样式与脚本全部丢失,SEO 插件的 meta 不输出 |
| footer.php | wp_footer()、wp_body_open() | 统计代码、部分弹窗、后台工具栏不显示 |
| single.php | the_content()、wp_link_pages() | 正文空白或分页文章只显示第一页 |
| functions.php | register_nav_menus()、add_theme_support() | 后台「外观 → 菜单」报错或缩略图无法设置 |
| sidebar.php | dynamic_sidebar()、is_active_sidebar() | 小工具区显示为空 |
wp_head() 和 wp_footer() 是最容易被新手删掉的两个调用。主题作者觉得「head 里东西太多」直接删掉,结果就是插件全部失效,然后开始怀疑插件有 bug。这两个函数不是可选项。
另一组常被写错的函数是模板引入:get_header()、get_footer()、get_sidebar()、get_template_part()。它们全都是「直接引入并输出」,不是返回路径。想要更细的控制,用 get_template_part( 'template-parts/card', get_post_type() ),它会依次找 card-post.php、card.php 再回落到父主题,是子主题做局部改版最省事的路子。这里传的是相对主题根目录的路径,不要带 .php 后缀。
四、条件判断:先判断再输出
常用的一共就那几个:is_single() 判断单篇文章(自定义文章类型的单页也返回 true),is_page() 判断页面,is_category() 判断分类归档,is_archive() 覆盖所有归档,is_front_page() 和 is_home() 则分别对应「首页设置的静态页」和「文章列表页」,两个都返回 true 的情况只在首页设为最新文章时出现。
if ( is_single() && in_category( 'jishuziliao' ) ) {
echo '<p class="x-note">本文由信科网络技术团队整理。</p>';
} elseif ( is_page( 'contact' ) ) {
echo '<p>工作时间 9:00 - 18:00。</p>';
} elseif ( is_category( 'wordpress' ) ) {
the_archive_description( '<div>', '</div>' );
}
一个必须记住的时机问题:这些条件函数依赖主查询,在 init 或 functions.php 顶层直接调用会返回 false,正确的位置是挂在 wp 或 template_redirect 之后。把判断写进 wp_head 回调里也是安全的。
条件判断写得多了会变成层层嵌套,这时候换成 get_queried_object() 往往更干净:它直接返回当前请求对应的对象,可能是 WP_Post、WP_Term 或 WP_User,用 instanceof 判断类型再做分支,比堆七八个 is_* 可读性高得多。
五、查函数手册的方法
官方手册在 developer.wordpress.org/reference/functions/,直接拼函数名就能到页面。看四块内容就够:Parameters 里每个参数的类型和默认值、Return 的返回类型、Source 里指向的源文件行号、User Contributed Notes 里的实际坑。
- 参数顺序记不住时看签名,不要凭印象写,PHP 不会因为参数顺序错了就报错。
- 函数带不带
_e()后缀决定是否输出,带esc_前缀的是转义版本。 - 不确定某个函数是否存在,
function_exists()包一层再调用,兼容性更稳。 - 本地源码在
wp-includes/post-template.php、general-template.php里,直接搜function the_title比翻文档快。
调试时用 WP-CLI 直接打印返回值,比写 var_dump 到模板里干净得多:
另外注意手册页顶部的版本标注。看到 @deprecated 就不要再用,比如 the_permalink() 本身没废弃但同类的 get_bloginfo( 'url' ) 已经建议换成 home_url()。函数参数里写「Since 5.5.0」的,说明老版本没有这个参数,主题要兼容多版本时得先判断 get_bloginfo( 'version' ) 或直接用 function_exists() 兜一层。
wp eval 'var_dump( get_permalink( 12 ) );'
wp eval 'print_r( get_post_meta( 12 ) );'
六、子主题里怎么「覆盖」函数
首先要明确一点:PHP 函数不能重定义。在子主题里再写一个同名函数,页面直接白屏并报 Fatal error: Cannot redeclare the_title()。可行的做法只有三种:
- 可插拔函数。WordPress 里少数核心函数用
if ( ! function_exists() )包着,比如wp_mail()、get_option(),这类可以在插件里先定义。数量有限,不能指望。 - 用过滤器改输出。这是常规做法,改标题、摘要、正文都走这条路。
- 覆盖模板文件。把父主题的
single.php复制到子主题同名路径,模板里的标签函数调用自然就变了。
// 子主题 functions.php:给循环内的标题追加站点名
add_filter( 'the_title', function ( $title, $id ) {
if ( is_admin() || ! in_the_loop() || ! is_main_query() ) {
return $title;
}
return $title . ' | 信科网络';
}, 10, 2 );
这个回调里的三个判断缺一不可:is_admin() 防止后台列表被改乱,in_the_loop() 防止菜单和面包屑被污染,is_main_query() 防止侧边栏的推荐位标题被追加后缀。少一个就会出现「后台文章列表标题全变了」这类问题。
七、几个反复出现的坑
- 在
header.php里直接写the_title(),结果输出的是第一篇文章的标题。改成wp_title()的替代方案add_theme_support( 'title-tag' )。 - 用
get_the_excerpt()拿不到内容,因为它在循环外返回空字符串,需要传 post ID。 - 自定义循环结束忘了
wp_reset_postdata(),导致分页和面包屑全乱。 - 把
the_permalink()塞进href,结果链接出现在页面上方,页面结构被撑破。 - 用
the_content()输出自定义字段里的富文本,短代码不解析,因为字段内容没进过过滤器。
如果模板改完之后整站白屏,先按白屏排查的顺序定位语法错误,再看主题定制里关于子主题结构的说明。函数用错导致的 404 链接,可以对照404 处理里的日志方法确认来源。要从零写一套模板标签的封装,插件定制那篇里的钩子写法可以配合使用。后台不熟悉的话,先看后台入门熟悉菜单位置。