我有一个解决方案,但这真的很难看。我很想听到更好的,但我不确定这是否可能。
WP_Query::get_posts()
呼叫parse_tax_query()
两次:第一次接近开始,然后在从中获取SQL之前再次。没有一个钩子可以让我拦截和调整$tax_query
为了及时调整SQL,我不得不分两部分来完成。
上的操作pre_get_posts
, 即将开始get_posts()
使用识别分类查询\'relation\' => \'OR\'
并对其进行简化,使其仅在上生成一个连接wp_term_relationships
. 同时,它存储了“WP\\u Query”对象内所有分类法中已解析的ID列表,以供以后使用。
过滤器打开posts_where_paged
, 年晚些时候query_posts()
, 检查已保存的ID列表并替换联接上的条件。
以下是代码:
add_action(\'pre_get_posts\', \'wp_query__pre\');
function wp_query__pre ($wp_query) {
if (!isset($wp_query->query[\'tax_query\'])) return;
if ($wp_query->query[\'tax_query\'][\'relation\'] != \'OR\') return;
$allterms = array();
foreach ($wp_query->tax_query->queries as $query) {
$tax = $query[\'taxonomy\'];
$terms = $query[\'terms\'];
$wp_query->tax_query->_transform_terms($terms, $query[\'taxonomy\'], $query[\'field\'], \'term_taxonomy_id\');
$allterms = array_merge($allterms, $terms);
}
$tax_query = array(array(
\'taxonomy\' => $tax,
\'terms\' => $terms,
\'operator\' => \'IN\',
\'include_children\' => 0,
\'field\' => \'term_taxonomy_id\',
));
$wp_query->query[\'tax_query\'] = $tax_query;
$wp_query->query_vars[\'tax_query\'] = $tax_query;
$wp_query->tax_query = new WP_Tax_Query($tax_query);
$wp_query->saved_tax_terms = $allterms;
}
add_filter(\'posts_where_paged\', \'wp_query__where\', 10, 2);
function wp_query__where ($where, $wp_query) {
if (!empty($wp_query->saved_tax_terms)) {
$terms = implode(", ", $wp_query->dft_tax_terms);
$where = preg_replace("!term_taxonomy_id IN \\([^)]*\\)!", "term_taxonomy_id IN ($terms)", $where);
}
return $where;
}
请注意,代码尚未经过彻底测试,毫无疑问包含各种各样的bug。我可能不会处理任何更复杂的问题。
这种方法的优点是,它不需要代码的其余部分了解它。只需使用OR
它将得到提升和优化。它并没有像我希望的那样提供很大的速度提升,但它确实是一个进步。
我想知道WordPress团队是否应该在核心代码中包含这样的内容。
<小时>Update: 为了适应如此丑陋的黑客行为,WordPress 3.2上打破了这一点。我正在寻找解决办法。