我会试着整理一些顺序,把我所有的想法集中在一个答案上,而不是评论两个好答案@s_ha_dum 和@kaiser (我两个都投了赞成票)。
首先,我们需要指定WordPress中有两种类型的查询,main 和secondaries.
两者都是同一类的实例,WP_Query
但第一个区别是,主查询对象由WordPress实例化并保存在全局$wp_query
变量,所有辅助查询必须由自定义代码实例化。
但还有另一个很大的区别:为了获得职位,WP_Query
需要接收一些参数:在主查询中,这些参数是from url 在辅助查询中,参数必须显式传递给构造函数或get_posts
方法
前面的一个直接结果是,对于主查询,来自url的查询参数只能是scalar variables: 字符串、整数和布尔值:值为数组的查询参数不能通过URL、infact、,any non scalar variable is strip out from query arguments set via urls.
因此,我们还有两种类型的查询参数,“quot;标量参数“;和;数组参数;。
WordPress使用标量参数设置模板标记,实际上WordPress工作流是:
- Setup query arguments using url arguments
- Setup conditional template properties (所有
is_*
) 在全球范围内$wp_query
对象Get the posts based on query arguments - Using those conditional template properties load a specific template
值得注意的是,即使无法使用url设置非标量参数,也可以使用
\'pre_get_posts\'
使主查询使用非标量变量的操作挂钩,如
tax_query
,
meta_query
,
date_query
等等
但是\'pre_get_posts\'
在上述工作流中,在#3到#4之间运行,因此即使可以使用基于数组的查询参数,条件模板属性也已经设置好,因此只需使用tax_query
或内部的任何其他非标量查询参数pre_get_posts
don\'t affect the template conditional tags (因此加载了模板),除非显式设置is_*
属性:
add_action( \'pre_get_posts\', function( $query ) {
if ( $query->is_main_query() && ! is_admin() ) {
$tax_query = array ( array(
\'taxonomy\' => \'category\', \'field\' => \'slug\', \'terms\' => \'foo\')
);
// this will affect query, but will NOT affect the template loaded
$query->query_vars[\'tax_query\'] = $tax_query;
// this will affect the template loaded, instead
$query->is_category = TRUE;
}
} );
也就是说,非标量查询参数
\'date_query\'
是
not 用于设置模板标记,所以问题变成了另一个:为什么WordPress解析
tax_query
即使他们
can\'t 是否影响模板?
即使应该向核心开发人员提出这个问题,我也有一个想法。
Notice: next 2 code snippets are bad, here just for proof of concept: don\'t do at home.
add_action( \'template_redirect\', function() {
$args = array( \'tax_query\' => array(
array( \'taxonomy\' => \'category\', \'terms\' => array( 16, 17 ) )
) );
$GLOBALS[\'wp_query\'] = new WP_Query( $args );
} );
在以前的代码中,我替换了全局
wp_query
使用另一个使用税务查询的查询。它可能看起来很奇怪,但工作正常,加载的模板是
category.php
因为WordPress为
\'tax_query\'
(事实和
$GLOBALS[\'wp_query\']->is_category()
将是
true
).
如果我使用\'date_query\'
:
add_action( \'template_redirect\', function() {
$args = array( \'date_query\' => array(
array( \'month\' => 3, \'year\' => 2014 )
) );
$GLOBALS[\'wp_query\'] = new WP_Query( $args );
} );
帖子将按预期检索(从2014年3月起),但加载的模板将
not date.php
和
$GLOBALS[\'wp_query\']->is_date()
将是
false
.
因此,我的猜测(也只是猜测)是,在旧代码中,核心开发人员考虑了覆盖全局$wp_query
对象,其中一个使用非标量参数,因此它们需要使模板层次结构在这种情况下工作。但在更为现代的代码中(“date\\u query”只出现在WP 3.7中),核心开发人员并不担心这一点,因为他们可能认为没有理由担心糟糕的做法。。。
本质上,对于核心的工作方式,这并不奇怪date_query
不设置模板条件属性,但奇怪的是tax_query
做
只有两个附加注释。
正在查看template hierarchy, 一些条件模板标记对其没有影响,例如。is_time
and much others 对模板选择没有影响。
那么,不影响模板选择的条件模板标记的有用性是什么?
如果我们回答:“;无“;,然后,我们必须承认,它们只是出于某些历史原因或错误原因而存在,否则,如果条件标记有用,即使不影响模板选择,那么我们必须承认,如果WP将为所有非标量参数设置条件属性,而不仅仅是\'tax_query\'
.
此外,有时在我的代码中,我使用创建自己的类来扩展WP_Query
(and I\'m not the only one). 即使在大多数情况下WP_Query
类是用于辅助查询的,可能还想将其用于主查询(这远非不可能,因为这只是覆盖一个全局变量的问题)。
当然是一种很糟糕的做法覆盖$wp_query
在它已经查询了帖子之后,但是如果一个人使用了一个早期的钩子,比如\'setup_theme\'
, 那里,全球$wp_query
只是一个空对象,可以无任何问题地重写。但自定义mainWP_Query
对象,可以为主查询使用非标量参数,并允许在设置条件模板属性之前设置它们。那样的话就没用了WP_Query
是否会解析所有非标量参数并相应地正确设置条件模板属性?
在我看来,是的,这将是有用的,但直到核心将强烈基于核心WP_Query
类(这是永远的),核心可能没有意义。
如果有人出于任何原因想要解析\'date_query\'
并设置条件模板标记,则可以使用以下代码:
add_action( \'parse_query\', function ( \\WP_Query $q ) {
$cond = array(
\'hour\' => \'is_time\', \'minute\' => \'is_time\', \'second\' => \'is_time\',
\'year\' => \'is_year\', \'month\' => \'is_month\', \'day\' => \'is_day\',
\'dayofweek\' => \'is_day\',
\'week\' => \'is_date\', \'before\' => \'is_date\', \'after\' => \'is_date\'
);
$date_query = isset( $q->query_vars[\'date_query\'] )
? $q->query_vars[\'date_query\']
: FALSE;
if ( empty( $date_query ) ) return;
$found = 0;
foreach ( $date_query as $i => $query ) {
if ( ! is_array( $query ) ) continue;
foreach ( $query as $key => $val) {
if ( is_numeric($key) || ! isset( $cond[$key] ) ) continue;
if ( in_array( $key, array( \'before\', \'after\' ) ) ) {
$q->is_time = $q->is_year = $q->is_month = $q->is_day = FALSE;
$q->is_date = $q->is_archive = TRUE;
return;
}
$found++;
$q->$cond[$key] = TRUE;
}
}
if ( $found <= 0 ) return;
// a query can\'t be is_time, is_year, is_month and is_day in same time
$q->is_year = $q->is_year && ! $q->is_time && ! $q->is_month && ! $q->is_day;
$q->is_month = $q->is_month && ! $q->is_time && ! $q->is_day;
$q->is_day = $q->is_day && ! $q->is_time;
$q->is_date = $q->is_archive = TRUE;
$q->is_home = FALSE;
});