Overhaul SQL generating logic in WP_Meta_Query to avoid unnecessary table joins.

The logic used to generate clause SQL in `WP_Meta_Query` is somewhat arcane,
stemming mostly from an ongoing effort to eliminate costly table joins when
they are not necessary. By systematizing the process of looking for shareable
joins - as was done in `WP_Tax_Query` [29902] - it becomes possible to simplify
the construction of SQL queries in `get_sql_for_clause()`. Moreover, the
simplified logic is actually considerably better at identifying shareable
joins, such that certain uses of `WP_Meta_Query` will see joins reduced by 50%
or more.

Includes integration tests for a representative cross-section of the query
clause combinations that result in shared table aliases.

Props boonebgorges, sc0ttkclark.
See #24093.

git-svn-id: https://develop.svn.wordpress.org/trunk@29940 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Boone Gorges 2014-10-17 20:20:04 +00:00
parent be59c5009e
commit 1708a580fd
3 changed files with 527 additions and 79 deletions

View File

@ -987,6 +987,10 @@ class WP_Meta_Query {
// First-order clause.
} else if ( $this->is_first_order_clause( $query ) ) {
if ( isset( $query['value'] ) && array() === $query['value'] ) {
unset( $query['value'] );
}
$clean_queries[] = $query;
// Otherwise, it's a nested query, so we recurse.
@ -1167,7 +1171,12 @@ class WP_Meta_Query {
* }
*/
protected function get_sql_clauses() {
$sql = $this->get_sql_for_query( $this->queries );
/*
* $queries are passed by reference to get_sql_for_query() for recursion.
* To keep $this->queries unaltered, pass a copy.
*/
$queries = $this->queries;
$sql = $this->get_sql_for_query( $queries );
if ( ! empty( $sql['where'] ) ) {
$sql['where'] = ' AND ' . $sql['where'];
@ -1195,7 +1204,7 @@ class WP_Meta_Query {
* @type string $where SQL fragment to append to the main WHERE clause.
* }
*/
protected function get_sql_for_query( $query, $depth = 0 ) {
protected function get_sql_for_query( &$query, $depth = 0 ) {
$sql_chunks = array(
'join' => array(),
'where' => array(),
@ -1211,7 +1220,7 @@ class WP_Meta_Query {
$indent .= " ";
}
foreach ( $query as $key => $clause ) {
foreach ( $query as $key => &$clause ) {
if ( 'relation' === $key ) {
$relation = $query['relation'];
} else if ( is_array( $clause ) ) {
@ -1278,7 +1287,7 @@ class WP_Meta_Query {
* @type string $where SQL fragment to append to the main WHERE clause.
* }
*/
public function get_sql_for_clause( $clause, $parent_query ) {
public function get_sql_for_clause( &$clause, $parent_query ) {
global $wpdb;
$sql_chunks = array(
@ -1286,16 +1295,13 @@ class WP_Meta_Query {
'join' => array(),
);
$i = count( $this->table_aliases );
$alias = $i ? 'mt' . $i : $this->meta_table;
if ( isset( $clause['compare'] ) ) {
$meta_compare = strtoupper( $clause['compare'] );
$clause['compare'] = strtoupper( $clause['compare'] );
} else {
$meta_compare = isset( $clause['value'] ) && is_array( $clause['value'] ) ? 'IN' : '=';
$clause['compare'] = isset( $clause['value'] ) && is_array( $clause['value'] ) ? 'IN' : '=';
}
if ( ! in_array( $meta_compare, array(
if ( ! in_array( $clause['compare'], array(
'=', '!=', '>', '>=', '<', '<=',
'LIKE', 'NOT LIKE',
'IN', 'NOT IN',
@ -1303,58 +1309,62 @@ class WP_Meta_Query {
'EXISTS', 'NOT EXISTS',
'REGEXP', 'NOT REGEXP', 'RLIKE'
) ) ) {
$meta_compare = '=';
$clause['compare'] = '=';
}
/*
* There are a number of different query structures that get
* built in different ways.
* 1. Key-only clauses - (a) clauses without a 'value' key that
* appear in the context of an OR relation and do not use
* 'NOT EXISTS' as the 'compare', or (b) clauses with an
* empty array for 'value'.
*/
if ( ! empty( $clause['key'] ) && (
( ! array_key_exists( 'value', $clause ) && 'NOT EXISTS' !== $meta_compare && 'OR' === $parent_query['relation'] ) ||
( isset( $clause['value'] ) && is_array( $clause['value'] ) && empty( $clause['value'] ) )
) ) {
$meta_compare = $clause['compare'];
$alias = $this->meta_table;
$sql_chunks['join'][] = " INNER JOIN $this->meta_table ON ($this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column)";
$sql_chunks['where'][] = $wpdb->prepare( "$this->meta_table.meta_key = %s", trim( $clause['key'] ) );
// First build the JOIN clause, if one is required.
$join = '';
// 2. NOT EXISTS.
} else if ( 'NOT EXISTS' === $meta_compare ) {
$join = " LEFT JOIN $this->meta_table";
$join .= $i ? " AS $alias" : '';
$join .= $wpdb->prepare( " ON ($this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column AND $alias.meta_key = %s )", $clause['key'] );
$sql_chunks['join'][] = $join;
// We prefer to avoid joins if possible. Look for an existing join compatible with this clause.
$alias = $this->find_compatible_table_alias( $clause, $parent_query );
if ( false === $alias ) {
$i = count( $this->table_aliases );
$alias = $i ? 'mt' . $i : $this->meta_table;
$sql_chunks['where'][] = $alias . '.' . $this->meta_id_column . ' IS NULL';
// JOIN clauses for NOT EXISTS have their own syntax.
if ( 'NOT EXISTS' === $meta_compare ) {
$join .= " LEFT JOIN $this->meta_table";
$join .= $i ? " AS $alias" : '';
$join .= $wpdb->prepare( " ON ($this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column AND $alias.meta_key = %s )", $clause['key'] );
$sql_chunks['join'][] = $join;
// 3. EXISTS and other key-only queries.
} else if ( 'EXISTS' === $meta_compare || ( ! empty( $clause['key'] ) && ! array_key_exists( 'value', $clause ) ) ) {
$join = " INNER JOIN $this->meta_table";
$join .= $i ? " AS $alias" : '';
$join .= " ON ( $this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column )";
$sql_chunks['join'][] = $join;
// All other JOIN clauses.
} else {
$alias = $this->find_compatible_table_alias( $clause, $parent_query );
if ( false === $alias ) {
$alias = $i ? 'mt' . $i : $this->meta_table;
$sql_chunks['where'][] = $wpdb->prepare( $alias . '.meta_key = %s', trim( $clause['key'] ) );
// 4. Clauses that have a value.
} else if ( array_key_exists( 'value', $clause ) ) {
$join = " INNER JOIN $this->meta_table";
$join .= $i ? " AS $alias" : '';
$join .= " ON ($this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column)";
$sql_chunks['join'][] = $join;
if ( ! empty( $clause['key'] ) ) {
$sql_chunks['where'][] = $wpdb->prepare( "$alias.meta_key = %s", trim( $clause['key'] ) );
$join .= " INNER JOIN $this->meta_table";
$join .= $i ? " AS $alias" : '';
$join .= " ON ( $this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column )";
}
}
$meta_type = $this->get_cast_for_type( isset( $clause['type'] ) ? $clause['type'] : '' );
$this->table_aliases[] = $alias;
$sql_chunks['join'][] = $join;
}
$meta_value = isset( $clause['value'] ) ? $clause['value'] : '';
// Save the alias to this clause, for future siblings to find.
$clause['alias'] = $alias;
// Next, build the WHERE clause.
$where = '';
// meta_key.
if ( array_key_exists( 'key', $clause ) ) {
if ( 'NOT EXISTS' === $meta_compare ) {
$sql_chunks['where'][] = $alias . '.' . $this->meta_id_column . ' IS NULL';
} else {
$sql_chunks['where'][] = $wpdb->prepare( "$alias.meta_key = %s", trim( $clause['key'] ) );
}
}
// meta_value.
if ( array_key_exists( 'value', $clause ) ) {
$meta_value = $clause['value'];
$meta_type = $this->get_cast_for_type( isset( $clause['type'] ) ? $clause['type'] : '' );
if ( in_array( $meta_compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) {
if ( ! is_array( $meta_value ) ) {
@ -1364,19 +1374,34 @@ class WP_Meta_Query {
$meta_value = trim( $meta_value );
}
if ( 'IN' == substr( $meta_compare, -2 ) ) {
$meta_compare_string = '(' . substr( str_repeat( ',%s', count( $meta_value ) ), 1 ) . ')';
} elseif ( 'BETWEEN' == substr( $meta_compare, -7 ) ) {
$meta_value = array_slice( $meta_value, 0, 2 );
$meta_compare_string = '%s AND %s';
} elseif ( 'LIKE' == $meta_compare || 'NOT LIKE' == $meta_compare ) {
$meta_value = '%' . $wpdb->esc_like( $meta_value ) . '%';
$meta_compare_string = '%s';
} else {
$meta_compare_string = '%s';
switch ( $meta_compare ) {
case 'IN' :
case 'NOT IN' :
$meta_compare_string = '(' . substr( str_repeat( ',%s', count( $meta_value ) ), 1 ) . ')';
$where = $wpdb->prepare( $meta_compare_string, $meta_value );
break;
case 'BETWEEN' :
case 'NOT BETWEEN' :
$meta_value = array_slice( $meta_value, 0, 2 );
$where = $wpdb->prepare( '%s AND %s', $meta_value );
break;
case 'LIKE' :
case 'NOT LIKE' :
$meta_value = '%' . $wpdb->esc_like( $meta_value ) . '%';
$where = $wpdb->prepare( '%s', $meta_value );
break;
default :
$where = $wpdb->prepare( '%s', $meta_value );
break;
}
$sql_chunks['where'][] = $wpdb->prepare( "CAST($alias.meta_value AS {$meta_type}) {$meta_compare} {$meta_compare_string}", $meta_value );
if ( $where ) {
$sql_chunks['where'][] = "CAST($alias.meta_value AS {$meta_type}) {$meta_compare} {$where}";
}
}
/*
@ -1387,10 +1412,62 @@ class WP_Meta_Query {
$sql_chunks['where'] = array( '( ' . implode( ' AND ', $sql_chunks['where'] ) . ' )' );
}
$this->table_aliases[] = $alias;
return $sql_chunks;
}
/**
* Identify an existing table alias that is compatible with the current query clause.
*
* We avoid unnecessary table joins by allowing each clause to look for
* an existing table alias that is compatible with the query that it
* needs to perform. An existing alias is compatible if (a) it is a
* sibling of $clause (ie, it's under the scope of the same relation),
* and (b) the combination of operator and relation between the clauses
* allows for a shared table join. In the case of WP_Meta_Query, this
* only applies to IN clauses that are connected by the relation OR.
*
* @since 4.1.0
* @access protected
*
* @param array $clause Query clause.
* @param array $parent_query Parent query of $clause.
* @return string|bool Table alias if found, otherwise false.
*/
protected function find_compatible_table_alias( $clause, $parent_query ) {
$alias = false;
foreach ( $parent_query as $sibling ) {
// If the sibling has no alias yet, there's nothing to check.
if ( empty( $sibling['alias'] ) ) {
continue;
}
// We're only interested in siblings that are first-order clauses.
if ( ! is_array( $sibling ) || ! $this->is_first_order_clause( $sibling ) ) {
continue;
}
$compatible_compares = array();
// Clauses connected by OR can share joins as long as they have "positive" operators.
if ( 'OR' === $parent_query['relation'] ) {
$compatible_compares = array( '=', 'IN', 'BETWEEN', 'LIKE', 'REGEXP', 'RLIKE', '>', '>=', '<', '<=' );
// Clauses joined by AND with "negative" operators share a join only if they also share a key.
} else if ( isset( $sibling['key'] ) && isset( $clause['key'] ) && $sibling['key'] === $clause['key'] ) {
$compatible_compares = array( '!=', 'NOT IN', 'NOT LIKE' );
}
$clause_compare = strtoupper( $clause['compare'] );
$sibling_compare = strtoupper( $sibling['compare'] );
if ( in_array( $clause_compare, $compatible_compares ) && in_array( $sibling_compare, $compatible_compares ) ) {
$alias = $sibling['alias'];
break;
}
}
return apply_filters( 'meta_query_find_compatible_table_alias', $alias, $clause, $parent_query, $this ) ;
}
}
/**

View File

@ -73,7 +73,7 @@ class Tests_Meta_Query extends WP_UnitTestCase {
$sql = $query->get_sql( 'post', $wpdb->posts, 'ID' );
$this->assertEquals( 2, substr_count( $sql['join'], 'INNER JOIN' ) );
$this->assertEquals( 1, substr_count( $sql['join'], 'INNER JOIN' ) );
}
/**
@ -476,12 +476,7 @@ class Tests_Meta_Query extends WP_UnitTestCase {
$sql = $query->get_sql( 'post', $wpdb->posts, 'ID', $this );
// We should have 2 joins - one for my_first_key and one for my_second_key
$this->assertEquals( 2, substr_count( $sql['join'], 'JOIN' ) );
// The WHERE should check my_third_key against an unaliased table
$this->assertEquals( 1, substr_count( $sql['where'], "$wpdb->postmeta.meta_key = 'my_third_key'" ) );
$this->assertEquals( 3, substr_count( $sql['join'], 'JOIN' ) );
}
/**
@ -546,9 +541,6 @@ class Tests_Meta_Query extends WP_UnitTestCase {
// NOT EXISTS compare queries are not key-only so should not be non-aliased
$this->assertSame( 0, substr_count( $sql['where'], "$wpdb->postmeta.meta_key = 'baz'" ) );
// When a value exists, it's not a key-only query
$this->assertSame( 0, substr_count( $sql['where'], "$wpdb->postmeta.meta_key = 'barry'" ) );
// 'AND' queries don't have key-only queries
$query2 = new WP_Meta_Query( array(
'relation' => 'AND',

View File

@ -646,6 +646,385 @@ class Tests_Post_Query extends WP_UnitTestCase {
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_or_compare_equals() {
$posts = $this->factory->post->create_many( 4 );
add_post_meta( $posts[0], 'color', 'orange' );
add_post_meta( $posts[1], 'color', 'blue' );
add_post_meta( $posts[1], 'vegetable', 'onion' );
add_post_meta( $posts[2], 'vegetable', 'shallot' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'vegetable',
'value' => 'onion',
'compare' => '=',
),
array(
'key' => 'vegetable',
'value' => 'shallot',
'compare' => '=',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[1], $posts[2] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_or_compare_equals_different_keys() {
$posts = $this->factory->post->create_many( 4 );
add_post_meta( $posts[0], 'color', 'orange' );
add_post_meta( $posts[1], 'color', 'blue' );
add_post_meta( $posts[1], 'vegetable', 'onion' );
add_post_meta( $posts[2], 'vegetable', 'shallot' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'vegetable',
'value' => 'onion',
'compare' => '=',
),
array(
'key' => 'color',
'value' => 'orange',
'compare' => '=',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[0], $posts[1] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_or_compare_equals_and_in() {
$posts = $this->factory->post->create_many( 4 );
add_post_meta( $posts[0], 'color', 'orange' );
add_post_meta( $posts[1], 'color', 'blue' );
add_post_meta( $posts[1], 'vegetable', 'onion' );
add_post_meta( $posts[2], 'vegetable', 'shallot' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'vegetable',
'value' => 'onion',
'compare' => '=',
),
array(
'key' => 'color',
'value' => array( 'orange', 'green' ),
'compare' => 'IN',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[0], $posts[1] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_or_compare_equals_and_like() {
$posts = $this->factory->post->create_many( 4 );
add_post_meta( $posts[0], 'color', 'orange' );
add_post_meta( $posts[1], 'color', 'blue' );
add_post_meta( $posts[1], 'vegetable', 'onion' );
add_post_meta( $posts[2], 'vegetable', 'shallot' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'vegetable',
'value' => 'onion',
'compare' => '=',
),
array(
'key' => 'vegetable',
'value' => 'hall',
'compare' => 'LIKE',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[1], $posts[2] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_or_compare_equals_and_between() {
$posts = $this->factory->post->create_many( 4 );
add_post_meta( $posts[0], 'number_of_colors', '2' );
add_post_meta( $posts[1], 'number_of_colors', '5' );
add_post_meta( $posts[1], 'vegetable', 'onion' );
add_post_meta( $posts[2], 'vegetable', 'shallot' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'vegetable',
'value' => 'shallot',
'compare' => '=',
),
array(
'key' => 'number_of_colors',
'value' => array( 1, 3 ),
'compare' => 'BETWEEN',
'type' => 'SIGNED',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[0], $posts[2] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_and_compare_in_same_keys() {
$posts = $this->factory->post->create_many( 4 );
add_post_meta( $posts[0], 'color', 'orange' );
add_post_meta( $posts[1], 'color', 'blue' );
add_post_meta( $posts[1], 'vegetable', 'onion' );
add_post_meta( $posts[2], 'vegetable', 'shallot' );
add_post_meta( $posts[3], 'vegetable', 'banana' );
add_post_meta( $posts[3], 'vegetable', 'onion' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'vegetable',
'value' => array( 'onion', 'shallot' ),
'compare' => 'IN',
),
array(
'key' => 'vegetable',
'value' => array( 'banana' ),
'compare' => 'IN',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[3] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_and_compare_in_different_keys() {
$posts = $this->factory->post->create_many( 4 );
add_post_meta( $posts[0], 'color', 'orange' );
add_post_meta( $posts[1], 'color', 'blue' );
add_post_meta( $posts[1], 'vegetable', 'onion' );
add_post_meta( $posts[1], 'vegetable', 'shallot' );
add_post_meta( $posts[2], 'vegetable', 'shallot' );
add_post_meta( $posts[3], 'vegetable', 'banana' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'vegetable',
'value' => array( 'onion', 'shallot' ),
'compare' => 'IN',
),
array(
'key' => 'color',
'value' => array( 'blue' ),
'compare' => 'IN',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[1] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_and_compare_not_equals() {
$posts = $this->factory->post->create_many( 4 );
add_post_meta( $posts[0], 'color', 'orange' );
add_post_meta( $posts[1], 'color', 'blue' );
add_post_meta( $posts[1], 'vegetable', 'onion' );
add_post_meta( $posts[2], 'vegetable', 'shallot' );
add_post_meta( $posts[3], 'vegetable', 'banana' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'vegetable',
'value' => 'onion',
'compare' => '!=',
),
array(
'key' => 'vegetable',
'value' => 'shallot',
'compare' => '!=',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[3] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_and_compare_not_equals_different_keys() {
$posts = $this->factory->post->create_many( 4 );
// !shallot, but orange.
add_post_meta( $posts[0], 'color', 'orange' );
add_post_meta( $posts[0], 'vegetable', 'onion' );
// !orange, but shallot.
add_post_meta( $posts[1], 'color', 'blue' );
add_post_meta( $posts[1], 'vegetable', 'shallot' );
// Neither.
add_post_meta( $posts[2], 'color', 'blue' );
add_post_meta( $posts[2], 'vegetable', 'onion' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'vegetable',
'value' => 'shallot',
'compare' => '!=',
),
array(
'key' => 'color',
'value' => 'orange',
'compare' => '!=',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[2] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_and_compare_not_equals_not_in() {
$posts = $this->factory->post->create_many( 4 );
add_post_meta( $posts[0], 'color', 'orange' );
add_post_meta( $posts[1], 'color', 'blue' );
add_post_meta( $posts[1], 'vegetable', 'onion' );
add_post_meta( $posts[2], 'vegetable', 'shallot' );
add_post_meta( $posts[3], 'vegetable', 'banana' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'vegetable',
'value' => 'onion',
'compare' => '!=',
),
array(
'key' => 'vegetable',
'value' => array( 'shallot' ),
'compare' => 'NOT IN',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[3] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 24093
*/
public function test_meta_query_relation_and_compare_not_equals_and_not_like() {
$posts = $this->factory->post->create_many( 4 );
add_post_meta( $posts[0], 'color', 'orange' );
add_post_meta( $posts[1], 'color', 'blue' );
add_post_meta( $posts[1], 'vegetable', 'onion' );
add_post_meta( $posts[2], 'vegetable', 'shallot' );
add_post_meta( $posts[3], 'vegetable', 'banana' );
$query = new WP_Query( array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'vegetable',
'value' => 'onion',
'compare' => '!=',
),
array(
'key' => 'vegetable',
'value' => 'hall',
'compare' => 'NOT LIKE',
),
),
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
) );
$expected = array( $posts[3] );
$this->assertEqualSets( $expected, $query->posts );
}
/**
* @ticket 23033
* @group meta
@ -1040,13 +1419,13 @@ class Tests_Post_Query extends WP_UnitTestCase {
$post_id6 = $this->factory->post->create();
add_post_meta( $post_id6, 'baz', 0 );
$posts = get_posts( array( 'meta_key' => 'foo', 'meta_value' => '0' ) );
$this->assertEquals( 1, count ( $posts ) );
foreach ( $posts as $post ) {
$q = new WP_Query( array( 'meta_key' => 'foo', 'meta_value' => '0' ) );
$this->assertEquals( 1, count ( $q->posts ) );
foreach ( $q->posts as $post ) {
$this->assertInstanceOf( 'WP_Post', $post );
$this->assertEquals( 'raw', $post->filter );
}
$this->assertEquals( $post_id, $posts[0]->ID );
$this->assertEquals( $post_id, $q->posts[0]->ID );
$posts = get_posts( array( 'meta_key' => 'bar', 'meta_value' => '0' ) );
$this->assertEquals( 2, count ( $posts ) );