使用wordpress遍历文章循环功能时,一直都是复制粘贴以下代码,在此基础上调整功能。由于不了解,每次使用时心里不踏实,徒增神秘感。因此,这次下决心了解此机制,非祛魅不可。
$args = array(
'post_type' => 'fanhua_history',
'posts_per_page' => 3
);
$query = new WP_Query($args);
if ($query->have_posts()) {
echo '有文章需要处理:';
while ($query->have_posts()) {
$query->the_post();
echo '<h2>'. get_the_title(). '</h2>';
}
} else {
echo '没有找到符合条件的文章。';
}
wp_reset_postdata();
◆ 查询文章返回结果
WP_Query Object
(
[query] => Array
(
[post_type] => fanhua_history
[posts_per_page] => -1
)
[query_vars] => Array
(
[post_type] => fanhua_history
[posts_per_page] => -1
[error] =>
[m] =>
[p] => 0
[post_parent] =>
[subpost] =>
[subpost_id] =>
[attachment] =>
[attachment_id] => 0
[name] =>
[pagename] =>
[page_id] => 0
[second] =>
[minute] =>
[hour] =>
[day] => 0
[monthnum] => 0
[year] => 0
[w] => 0
[category_name] =>
[tag] =>
[cat] =>
[tag_id] =>
[author] =>
[author_name] =>
[feed] =>
[tb] =>
[paged] => 0
[meta_key] =>
[meta_value] =>
[preview] =>
[s] =>
[sentence] =>
[title] =>
[fields] =>
[menu_order] =>
=>
[category__in] => Array ()
[category__not_in] => Array()
[category__and] => Array()
[post__in] => Array()
[post__not_in] => Array()
[post_name__in] => Array()
[tag__in] => Array()
[tag__not_in] => Array()
[tag__and] => Array()
[tag_slug__in] => Array()
[tag_slug__and] => Array()
[post_parent__in] => Array()
[post_parent__not_in] => Array()
[author__in] => Array()
[author__not_in] => Array()
[search_columns] => Array()
[ignore_sticky_posts] =>
[suppress_filters] =>
[cache_results] => 1
[update_post_term_cache] => 1
[update_menu_item_cache] =>
[lazy_load_term_meta] => 1
[update_post_meta_cache] => 1
[nopaging] => 1
[comments_per_page] => 50
[no_found_rows] =>
[order] => DESC
)
[tax_query] => WP_Tax_Query Object
(
[queries] => Array()
[relation] => AND
[table_aliases:protected] => Array()
[queried_terms] => Array()
[primary_table] => xs_3_posts
[primary_id_column] => ID
)
[meta_query] => WP_Meta_Query Object
(
[queries] => Array()
[relation] =>
[meta_table] =>
[meta_id_column] =>
[primary_table] =>
[primary_id_column] =>
[table_aliases:protected] => Array()
[clauses:protected] => Array()
[has_or_relation:protected] =>
)
[date_query] =>
[request] =>
SELECT xs_3_posts.* FROM xs_3_posts
WHERE 1 = 1
AND (
(
xs_3_posts.post_type = 'fanhua_history'
AND (xs_3_posts.post_status = 'publish' OR xs_3_posts.post_status = 'private')
)
)
ORDER BY xs_3_posts.post_date DESC
[posts] => Array
(
[0] => WP_Post Object
(
[ID] => 74
[post_author] => 1
[post_date] => 2025-02-27 16:17:12
[post_date_gmt] => 2025-02-27 08:17:12
[post_content] =>
[post_title] => X先生的打字机
[post_excerpt] =>
[post_status] => publish
[comment_status] => closed
[ping_status] => closed
[post_password] =>
[post_name] => x%e5%85%88%e7%94%9f%e7%9a%84%e6%89%93%e5%ad%97%e6%9c%ba
[to_ping] =>
[pinged] =>
[post_modified] => 2025-02-27 16:17:12
[post_modified_gmt] => 2025-02-27 08:17:12
[post_content_filtered] =>
[post_parent] => 0
[guid] => https://example3.chenzhuzhen.cn/?post_type=fanhua_history&p=74
[menu_order] => 0
[post_type] => fanhua_history
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
)
[1] => WP_Post Object
(
[ID] => 73
[post_author] => 1
[post_date] => 2025-02-27 16:16:28
[post_date_gmt] => 2025-02-27 08:16:28
[post_content] =>
[post_title] => L女士的首饰音乐盒
[post_excerpt] =>
[post_status] => publish
[comment_status] => closed
[ping_status] => closed
[post_password] =>
[post_name] => l%e5%a5%b3%e5%a3%ab%e7%9a%84%e9%a6%96%e9%a5%b0%e9%9f%b3%e4%b9%90%e7%9b%92
[to_ping] =>
[pinged] =>
[post_modified] => 2025-02-27 16:16:28
[post_modified_gmt] => 2025-02-27 08:16:28
[post_content_filtered] =>
[post_parent] => 0
[guid] => https://example3.chenzhuzhen.cn/?post_type=fanhua_history&p=73
[menu_order] => 0
[post_type] => fanhua_history
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
)
[2] => WP_Post Object
(
[ID] => 72
[post_author] => 1
[post_date] => 2025-02-27 16:15:49
[post_date_gmt] => 2025-02-27 08:15:49
[post_content] =>
[post_title] => K先生的金利来考克箱
[post_excerpt] =>
[post_status] => publish
[comment_status] => closed
[ping_status] => closed
[post_password] =>
[post_name] => k%e5%85%88%e7%94%9f%e7%9a%84%e9%87%91%e5%88%a9%e6%9d%a5%e8%80%83%e5%85%8b%e7%ae%b1
[to_ping] =>
[pinged] =>
[post_modified] => 2025-02-27 16:15:49
[post_modified_gmt] => 2025-02-27 08:15:49
[post_content_filtered] =>
[post_parent] => 0
[guid] => https://example3.chenzhuzhen.cn/?post_type=fanhua_history&p=72
[menu_order] => 0
[post_type] => fanhua_history
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
)
[3] => WP_Post Object
(
[ID] => 63
[post_author] => 1
[post_date] => 2025-02-27 16:13:30
[post_date_gmt] => 2025-02-27 08:13:30
[post_content] =>
[post_title] => 小Y奶奶的盘子“宝物”
[post_excerpt] =>
[post_status] => publish
[comment_status] => closed
[ping_status] => closed
[post_password] =>
[post_name] => %e5%b0%8fy%e5%a5%b6%e5%a5%b6%e7%9a%84%e7%9b%98%e5%ad%90%e5%ae%9d%e7%89%a9
[to_ping] =>
[pinged] =>
[post_modified] => 2025-02-27 16:13:30
[post_modified_gmt] => 2025-02-27 08:13:30
[post_content_filtered] =>
[post_parent] => 0
[guid] => https://example3.chenzhuzhen.cn/?post_type=fanhua_history&p=63
[menu_order] => 0
[post_type] => fanhua_history
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
)
[4] => WP_Post Object
(
[ID] => 64
[post_author] => 1
[post_date] => 2025-02-27 16:12:39
[post_date_gmt] => 2025-02-27 08:12:39
[post_content] =>
[post_title] => 监制、总导演王家卫三十年珍藏绍兴老酒
[post_excerpt] =>
[post_status] => publish
[comment_status] => closed
[ping_status] => closed
[post_password] =>
[post_name] => 64
[to_ping] =>
[pinged] =>
[post_modified] => 2025-02-27 16:12:44
[post_modified_gmt] => 2025-02-27 08:12:44
[post_content_filtered] =>
[post_parent] => 0
[guid] => https://example3.chenzhuzhen.cn/?post_type=fanhua_history&p=64
[menu_order] => 0
[post_type] => fanhua_history
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
)
[5] => WP_Post Object
(
[ID] => 65
[post_author] => 1
[post_date] => 2025-02-27 16:11:44
[post_date_gmt] => 2025-02-27 08:11:44
[post_content] =>
[post_title] => 原著作者金宇澄老师珍贵旧物
[post_excerpt] =>
[post_status] => publish
[comment_status] => closed
[ping_status] => closed
[post_password] =>
[post_name] => 65
[to_ping] =>
[pinged] =>
[post_modified] => 2025-02-27 16:11:48
[post_modified_gmt] => 2025-02-27 08:11:48
[post_content_filtered] =>
[post_parent] => 0
[guid] => https://example3.chenzhuzhen.cn/?post_type=fanhua_history&p=65
[menu_order] => 0
[post_type] => fanhua_history
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
)
[6] => WP_Post Object
(
[ID] => 66
[post_author] => 1
[post_date] => 2025-02-27 10:05:56
[post_date_gmt] => 2025-02-27 02:05:56
[post_content] =>
[post_title] => 胡歌捐缝纫机给繁花剧组
[post_excerpt] =>
[post_status] => publish
[comment_status] => closed
[ping_status] => closed
[post_password] =>
[post_name] => 66
[to_ping] =>
[pinged] =>
[post_modified] => 2025-02-27 10:06:11
[post_modified_gmt] => 2025-02-27 02:06:11
[post_content_filtered] =>
[post_parent] => 0
[guid] => https://example3.chenzhuzhen.cn/?post_type=fanhua_history&p=66
[menu_order] => 0
[post_type] => fanhua_history
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
)
)
[post_count] => 7
[current_post] => -1
[before_loop] => 1
[in_the_loop] =>
[post] => WP_Post Object
(
[ID] => 74
[post_author] => 1
[post_date] => 2025-02-27 16:17:12
[post_date_gmt] => 2025-02-27 08:17:12
[post_content] =>
[post_title] => X先生的打字机
[post_excerpt] =>
[post_status] => publish
[comment_status] => closed
[ping_status] => closed
[post_password] =>
[post_name] => x%e5%85%88%e7%94%9f%e7%9a%84%e6%89%93%e5%ad%97%e6%9c%ba
[to_ping] =>
[pinged] =>
[post_modified] => 2025-02-27 16:17:12
[post_modified_gmt] => 2025-02-27 08:17:12
[post_content_filtered] =>
[post_parent] => 0
[guid] => https://example3.chenzhuzhen.cn/?post_type=fanhua_history&p=74
[menu_order] => 0
[post_type] => fanhua_history
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
)
[comment_count] => 0
[current_comment] => -1
[found_posts] => 7
[max_num_pages] => 0
[max_num_comment_pages] => 0
[is_single] =>
[is_preview] =>
[is_page] =>
[is_archive] =>
[is_date] =>
[is_year] =>
[is_month] =>
[is_day] =>
[is_time] =>
[is_author] =>
[is_category] =>
[is_tag] =>
[is_tax] =>
[is_search] =>
[is_feed] =>
[is_comment_feed] =>
[is_trackback] =>
[is_home] => 1
[is_privacy_policy] =>
[is_404] =>
[is_embed] =>
[is_paged] =>
[is_admin] =>
[is_attachment] =>
[is_singular] =>
[is_robots] =>
[is_favicon] =>
[is_posts_page] =>
[is_post_type_archive] =>
[query_vars_hash:WP_Query:private] => 2f489cdc43f68566e67c65fc2fb2ac65
[query_vars_changed:WP_Query:private] =>
[thumbnails_cached] =>
[allow_query_attachment_by_filename:protected] =>
[stopwords:WP_Query:private] =>
[compat_fields:WP_Query:private] => Array
(
[0] => query_vars_hash
[1] => query_vars_changed
)
[compat_methods:WP_Query:private] => Array
(
[0] => init_query_flags
[1] => parse_tax_query
)
)
可见$query = new WP_Query($args);经过数据库执行后,其结果都缓存在$query对象里。后面均是围绕上面内容循环遍历文章。
◆ 遍历文章
public function have_posts() {
if ( $this->current_post + 1 < $this->post_count ) {
return true;
} elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
do_action_ref_array( 'loop_end', array( &$this ) );
// Do some cleaning up after the loop.
$this->rewind_posts();
} elseif ( 0 === $this->post_count ) {
$this->before_loop = false;
do_action( 'loop_no_results', $this );
}
$this->in_the_loop = false;
return false;
}
如上代码,have_posts()
方法通过$this->current_post + 1【这些current_post 、post_count 等变量均来自$query = new WP_Query($args)的查询结果】,比较当前处理的文章索引和文章总数,判断是否还有未处理的文章,并根据不同情况触发相应的动作钩子和进行状态重置。所以,通常会结合 while
循环来遍历查询结果集中的文章。
◆ 获取当前文章内容
public function the_post() {
global $post;
if ( ! $this->in_the_loop ) {
// Only prime the post cache for queries limited to the ID field.
$post_ids = array_filter( $this->posts, 'is_numeric' );
// Exclude any falsey values, such as 0.
$post_ids = array_filter( $post_ids );
if ( $post_ids ) {
_prime_post_caches( $post_ids, $this->query_vars['update_post_term_cache'], $this->query_vars['update_post_meta_cache'] );
}
$post_objects = array_map( 'get_post', $this->posts );
update_post_author_caches( $post_objects );
}
$this->in_the_loop = true;
$this->before_loop = false;
if ( -1 == $this->current_post ) { // Loop has just started.
do_action_ref_array( 'loop_start', array( &$this ) );
}
$post = $this->next_post();
$this->setup_postdata( $post );
}
public function next_post() {
++$this->current_post;
/** @var WP_Post */
$this->post = $this->posts[ $this->current_post ];
return $this->post;
}
如上代码,the_post() 方法作用是将查询结果集中的下一篇文章设置为当前文章,并为该文章设置好相关的数据和上下文,以便后续使用 WordPress 的模板标签(如 the_title()
、the_content()
等)来显示文章的内容。
其中 next_post()
方法中++$this->current_post
会先将 $this->current_post
的值加 1,然后再使用这个新值。即调用该方法时,current_post
变量值加一,指向下一篇文章。
◆ 恢复主查询的当前文章对象
function wp_reset_postdata() {
global $wp_query;
if ( isset( $wp_query ) ) {
$wp_query->reset_postdata();
}
}
public function reset_postdata() {
if ( ! empty( $this->post ) ) {
$GLOBALS['post'] = $this->post;
$this->setup_postdata( $this->post );
}
}
由于new WP_Query()
创建的自定义查询,遍历循环时,调用 the_post()
会修改全局 $post
对象。因此如果不重置,后续模板标签(如 the_title()
)可能继续使用自定义查询的最后一篇文章数据,导致【主查询】或其它地方显示异常,这涉及到主循环等相关概念。
【主查询】:著查询是 WordPress 根据当前访问的 URL 自动生成的默认查询(如:访问首页时,主查询是按时间倒序显示文章列表),存在全局变量$wp_query 中(即WP_Query 对象实例),可通过 global $wp_query进行访问。
【自定义查询】:当创建自定义查询时,$query = new WP_Query($args),即创建一个新的WP_Query实例时,务必使用自定义变量名$query保存数据结果,以避免覆盖保存原本著查询结果的全局变量名$wp_query。这样使用独立的变量名$query创建自定义查询,即$query
是一个独立的新的 WP_Query
对象,其操作不会影响主查询对象 $wp_query
。
但是$post
是一个全局变量(WP_Post
对象),当在循环中调用 the_post()
,会将 $post
设置为循环中的当前文章。所以遍历循环完后,一定要将全局 $post
重置为 存储著查询结果的$wp_query->posts
数组中对应的文章对象。
【主循环重置流程】:如上代码,wp_reset_postdata() 的核心作用是 将 $post 重新指向主查询当前循环的文章。具体过程为主查询($wp_query)保存了循环的进度,其内部有一个变量current_post,记录当前循环到了第几篇文章(例如首页文章列表中的第3篇文章)。调用 wp_reset_postdata() 时,将全局 $post 设置为 $wp_query->posts 数组中对应的文章对象。
所以,了解以上机理。当你使用自定义查询时,其返回结果,如果你用原本保存著查询结果的全局变量$wp_query,即$wp_query = new WP_Query($args);这会造成严重后果,原始主查询(如页面内容、文章详情等)被彻底替换,就算用wp_reset_postdata() 只能恢复被覆盖后的 $wp_query 的状态。所以,再次强调:永远不要直接覆盖 $wp_query:它是 WordPress 的核心全局变量,存储主查询数据。正确做法应使用独立的变量名(如 $query)创建自定义查询。