Make WordPress Core

Ticket #24093: 24093.5.patch

File 24093.5.patch, 23.2 KB (added by boonebgorges, 10 years ago)
  • src/wp-includes/meta.php

    diff --git src/wp-includes/meta.php src/wp-includes/meta.php
    index afbf954..176a5db 100644
    class WP_Meta_Query { 
    987987
    988988                        // First-order clause.
    989989                        } else if ( $this->is_first_order_clause( $query ) ) {
     990                                if ( isset( $query['value'] ) && array() === $query['value'] ) {
     991                                        unset( $query['value'] );
     992                                }
     993
    990994                                $clean_queries[] = $query;
    991995
    992996                        // Otherwise, it's a nested query, so we recurse.
    class WP_Meta_Query { 
    11671171         * }
    11681172         */
    11691173        protected function get_sql_clauses() {
    1170                 $sql = $this->get_sql_for_query( $this->queries );
     1174                /*
     1175                 * $queries are passed by reference to get_sql_for_query() for recursion.
     1176                 * To keep $this->queries unaltered, pass a copy.
     1177                 */
     1178                $queries = $this->queries;
     1179                $sql = $this->get_sql_for_query( $queries );
    11711180
    11721181                if ( ! empty( $sql['where'] ) ) {
    11731182                        $sql['where'] = ' AND ' . $sql['where'];
    class WP_Meta_Query { 
    11951204         *     @type string $where SQL fragment to append to the main WHERE clause.
    11961205         * }
    11971206         */
    1198         protected function get_sql_for_query( $query, $depth = 0 ) {
     1207        protected function get_sql_for_query( &$query, $depth = 0 ) {
    11991208                $sql_chunks = array(
    12001209                        'join'  => array(),
    12011210                        'where' => array(),
    class WP_Meta_Query { 
    12111220                        $indent .= "  ";
    12121221                }
    12131222
    1214                 foreach ( $query as $key => $clause ) {
     1223                foreach ( $query as $key => &$clause ) {
    12151224                        if ( 'relation' === $key ) {
    12161225                                $relation = $query['relation'];
    12171226                        } else if ( is_array( $clause ) ) {
    class WP_Meta_Query { 
    12781287         *     @type string $where SQL fragment to append to the main WHERE clause.
    12791288         * }
    12801289         */
    1281         public function get_sql_for_clause( $clause, $parent_query ) {
     1290        public function get_sql_for_clause( &$clause, $parent_query ) {
    12821291                global $wpdb;
    12831292
    12841293                $sql_chunks = array(
    class WP_Meta_Query { 
    12861295                        'join' => array(),
    12871296                );
    12881297
    1289                 $i = count( $this->table_aliases );
    1290                 $alias = $i ? 'mt' . $i : $this->meta_table;
    1291 
    12921298                if ( isset( $clause['compare'] ) ) {
    1293                         $meta_compare = strtoupper( $clause['compare'] );
     1299                        $clause['compare'] = strtoupper( $clause['compare'] );
    12941300                } else {
    1295                         $meta_compare = isset( $clause['value'] ) && is_array( $clause['value'] ) ? 'IN' : '=';
     1301                        $clause['compare'] = isset( $clause['value'] ) && is_array( $clause['value'] ) ? 'IN' : '=';
    12961302                }
    12971303
    1298                 if ( ! in_array( $meta_compare, array(
     1304                if ( ! in_array( $clause['compare'], array(
    12991305                        '=', '!=', '>', '>=', '<', '<=',
    13001306                        'LIKE', 'NOT LIKE',
    13011307                        'IN', 'NOT IN',
    class WP_Meta_Query { 
    13031309                        'EXISTS', 'NOT EXISTS',
    13041310                        'REGEXP', 'NOT REGEXP', 'RLIKE'
    13051311                ) ) ) {
    1306                         $meta_compare = '=';
     1312                        $clause['compare'] = '=';
    13071313                }
    13081314
    1309                 /*
    1310                  * There are a number of different query structures that get
    1311                  * built in different ways.
    1312                  * 1. Key-only clauses - (a) clauses without a 'value' key that
    1313                  *    appear in the context of an OR relation and do not use
    1314                  *    'NOT EXISTS' as the 'compare', or (b) clauses with an
    1315                  *    empty array for 'value'.
    1316                  */
    1317                 if ( ! empty( $clause['key'] ) && (
    1318                         ( ! array_key_exists( 'value', $clause ) && 'NOT EXISTS' !== $meta_compare && 'OR' === $parent_query['relation'] ) ||
    1319                         ( isset( $clause['value'] ) && is_array( $clause['value'] ) && empty( $clause['value'] ) )
    1320                 ) ) {
    1321 
    1322                         $alias = $this->meta_table;
    1323                         $sql_chunks['join'][] = " INNER JOIN $this->meta_table ON ($this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column)";
    1324                         $sql_chunks['where'][] = $wpdb->prepare( "$this->meta_table.meta_key = %s", trim( $clause['key'] ) );
    1325 
    1326                 // 2. NOT EXISTS.
    1327                 } else if ( 'NOT EXISTS' === $meta_compare ) {
    1328                         $join  = " LEFT JOIN $this->meta_table";
    1329                         $join .= $i ? " AS $alias" : '';
    1330                         $join .= $wpdb->prepare( " ON ($this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column AND $alias.meta_key = %s )", $clause['key'] );
    1331                         $sql_chunks['join'][] = $join;
     1315                $meta_compare = $clause['compare'];
    13321316
    1333                         $sql_chunks['where'][] = $alias . '.' . $this->meta_id_column . ' IS NULL';
     1317                // First build the JOIN clause, if one is required.
     1318                $join = '';
    13341319
    1335                 // 3. EXISTS and other key-only queries.
    1336                 } else if ( 'EXISTS' === $meta_compare || ( ! empty( $clause['key'] ) && ! array_key_exists( 'value', $clause ) ) ) {
    1337                         $join  = " INNER JOIN $this->meta_table";
    1338                         $join .= $i ? " AS $alias" : '';
    1339                         $join .= " ON ( $this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column )";
    1340                         $sql_chunks['join'][] = $join;
     1320                // We prefer to avoid joins if possible. Look for an existing join compatible with this clause.
     1321                $alias = $this->find_compatible_table_alias( $clause, $parent_query );
     1322                if ( false === $alias ) {
     1323                        $i = count( $this->table_aliases );
     1324                        $alias = $i ? 'mt' . $i : $this->meta_table;
    13411325
    1342                         $sql_chunks['where'][] = $wpdb->prepare( $alias . '.meta_key = %s', trim( $clause['key'] ) );
     1326                        // JOIN clauses for NOT EXISTS have their own syntax.
     1327                        if ( 'NOT EXISTS' === $meta_compare ) {
     1328                                $join .= " LEFT JOIN $this->meta_table";
     1329                                $join .= $i ? " AS $alias" : '';
     1330                                $join .= $wpdb->prepare( " ON ($this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column AND $alias.meta_key = %s )", $clause['key'] );
     1331                                $sql_chunks['join'][] = $join;
    13431332
    1344                 // 4. Clauses that have a value.
    1345                 } else if ( array_key_exists( 'value', $clause ) ) {
    1346                         $join  = " INNER JOIN $this->meta_table";
    1347                         $join .= $i ? " AS $alias" : '';
    1348                         $join .= " ON ($this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column)";
     1333                        // All other JOIN clauses.
     1334                        } else {
     1335                                $alias = $this->find_compatible_table_alias( $clause, $parent_query );
     1336                                if ( false === $alias ) {
     1337                                        $alias = $i ? 'mt' . $i : $this->meta_table;
     1338
     1339                                        $join .= " INNER JOIN $this->meta_table";
     1340                                        $join .= $i ? " AS $alias" : '';
     1341                                        $join .= " ON ( $this->primary_table.$this->primary_id_column = $alias.$this->meta_id_column )";
     1342                                }
     1343                        }
     1344
     1345                        $this->table_aliases[] = $alias;
    13491346                        $sql_chunks['join'][] = $join;
     1347                }
    13501348
    1351                         if ( ! empty( $clause['key'] ) ) {
     1349                // Save the alias to this clause, for future siblings to find.
     1350                $clause['alias'] = $alias;
     1351
     1352                // Next, build the WHERE clause.
     1353                $where = '';
     1354
     1355                // meta_key.
     1356                if ( array_key_exists( 'key', $clause ) ) {
     1357                        if ( 'NOT EXISTS' === $meta_compare ) {
     1358                                $sql_chunks['where'][] = $alias . '.' . $this->meta_id_column . ' IS NULL';
     1359                        } else {
    13521360                                $sql_chunks['where'][] = $wpdb->prepare( "$alias.meta_key = %s", trim( $clause['key'] ) );
    13531361                        }
     1362                }
    13541363
     1364                // meta_value.
     1365                if ( array_key_exists( 'value', $clause ) ) {
     1366                        $meta_value = $clause['value'];
    13551367                        $meta_type = $this->get_cast_for_type( isset( $clause['type'] ) ? $clause['type'] : '' );
    13561368
    1357                         $meta_value = isset( $clause['value'] ) ? $clause['value'] : '';
    1358 
    13591369                        if ( in_array( $meta_compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) {
    13601370                                if ( ! is_array( $meta_value ) ) {
    13611371                                        $meta_value = preg_split( '/[,\s]+/', $meta_value );
    class WP_Meta_Query { 
    13641374                                $meta_value = trim( $meta_value );
    13651375                        }
    13661376
    1367                         if ( 'IN' == substr( $meta_compare, -2 ) ) {
    1368                                 $meta_compare_string = '(' . substr( str_repeat( ',%s', count( $meta_value ) ), 1 ) . ')';
    1369                         } elseif ( 'BETWEEN' == substr( $meta_compare, -7 ) ) {
    1370                                 $meta_value = array_slice( $meta_value, 0, 2 );
    1371                                 $meta_compare_string = '%s AND %s';
    1372                         } elseif ( 'LIKE' == $meta_compare || 'NOT LIKE' == $meta_compare ) {
    1373                                 $meta_value = '%' . $wpdb->esc_like( $meta_value ) . '%';
    1374                                 $meta_compare_string = '%s';
    1375                         } else {
    1376                                 $meta_compare_string = '%s';
     1377                        switch ( $meta_compare ) {
     1378                                case 'IN' :
     1379                                case 'NOT IN' :
     1380                                        $meta_compare_string = '(' . substr( str_repeat( ',%s', count( $meta_value ) ), 1 ) . ')';
     1381                                        $where = $wpdb->prepare( $meta_compare_string, $meta_value );
     1382                                        break;
     1383
     1384                                case 'BETWEEN' :
     1385                                case 'NOT BETWEEN' :
     1386                                        $meta_value = array_slice( $meta_value, 0, 2 );
     1387                                        $where = $wpdb->prepare( '%s AND %s', $meta_value );
     1388                                        break;
     1389
     1390                                case 'LIKE' :
     1391                                case 'NOT LIKE' :
     1392                                        $meta_value = '%' . $wpdb->esc_like( $meta_value ) . '%';
     1393                                        $where = $wpdb->prepare( '%s', $meta_value );
     1394                                        break;
     1395
     1396                                default :
     1397                                        $where = $wpdb->prepare( '%s', $meta_value );
     1398                                        break;
     1399
    13771400                        }
    13781401
    1379                         $sql_chunks['where'][] = $wpdb->prepare( "CAST($alias.meta_value AS {$meta_type}) {$meta_compare} {$meta_compare_string}", $meta_value );
     1402                        if ( $where ) {
     1403                                $sql_chunks['where'][] = "CAST($alias.meta_value AS {$meta_type}) {$meta_compare} {$where}";
     1404                        }
    13801405                }
    13811406
    13821407                /*
    class WP_Meta_Query { 
    13871412                        $sql_chunks['where'] = array( '( ' . implode( ' AND ', $sql_chunks['where'] ) . ' )' );
    13881413                }
    13891414
    1390                 $this->table_aliases[] = $alias;
    1391 
    13921415                return $sql_chunks;
    13931416        }
     1417
     1418        /**
     1419         * Identify an existing table alias that is compatible with the current query clause.
     1420         *
     1421         * We avoid unnecessary table joins by allowing each clause to look for
     1422         * an existing table alias that is compatible with the query that it
     1423         * needs to perform. An existing alias is compatible if (a) it is a
     1424         * sibling of $clause (ie, it's under the scope of the same relation),
     1425         * and (b) the combination of operator and relation between the clauses
     1426         * allows for a shared table join. In the case of WP_Meta_Query, this
     1427         * only applies to IN clauses that are connected by the relation OR.
     1428         *
     1429         * @since 4.1.0
     1430         * @access protected
     1431         *
     1432         * @param  array       $clause       Query clause.
     1433         * @param  array       $parent_query Parent query of $clause.
     1434         * @return string|bool Table alias if found, otherwise false.
     1435         */
     1436        protected function find_compatible_table_alias( $clause, $parent_query ) {
     1437                $alias = false;
     1438
     1439                if ( 'OR' === $parent_query['relation'] ) {
     1440                        $compatible_compares = array( '=', 'IN', 'BETWEEN', 'LIKE', 'REGEXP', 'RLIKE', '>', '>=', '<', '<=' );
     1441                } else {
     1442                        $compatible_compares = array( '!=', 'NOT IN', 'NOT LIKE' );
     1443                }
     1444
     1445                foreach ( $parent_query as $sibling ) {
     1446                        // If the sibling has no alias yet, there's nothing to check.
     1447                        if ( empty( $sibling['alias'] ) ) {
     1448                                continue;
     1449                        }
     1450
     1451                        // We're only interested in siblings that are first-order clauses.
     1452                        if ( ! is_array( $sibling ) || ! $this->is_first_order_clause( $sibling ) ) {
     1453                                continue;
     1454                        }
     1455
     1456                        // Clauses joined by AND can share a join only if they also share a key.
     1457                        if ( 'AND' === $parent_query['relation'] && $sibling['key'] !== $clause['key'] ) {
     1458                                continue;
     1459                        }
     1460
     1461                        $clause_compare  = strtoupper( $clause['compare'] );
     1462                        $sibling_compare = strtoupper( $sibling['compare'] );
     1463                        if ( in_array( $clause_compare, $compatible_compares ) && in_array( $sibling_compare, $compatible_compares ) ) {
     1464                                $alias = $sibling['alias'];
     1465                                break;
     1466                        }
     1467                }
     1468
     1469                return $alias;
     1470        }
    13941471}
    13951472
    13961473/**
  • tests/phpunit/tests/meta/query.php

    diff --git tests/phpunit/tests/meta/query.php tests/phpunit/tests/meta/query.php
    index 390ccc9..ceee7cf 100644
    class Tests_Meta_Query extends WP_UnitTestCase { 
    7373
    7474                $sql = $query->get_sql( 'post', $wpdb->posts, 'ID' );
    7575
    76                 $this->assertEquals( 2, substr_count( $sql['join'], 'INNER JOIN' ) );
     76                $this->assertEquals( 1, substr_count( $sql['join'], 'INNER JOIN' ) );
    7777        }
    7878
    7979        /**
    class Tests_Meta_Query extends WP_UnitTestCase { 
    476476
    477477                $sql = $query->get_sql( 'post', $wpdb->posts, 'ID', $this );
    478478
    479                 // We should have 2 joins - one for my_first_key and one for my_second_key
    480                 $this->assertEquals( 2, substr_count( $sql['join'], 'JOIN' ) );
    481 
    482                 // The WHERE should check my_third_key against an unaliased table
    483                 $this->assertEquals( 1, substr_count( $sql['where'], "$wpdb->postmeta.meta_key = 'my_third_key'" ) );
    484 
     479                $this->assertEquals( 3, substr_count( $sql['join'], 'JOIN' ) );
    485480        }
    486481
    487482        /**
    class Tests_Meta_Query extends WP_UnitTestCase { 
    546541                // NOT EXISTS compare queries are not key-only so should not be non-aliased
    547542                $this->assertSame( 0, substr_count( $sql['where'], "$wpdb->postmeta.meta_key = 'baz'" ) );
    548543
    549                 // When a value exists, it's not a key-only query
    550                 $this->assertSame( 0, substr_count( $sql['where'], "$wpdb->postmeta.meta_key = 'barry'" ) );
    551 
    552544                // 'AND' queries don't have key-only queries
    553545                $query2 = new WP_Meta_Query( array(
    554546                        'relation' => 'AND',
  • tests/phpunit/tests/post/query.php

    diff --git tests/phpunit/tests/post/query.php tests/phpunit/tests/post/query.php
    index 250f132..adf683c 100644
    class Tests_Post_Query extends WP_UnitTestCase { 
    647647        }
    648648
    649649        /**
     650         * @ticket 24093
     651         */
     652        public function test_meta_query_relation_or_compare_equals() {
     653                $posts = $this->factory->post->create_many( 4 );
     654                add_post_meta( $posts[0], 'color', 'orange' );
     655                add_post_meta( $posts[1], 'color', 'blue' );
     656                add_post_meta( $posts[1], 'vegetable', 'onion' );
     657                add_post_meta( $posts[2], 'vegetable', 'shallot' );
     658
     659                $query = new WP_Query( array(
     660                        'meta_query' => array(
     661                                'relation' => 'OR',
     662                                array(
     663                                        'key' => 'vegetable',
     664                                        'value' => 'onion',
     665                                        'compare' => '=',
     666                                ),
     667                                array(
     668                                        'key' => 'vegetable',
     669                                        'value' => 'shallot',
     670                                        'compare' => '=',
     671                                ),
     672                        ),
     673                        'update_post_meta_cache' => false,
     674                        'update_post_term_cache' => false,
     675                        'fields' => 'ids',
     676                ) );
     677
     678                $expected = array( $posts[1], $posts[2] );
     679                $this->assertEqualSets( $expected, $query->posts );
     680        }
     681
     682        /**
     683         * @ticket 24093
     684         */
     685        public function test_meta_query_relation_or_compare_equals_different_keys() {
     686                $posts = $this->factory->post->create_many( 4 );
     687                add_post_meta( $posts[0], 'color', 'orange' );
     688                add_post_meta( $posts[1], 'color', 'blue' );
     689                add_post_meta( $posts[1], 'vegetable', 'onion' );
     690                add_post_meta( $posts[2], 'vegetable', 'shallot' );
     691
     692                $query = new WP_Query( array(
     693                        'meta_query' => array(
     694                                'relation' => 'OR',
     695                                array(
     696                                        'key' => 'vegetable',
     697                                        'value' => 'onion',
     698                                        'compare' => '=',
     699                                ),
     700                                array(
     701                                        'key' => 'color',
     702                                        'value' => 'orange',
     703                                        'compare' => '=',
     704                                ),
     705                        ),
     706                        'update_post_meta_cache' => false,
     707                        'update_post_term_cache' => false,
     708                        'fields' => 'ids',
     709                ) );
     710
     711                $expected = array( $posts[0], $posts[1] );
     712                $this->assertEqualSets( $expected, $query->posts );
     713        }
     714
     715        /**
     716         * @ticket 24093
     717         */
     718        public function test_meta_query_relation_or_compare_equals_and_in() {
     719                $posts = $this->factory->post->create_many( 4 );
     720                add_post_meta( $posts[0], 'color', 'orange' );
     721                add_post_meta( $posts[1], 'color', 'blue' );
     722                add_post_meta( $posts[1], 'vegetable', 'onion' );
     723                add_post_meta( $posts[2], 'vegetable', 'shallot' );
     724
     725                $query = new WP_Query( array(
     726                        'meta_query' => array(
     727                                'relation' => 'OR',
     728                                array(
     729                                        'key' => 'vegetable',
     730                                        'value' => 'onion',
     731                                        'compare' => '=',
     732                                ),
     733                                array(
     734                                        'key' => 'color',
     735                                        'value' => array( 'orange', 'green' ),
     736                                        'compare' => 'IN',
     737                                ),
     738                        ),
     739                        'update_post_meta_cache' => false,
     740                        'update_post_term_cache' => false,
     741                        'fields' => 'ids',
     742                ) );
     743
     744                $expected = array( $posts[0], $posts[1] );
     745                $this->assertEqualSets( $expected, $query->posts );
     746        }
     747
     748        /**
     749         * @ticket 24093
     750         */
     751        public function test_meta_query_relation_or_compare_equals_and_like() {
     752                $posts = $this->factory->post->create_many( 4 );
     753                add_post_meta( $posts[0], 'color', 'orange' );
     754                add_post_meta( $posts[1], 'color', 'blue' );
     755                add_post_meta( $posts[1], 'vegetable', 'onion' );
     756                add_post_meta( $posts[2], 'vegetable', 'shallot' );
     757
     758                $query = new WP_Query( array(
     759                        'meta_query' => array(
     760                                'relation' => 'OR',
     761                                array(
     762                                        'key' => 'vegetable',
     763                                        'value' => 'onion',
     764                                        'compare' => '=',
     765                                ),
     766                                array(
     767                                        'key' => 'vegetable',
     768                                        'value' => 'hall',
     769                                        'compare' => 'LIKE',
     770                                ),
     771                        ),
     772                        'update_post_meta_cache' => false,
     773                        'update_post_term_cache' => false,
     774                        'fields' => 'ids',
     775                ) );
     776
     777                $expected = array( $posts[1], $posts[2] );
     778                $this->assertEqualSets( $expected, $query->posts );
     779        }
     780
     781        /**
     782         * @ticket 24093
     783         */
     784        public function test_meta_query_relation_or_compare_equals_and_between() {
     785                $posts = $this->factory->post->create_many( 4 );
     786                add_post_meta( $posts[0], 'number_of_colors', '2' );
     787                add_post_meta( $posts[1], 'number_of_colors', '5' );
     788                add_post_meta( $posts[1], 'vegetable', 'onion' );
     789                add_post_meta( $posts[2], 'vegetable', 'shallot' );
     790
     791                $query = new WP_Query( array(
     792                        'meta_query' => array(
     793                                'relation' => 'OR',
     794                                array(
     795                                        'key' => 'vegetable',
     796                                        'value' => 'shallot',
     797                                        'compare' => '=',
     798                                ),
     799                                array(
     800                                        'key' => 'number_of_colors',
     801                                        'value' => array( 1, 3 ),
     802                                        'compare' => 'BETWEEN',
     803                                        'type' => 'SIGNED',
     804                                ),
     805                        ),
     806                        'update_post_meta_cache' => false,
     807                        'update_post_term_cache' => false,
     808                        'fields' => 'ids',
     809                ) );
     810
     811                $expected = array( $posts[0], $posts[2] );
     812                $this->assertEqualSets( $expected, $query->posts );
     813        }
     814
     815        /**
     816         * @ticket 24093
     817         */
     818        public function test_meta_query_relation_and_compare_in_same_keys() {
     819                $posts = $this->factory->post->create_many( 4 );
     820                add_post_meta( $posts[0], 'color', 'orange' );
     821                add_post_meta( $posts[1], 'color', 'blue' );
     822                add_post_meta( $posts[1], 'vegetable', 'onion' );
     823                add_post_meta( $posts[2], 'vegetable', 'shallot' );
     824                add_post_meta( $posts[3], 'vegetable', 'banana' );
     825                add_post_meta( $posts[3], 'vegetable', 'onion' );
     826
     827                $query = new WP_Query( array(
     828                        'meta_query' => array(
     829                                'relation' => 'AND',
     830                                array(
     831                                        'key' => 'vegetable',
     832                                        'value' => array( 'onion', 'shallot' ),
     833                                        'compare' => 'IN',
     834                                ),
     835                                array(
     836                                        'key' => 'vegetable',
     837                                        'value' => array( 'banana' ),
     838                                        'compare' => 'IN',
     839                                ),
     840                        ),
     841                        'update_post_meta_cache' => false,
     842                        'update_post_term_cache' => false,
     843                        'fields' => 'ids',
     844                ) );
     845
     846                $expected = array( $posts[3] );
     847                $this->assertEqualSets( $expected, $query->posts );
     848        }
     849
     850        /**
     851         * @ticket 24093
     852         */
     853        public function test_meta_query_relation_and_compare_in_different_keys() {
     854                $posts = $this->factory->post->create_many( 4 );
     855                add_post_meta( $posts[0], 'color', 'orange' );
     856                add_post_meta( $posts[1], 'color', 'blue' );
     857                add_post_meta( $posts[1], 'vegetable', 'onion' );
     858                add_post_meta( $posts[1], 'vegetable', 'shallot' );
     859                add_post_meta( $posts[2], 'vegetable', 'shallot' );
     860                add_post_meta( $posts[3], 'vegetable', 'banana' );
     861
     862                $query = new WP_Query( array(
     863                        'meta_query' => array(
     864                                'relation' => 'AND',
     865                                array(
     866                                        'key' => 'vegetable',
     867                                        'value' => array( 'onion', 'shallot' ),
     868                                        'compare' => 'IN',
     869                                ),
     870                                array(
     871                                        'key' => 'color',
     872                                        'value' => array( 'blue' ),
     873                                        'compare' => 'IN',
     874                                ),
     875                        ),
     876                        'update_post_meta_cache' => false,
     877                        'update_post_term_cache' => false,
     878                        'fields' => 'ids',
     879                ) );
     880
     881                $expected = array( $posts[1] );
     882                $this->assertEqualSets( $expected, $query->posts );
     883        }
     884
     885        /**
     886         * @ticket 24093
     887         */
     888        public function test_meta_query_relation_and_compare_not_equals() {
     889                $posts = $this->factory->post->create_many( 4 );
     890                add_post_meta( $posts[0], 'color', 'orange' );
     891                add_post_meta( $posts[1], 'color', 'blue' );
     892                add_post_meta( $posts[1], 'vegetable', 'onion' );
     893                add_post_meta( $posts[2], 'vegetable', 'shallot' );
     894                add_post_meta( $posts[3], 'vegetable', 'banana' );
     895
     896                $query = new WP_Query( array(
     897                        'meta_query' => array(
     898                                'relation' => 'AND',
     899                                array(
     900                                        'key' => 'vegetable',
     901                                        'value' => 'onion',
     902                                        'compare' => '!=',
     903                                ),
     904                                array(
     905                                        'key' => 'vegetable',
     906                                        'value' => 'shallot',
     907                                        'compare' => '!=',
     908                                ),
     909                        ),
     910                        'update_post_meta_cache' => false,
     911                        'update_post_term_cache' => false,
     912                        'fields' => 'ids',
     913                ) );
     914
     915                $expected = array( $posts[3] );
     916                $this->assertEqualSets( $expected, $query->posts );
     917        }
     918
     919        /**
     920         * @ticket 24093
     921         */
     922        public function test_meta_query_relation_and_compare_not_equals_different_keys() {
     923                $posts = $this->factory->post->create_many( 4 );
     924
     925                // !shallot, but orange.
     926                add_post_meta( $posts[0], 'color', 'orange' );
     927                add_post_meta( $posts[0], 'vegetable', 'onion' );
     928
     929                // !orange, but shallot.
     930                add_post_meta( $posts[1], 'color', 'blue' );
     931                add_post_meta( $posts[1], 'vegetable', 'shallot' );
     932
     933                // Neither.
     934                add_post_meta( $posts[2], 'color', 'blue' );
     935                add_post_meta( $posts[2], 'vegetable', 'onion' );
     936
     937                $query = new WP_Query( array(
     938                        'meta_query' => array(
     939                                'relation' => 'AND',
     940                                array(
     941                                        'key' => 'vegetable',
     942                                        'value' => 'shallot',
     943                                        'compare' => '!=',
     944                                ),
     945                                array(
     946                                        'key' => 'color',
     947                                        'value' => 'orange',
     948                                        'compare' => '!=',
     949                                ),
     950                        ),
     951                        'update_post_meta_cache' => false,
     952                        'update_post_term_cache' => false,
     953                        'fields' => 'ids',
     954                ) );
     955
     956                $expected = array( $posts[2] );
     957                $this->assertEqualSets( $expected, $query->posts );
     958        }
     959
     960        /**
     961         * @ticket 24093
     962         */
     963        public function test_meta_query_relation_and_compare_not_equals_not_in() {
     964                $posts = $this->factory->post->create_many( 4 );
     965                add_post_meta( $posts[0], 'color', 'orange' );
     966                add_post_meta( $posts[1], 'color', 'blue' );
     967                add_post_meta( $posts[1], 'vegetable', 'onion' );
     968                add_post_meta( $posts[2], 'vegetable', 'shallot' );
     969                add_post_meta( $posts[3], 'vegetable', 'banana' );
     970
     971                $query = new WP_Query( array(
     972                        'meta_query' => array(
     973                                'relation' => 'AND',
     974                                array(
     975                                        'key' => 'vegetable',
     976                                        'value' => 'onion',
     977                                        'compare' => '!=',
     978                                ),
     979                                array(
     980                                        'key' => 'vegetable',
     981                                        'value' => array( 'shallot' ),
     982                                        'compare' => 'NOT IN',
     983                                ),
     984                        ),
     985                        'update_post_meta_cache' => false,
     986                        'update_post_term_cache' => false,
     987                        'fields' => 'ids',
     988                ) );
     989
     990                $expected = array( $posts[3] );
     991                $this->assertEqualSets( $expected, $query->posts );
     992        }
     993
     994        /**
     995         * @ticket 24093
     996         */
     997        public function test_meta_query_relation_and_compare_not_equals_and_not_like() {
     998                $posts = $this->factory->post->create_many( 4 );
     999                add_post_meta( $posts[0], 'color', 'orange' );
     1000                add_post_meta( $posts[1], 'color', 'blue' );
     1001                add_post_meta( $posts[1], 'vegetable', 'onion' );
     1002                add_post_meta( $posts[2], 'vegetable', 'shallot' );
     1003                add_post_meta( $posts[3], 'vegetable', 'banana' );
     1004
     1005                $query = new WP_Query( array(
     1006                        'meta_query' => array(
     1007                                'relation' => 'AND',
     1008                                array(
     1009                                        'key' => 'vegetable',
     1010                                        'value' => 'onion',
     1011                                        'compare' => '!=',
     1012                                ),
     1013                                array(
     1014                                        'key' => 'vegetable',
     1015                                        'value' => 'hall',
     1016                                        'compare' => 'NOT LIKE',
     1017                                ),
     1018                        ),
     1019                        'update_post_meta_cache' => false,
     1020                        'update_post_term_cache' => false,
     1021                        'fields' => 'ids',
     1022                ) );
     1023
     1024                $expected = array( $posts[3] );
     1025                $this->assertEqualSets( $expected, $query->posts );
     1026        }
     1027
     1028        /**
    6501029         * @ticket 23033
    6511030         * @group meta
    6521031         */
    class Tests_Post_Query extends WP_UnitTestCase { 
    10401419                $post_id6 = $this->factory->post->create();
    10411420                add_post_meta( $post_id6, 'baz', 0 );
    10421421
    1043                 $posts = get_posts( array( 'meta_key' => 'foo', 'meta_value' => '0' ) );
    1044                 $this->assertEquals( 1, count ( $posts ) );
    1045                 foreach ( $posts as $post ) {
     1422                $q = new WP_Query( array( 'meta_key' => 'foo', 'meta_value' => '0' ) );
     1423                $this->assertEquals( 1, count ( $q->posts ) );
     1424                foreach ( $q->posts as $post ) {
    10461425                        $this->assertInstanceOf( 'WP_Post', $post );
    10471426                        $this->assertEquals( 'raw', $post->filter );
    10481427                }
    1049                 $this->assertEquals( $post_id, $posts[0]->ID );
     1428                $this->assertEquals( $post_id, $q->posts[0]->ID );
    10501429
    10511430                $posts = get_posts( array( 'meta_key' => 'bar', 'meta_value' => '0' ) );
    10521431                $this->assertEquals( 2, count ( $posts ) );