我需要查询wordpress帖子,返回可以通过类别OR自定义字段匹配的结果。如果它们与类别AND自定义字段匹配,则使用以下代码仅返回结果。我需要找到可以通过任一查询匹配的匹配项,因此“OR”结果但似乎不起作用。
有人可以帮忙吗?
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'arts','food' ),
'operator' => 'IN'
)
),
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'birth_city',
'value' => 'London',
'compare' => 'IN',
),
)
);
答案 0 :(得分:4)
这是我之前回答的简化 - 我希望你不要介意我把它作为一个新答案添加,以避免与我之前的答案混淆。
在这里,我使用WordPress函数get_meta_sql()
和get_tax_sql()
来修改由WHERE
生成的SQL的WP_Query()
部分:
/**
* Class WPSE_OR_Query
*
* Add a support for (tax_query OR meta_query)
*
* @version 0.2
* @link http://stackoverflow.com/a/22633399/2078474
*
*/
class WPSE_OR_Query extends WP_Query
{
protected $meta_or_tax = FALSE;
protected $tax_args = NULL;
protected $meta_args = NULL;
public function __construct( $args = array() )
{
add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), 999 );
add_filter( 'posts_where', array( $this, 'posts_where' ), 999 );
parent::__construct( $args );
}
public function pre_get_posts( $qry )
{
remove_action( current_filter(), array( $this, __FUNCTION__ ) );
// Get query vars
$this->meta_or_tax = ( isset( $qry->query_vars['meta_or_tax'] ) ) ? $qry->query_vars['meta_or_tax'] : FALSE;
if( $this->meta_or_tax )
{
$this->tax_args = ( isset( $qry->query_vars['tax_query'] ) ) ? $qry->query_vars['tax_query'] : NULL;
$this->meta_args = ( isset( $qry->query_vars['meta_query'] ) ) ? $qry->query_vars['meta_query'] : NULL;
}
}
public function posts_where( $where )
{
global $wpdb;
$field = 'ID';
remove_filter( current_filter(), array( $this, __FUNCTION__ ) );
// Construct the "tax OR meta" query
if( $this->meta_or_tax && is_array( $this->tax_args ) && is_array( $this->meta_args ) )
{
// Tax query
$sql_tax = get_tax_sql( $this->tax_args, $wpdb->posts, $field );
// Meta query
$sql_meta = get_meta_sql( $this->meta_args, 'post', $wpdb->posts, $field );
// Modify the 'where' part
if( isset( $sql_meta['where'] ) && isset( $sql_tax['where'] ) )
{
$where = str_replace( array( $sql_meta['where'], $sql_tax['where'] ) , '', $where );
$where .= sprintf( ' AND ( %s OR %s ) ', substr( trim( $sql_meta['where'] ), 4 ), substr( trim( $sql_tax['where'] ), 4 ) );
}
}
return $where;
}
}
答案 1 :(得分:3)
这是解决问题的第一次尝试。我在以下限制范围内工作:
WP_Query
WP_Tax_Query
和WP_Meta_Query
preg_replace
/ str_replace
。这可能太受限制,但这是一个挑战; - )
所以你可以试试:
$args = array(
'post_type' => 'post',
'meta_or_tax' => TRUE,
'tax_query' => array(
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'birds','falcons' ),
'operator' => 'IN'
)
),
'meta_query' => array(
array(
'key' => 'birth_city',
'value' => 'London',
'compare' => 'IN',
),
)
);
$q = new WPSE_OR_Query( $args );
我们引入新参数meta_or_tax
:
`meta_or_tax` => FALSE
会为您提供正常的WP_Query
行为和
`meta_or_tax` => TRUE
将允许您在纳税查询和元查询之间获得OR
而非默认AND
。
新的WPSE_OR_Query
类定义为:
/**
* Class WPSE_OR_Query
*
* Add a support for (tax_query OR meta_query)
*
* @link http://stackoverflow.com/a/22616337/2078474
*
*/
class WPSE_OR_Query extends WP_Query
{
protected $meta_or_tax = FALSE;
protected $tax_args = NULL;
protected $meta_args = NULL;
public function __construct( $args = array() )
{
add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), 10 );
add_filter( 'posts_clauses', array( $this, 'posts_clauses' ), 10 );
parent::__construct( $args );
}
public function pre_get_posts( $qry )
{
remove_action( current_filter(), array( $this, __FUNCTION__ ) );
// Get query vars
$this->meta_or_tax = ( isset( $qry->query_vars['meta_or_tax'] ) ) ? $qry->query_vars['meta_or_tax'] : FALSE;
if( $this->meta_or_tax )
{
$this->tax_args = ( isset( $qry->query_vars['tax_query'] ) ) ? $qry->query_vars['tax_query'] : NULL;
$this->meta_args = ( isset( $qry->query_vars['meta_query'] ) ) ? $qry->query_vars['meta_query'] : NULL;
// Unset meta and tax query
unset( $qry->query_vars['meta_query'] );
unset( $qry->query_vars['tax_query'] );
}
}
public function posts_clauses( $clauses )
{
global $wpdb;
$field = 'ID';
remove_filter( current_filter(), array( $this, __FUNCTION__ ) );
// Reconstruct the "tax OR meta" query
if( $this->meta_or_tax && is_array( $this->tax_args ) && is_array( $this->meta_args ) )
{
// Tax query
$tax_query = new WP_Tax_Query( $this->tax_args );
$sql_tax = $tax_query->get_sql( $wpdb->posts, $field );
// Meta query
$meta_query = new WP_Meta_Query( $this->meta_args );
$sql_meta = $meta_query->get_sql( 'post', $wpdb->posts, $field );
// Where part
if( isset( $sql_meta['where'] ) && isset( $sql_tax['where'] ) )
{
$t = substr( trim( $sql_tax['where'] ), 4 );
$m = substr( trim( $sql_meta['where'] ), 4 );
$clauses['where'] .= sprintf( ' AND ( %s OR %s ) ', $t, $m );
}
// Join/Groupby part
if( isset( $sql_meta['join'] ) && isset( $sql_tax['join'] ) )
{
$clauses['join'] .= sprintf( ' %s %s ', $sql_meta['join'], $sql_tax['join'] );
$clauses['groupby'] .= sprintf( ' %s.%s ', $wpdb->posts, $field );
}
}
return $clauses;
}
}
这是普通SQL的一个例子:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (15,70) )
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
AND ( (wp_postmeta.meta_key = 'birth_city' AND CAST(wp_postmeta.meta_value AS CHAR) IN ('London')) )
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC LIMIT 0, 10
和修改版本的SQL:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE 1=1
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
AND ( ( (wp_postmeta.meta_key = 'birth_city' AND CAST(wp_postmeta.meta_value AS CHAR) IN ('London')) ) OR ( wp_term_relationships.term_taxonomy_id IN (15,70) ) )
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC LIMIT 0, 10
这当然可以进一步完善,您可以根据自己的需要进一步扩展。
希望这有帮助。
答案 2 :(得分:1)
我没有找到一种方法如何使用WP_Query,但如果它有帮助,这里是如何手动编写查询,它看起来很丑,但如果这是唯一的方式它将达到目的:
$results = $wpdb->get_results( $wpdb->prepare( "
SELECT * FROM $wpdb->posts
LEFT JOIN $wpdb->postmeta ON($wpdb->posts.ID = $wpdb->postmeta.post_id)
LEFT JOIN $wpdb->term_relationships ON($wpdb->posts.ID = $wpdb->term_relationships.object_id)
LEFT JOIN $wpdb->term_taxonomy ON($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
LEFT JOIN $wpdb->terms ON($wpdb->term_taxonomy.term_id = $wpdb->terms.term_id)
WHERE $wpdb->posts.post_status = 'publish'
AND $wpdb->posts.post_type = 'post'
AND $wpdb->term_taxonomy.taxonomy = 'category'
AND $wpdb->terms.name IN ( %s, %s )
OR ( $wpdb->postmeta.meta_key = %s
AND $wpdb->postmeta.meta_value = %s )
ORDER BY $wpdb->posts.post_date DESC
", 'arts', 'food', 'birth_city', 'London' ), OBJECT_K );