WordPress.org

Make WordPress Core

Ticket #29822: 29822.2.patch

File 29822.2.patch, 20.9 KB (added by boonebgorges, 5 years ago)
  • src/wp-includes/date.php

    diff --git src/wp-includes/date.php src/wp-includes/date.php
    index 1cf4c6d..be57fac 100644
     
    11<?php
    22/**
    3  * WP_Date_Query will generate a MySQL WHERE clause for the specified date-based parameters.
     3 * Class for generating SQL clauses that filter a primary query according to date.
    44 *
    5  * Initialize the class by passing an array of arrays of parameters.
     5 * `WP_Date_Query` is a helper that allows primary query classes, such as {@see WP_Query},
     6 * to filter their results by date columns, by generating `WHERE` subclauses to be attached
     7 * to the primary SQL query string.
    68 *
    79 * @link http://codex.wordpress.org/Function_Reference/WP_Query Codex page.
    810 *
     
    1012 */
    1113class WP_Date_Query {
    1214        /**
    13          * List of date queries.
     15         * Array of date queries.
     16         *
     17         * See {@see WP_Date_Query::__construct()} for information on date query arguments.
    1418         *
    1519         * @since 3.7.0
    1620         * @access public
    class WP_Date_Query { 
    1923        public $queries = array();
    2024
    2125        /**
    22          * The relation between the queries. Can be either 'AND' or 'OR' and can be changed via the query arguments.
     26         * The default relation between top-level queries. Can be either 'AND' or 'OR'.
    2327         *
    2428         * @since 3.7.0
    2529         * @access public
    class WP_Date_Query { 
    4650        public $compare = '=';
    4751
    4852        /**
     53         * Supported time-related parameter keys.
     54         *
     55         * @since 4.1.0
     56         * @access public
     57         * @var array
     58         */
     59        public $time_keys = array( 'after', 'before', 'year', 'month', 'monthnum', 'week', 'w', 'dayofyear', 'day', 'dayofweek', 'hour', 'minute', 'second' );
     60
     61        /**
    4962         * Constructor.
    5063         *
    5164         * @since 3.7.0
    5265         * @since 4.0.0 The $inclusive logic was updated to include all times within the date range.
     66         * @access public
    5367         *
    5468         * @param array $date_query {
    55          *     One or more associative arrays of date query parameters.
     69         *     Array of date query clauses.
    5670         *
    5771         *     @type array {
    5872         *         @type string $column   Optional. The column to query against. If undefined, inherits the value of
    class WP_Date_Query { 
    6074         *                                'post_date_gmt', 'post_modified','post_modified_gmt', 'comment_date',
    6175         *                                'comment_date_gmt'.
    6276         *         @type string $compare  Optional. The comparison operator.
    63          *                                Default '='. Accepts '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN',
     77         *                                Accepts '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', Default '='.
    6478         *                                'BETWEEN', 'NOT BETWEEN'.
    65          *         @type string $relation Optional. The boolean relationship between the date queryies.
    66          *                                Default 'OR'. Accepts 'OR', 'AND'.
     79         *         @type string $relation Optional. The boolean relationship between the date queries.
     80         *                                Accepts 'OR', 'AND'. Default 'OR'.
    6781         *         @type array {
     82                       Optional. An array of first-order clause parameters, or another fully-formed date query.
    6883         *             @type string|array $before Optional. Date to retrieve posts before. Accepts strtotime()-compatible
    6984         *                                        string, or array of 'year', 'month', 'day' values. {
    7085         *
    class WP_Date_Query { 
    109124         *                              'comment_date', 'comment_date_gmt'.
    110125         */
    111126        public function __construct( $date_query, $default_column = 'post_date' ) {
    112                 if ( empty( $date_query ) || ! is_array( $date_query ) )
    113                         return;
    114127
    115                 if ( isset( $date_query['relation'] ) && strtoupper( $date_query['relation'] ) == 'OR' )
     128                if ( isset( $date_query['relation'] ) && 'OR' === strtoupper( $date_query['relation'] ) ) {
    116129                        $this->relation = 'OR';
    117                 else
     130                } else {
    118131                        $this->relation = 'AND';
     132                }
    119133
    120                 if ( ! empty( $date_query['column'] ) )
    121                         $this->column = esc_sql( $date_query['column'] );
    122                 else
    123                         $this->column = esc_sql( $default_column );
     134                if ( ! is_array( $date_query ) ) {
     135                        return;
     136                }
     137
     138                // Support for passing time-based keys in the top level of the $date_query array.
     139                if ( ! isset( $date_query[0] ) && ! empty( $date_query ) ) {
     140                        $date_query = array( $date_query );
     141                }
     142
     143                if ( empty( $date_query ) ) {
     144                        return;
     145                }
     146
     147                if ( ! empty( $date_query['column'] ) ) {
     148                        $date_query['column'] = esc_sql( $date_query['column'] );
     149                } else {
     150                        $date_query['column'] = esc_sql( $default_column );
     151                }
    124152
    125153                $this->column = $this->validate_column( $this->column );
    126154
    127155                $this->compare = $this->get_compare( $date_query );
    128156
    129                 // If an array of arrays wasn't passed, fix it
    130                 if ( ! isset( $date_query[0] ) )
    131                         $date_query = array( $date_query );
     157                $this->queries = $this->sanitize_query( $date_query );
     158
     159                return;
     160        }
     161
     162        /**
     163         * Recursive-friendly query sanitizer.
     164         *
     165         * Ensures that each query-level clause has a 'relation' key, and that
     166         * each first-order clause contains all the necessary keys from
     167         * $defaults.
     168         *
     169         * @since 4.1.0
     170         * @access public
     171         *
     172         * @param  array $query A tax_query query clause.
     173         * @return array Sanitized queries.
     174         */
     175        public function sanitize_query( $queries, $parent_query = null ) {
     176                $cleaned_query = array();
     177
     178                $defaults = array(
     179                        'column' => 'post_date',
     180                        'compare' => '=',
     181                        'relation' => 'AND',
     182                );
    132183
    133                 $this->queries = array();
    134                 foreach ( $date_query as $key => $query ) {
    135                         if ( ! is_array( $query ) )
     184                // Numeric keys should always have array values.
     185                foreach ( $queries as $qkey => $qvalue ) {
     186                        if ( is_numeric( $qkey ) && ! is_array( $qvalue ) ) {
     187                                unset( $queries[ $qkey ] );
     188                        }
     189                }
     190
     191                // Each query should have a value for each default key. Inherit from the parent when possible.
     192                foreach ( $defaults as $dkey => $dvalue ) {
     193                        if ( isset( $queries[ $dkey ] ) ) {
    136194                                continue;
     195                        }
    137196
    138                         $this->queries[$key] = $query;
     197                        if ( isset( $parent_query[ $dkey ] ) ) {
     198                                $queries[ $dkey ] = $parent_query[ $dkey ];
     199                        } else {
     200                                $queries[ $dkey ] = $dvalue;
     201                        }
    139202                }
     203
     204                foreach ( $queries as $key => $q ) {
     205                        if ( ! is_array( $q ) || in_array( $key, $this->time_keys, true ) ) {
     206                                $cleaned_query[ $key ] = $q;
     207                        } else {
     208                                // Any array without a time key is another query, so we recurse.
     209                                $cleaned_query[] = $this->sanitize_query( $q, $queries );
     210                        }
     211                }
     212
     213                return $cleaned_query;
     214        }
     215
     216        /**
     217         * Determine whether this is a first-order clause.
     218         *
     219         * Essentially, this checks to see if the current clause has any time-
     220         * related keys. If so, it's first-order.
     221         *
     222         * @param  array $query Query clause.
     223         * @return bool True if this is a first-order clause.
     224         */
     225        protected function is_first_order_clause( $query ) {
     226                $time_keys = array_intersect( $this->time_keys, array_keys( $query ) );
     227                return ! empty( $time_keys );
    140228        }
    141229
    142230        /**
    class WP_Date_Query { 
    145233         * @since 3.7.0
    146234         * @access public
    147235         *
    148          * @param array $query A date query or a date subquery
    149          * @return string The comparison operator
     236         * @param array $query A date query or a date subquery.
     237         * @return string The comparison operator.
    150238         */
    151239        public function get_compare( $query ) {
    152240                if ( ! empty( $query['compare'] ) && in_array( $query['compare'], array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) )
    class WP_Date_Query { 
    184272        }
    185273
    186274        /**
    187          * Turns an array of date query parameters into a MySQL string.
     275         * Generate WHERE clause to be appended to a main query.
    188276         *
    189277         * @since 3.7.0
    190278         * @access public
    191279         *
    192          * @return string MySQL WHERE parameters
     280         * @return string MySQL WHERE clause.
    193281         */
    194282        public function get_sql() {
    195                 // The parts of the final query
    196                 $where = array();
    197 
    198                 foreach ( $this->queries as $key => $query ) {
    199                         $where_parts = $this->get_sql_for_subquery( $query );
    200                         if ( $where_parts ) {
    201                                 // Combine the parts of this subquery into a single string
    202                                 $where[ $key ] = '( ' . implode( ' AND ', $where_parts ) . ' )';
    203                         }
    204                 }
     283                $sql = $this->get_sql_clauses();
    205284
    206                 // Combine the subquery strings into a single string
    207                 if ( $where )
    208                         $where = ' AND ( ' . implode( " {$this->relation} ", $where ) . ' )';
    209                 else
    210                         $where = '';
     285                $where = $sql['where'];
    211286
    212287                /**
    213288                 * Filter the date query WHERE clause.
    class WP_Date_Query { 
    221296        }
    222297
    223298        /**
    224          * Turns a single date subquery into pieces for a WHERE clause.
     299         * Generate SQL clauses to be appended to a main query.
    225300         *
    226          * @since 3.7.0
    227          * return array
     301         * Called by the public {@see WP_Date_Query::get_sql()}, this method
     302         * is abstracted out to maintain parity with the other Query classes.
     303         *
     304         * @since 4.1.0
     305         * @access protected
     306         *
     307         * @return array {
     308         *     Array containing JOIN and WHERE SQL clauses to append to the main query.
     309         *
     310         *     @type string $join  SQL fragment to append to the main JOIN clause.
     311         *     @type string $where SQL fragment to append to the main WHERE clause.
     312         * }
     313         */
     314        protected function get_sql_clauses() {
     315                $sql = $this->get_sql_for_query( $this->queries );
     316
     317                if ( ! empty( $sql['where'] ) ) {
     318                        $sql['where'] = ' AND ' . $sql['where'];
     319                }
     320
     321                return $sql;
     322        }
     323
     324        /**
     325         * Generate SQL clauses for a single query array.
     326         *
     327         * If nested subqueries are found, this method recurses the tree to
     328         * produce the properly nested SQL.
     329         *
     330         * @since 4.1.0
     331         * @access protected
     332         *
     333         * @param array $query Query to parse.
     334         * @param int   $depth Optional. Number of tree levels deep we currently are.
     335         *                     Used to calculate indentation.
     336         * @return array {
     337         *     Array containing JOIN and WHERE SQL clauses to append to a single query array.
     338         *
     339         *     @type string $join  SQL fragment to append to the main JOIN clause.
     340         *     @type string $where SQL fragment to append to the main WHERE clause.
     341         * }
     342         */
     343        protected function get_sql_for_query( $query, $depth = 0 ) {
     344                $sql_chunks = array(
     345                        'join'  => array(),
     346                        'where' => array(),
     347                );
     348
     349                $sql = array(
     350                        'join'  => '',
     351                        'where' => '',
     352                );
     353
     354                $indent = '';
     355                for ( $i = 0; $i < $depth; $i++ ) {
     356                        $indent .= "  ";
     357                }
     358
     359                foreach ( $query as $key => $clause ) {
     360                        if ( 'relation' === $key ) {
     361                                $relation = $query['relation'];
     362                        } else if ( is_array( $clause ) ) {
     363
     364                                // This is a first-order clause.
     365                                if ( $this->is_first_order_clause( $clause ) ) {
     366                                        $clause_sql = $this->get_sql_for_clause( $clause, $query );
     367
     368                                        $where_count = count( $clause_sql['where'] );
     369                                        if ( ! $where_count ) {
     370                                                $sql_chunks['where'][] = '';
     371                                        } else if ( 1 === $where_count ) {
     372                                                $sql_chunks['where'][] = $clause_sql['where'][0];
     373                                        } else {
     374                                                $sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )';
     375                                        }
     376
     377                                        $sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] );
     378                                // This is a subquery, so we recurse.
     379                                } else {
     380                                        $clause_sql = $this->get_sql_for_query( $clause, $depth + 1 );
     381
     382                                        $sql_chunks['where'][] = $clause_sql['where'];
     383                                        $sql_chunks['join'][]  = $clause_sql['join'];
     384                                }
     385                        }
     386                }
     387
     388                // Filter to remove empties.
     389                $sql_chunks['join']  = array_filter( $sql_chunks['join'] );
     390                $sql_chunks['where'] = array_filter( $sql_chunks['where'] );
     391
     392                if ( empty( $relation ) ) {
     393                        $relation = 'AND';
     394                }
     395
     396                // Filter duplicate JOIN clauses and combine into a single string.
     397                if ( ! empty( $sql_chunks['join'] ) ) {
     398                        $sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) );
     399                }
     400
     401                // Generate a single WHERE clause with proper brackets and indentation.
     402                if ( ! empty( $sql_chunks['where'] ) ) {
     403                        $sql['where'] = '( ' . "\n  " . $indent . implode( ' ' . "\n  " . $indent . $relation . ' ' . "\n  " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')';
     404                }
     405
     406                return $sql;
     407        }
     408
     409        /**
     410         * Turns a single date clause into pieces for a WHERE clause.
     411         *
     412         * A wrapper for get_sql_for_clause(), included here for backward
     413         * compatibility while retaining the naming convention across Query classes.
     414         *
     415         * @since  3.7.0
     416         * @access protected
     417         *
     418         * @param  array $query Date query arguments.
     419         * @return array {
     420         *     Array containing JOIN and WHERE SQL clauses to append to the main query.
     421         *
     422         *     @type string $join  SQL fragment to append to the main JOIN clause.
     423         *     @type string $where SQL fragment to append to the main WHERE clause.
     424         * }
    228425         */
    229426        protected function get_sql_for_subquery( $query ) {
     427                return $this->get_sql_for_clause( $query, '' );
     428        }
     429
     430        /**
     431         * Turns a first-order date query into SQL for a WHERE clause.
     432         *
     433         * @since  4.1.0
     434         * @access protected
     435         *
     436         * @param  array $query        Date query clause.
     437         * @param  array $parent_query Parent query of the current date query.
     438         * @return array {
     439         *     Array containing JOIN and WHERE SQL clauses to append to the main query.
     440         *
     441         *     @type string $join  SQL fragment to append to the main JOIN clause.
     442         *     @type string $where SQL fragment to append to the main WHERE clause.
     443         * }
     444         */
     445        protected function get_sql_for_clause( $query, $parent_query ) {
    230446                global $wpdb;
    231447
    232                 // The sub-parts of a $where part
     448                // The sub-parts of a $where part.
    233449                $where_parts = array();
    234450
    235451                $column = ( ! empty( $query['column'] ) ) ? esc_sql( $query['column'] ) : $this->column;
    class WP_Date_Query { 
    249465                        $gt .= '=';
    250466                }
    251467
    252                 // Range queries
     468                // Range queries.
    253469                if ( ! empty( $query['after'] ) )
    254470                        $where_parts[] = $wpdb->prepare( "$column $gt %s", $this->build_mysql_datetime( $query['after'], ! $inclusive ) );
    255471
    256472                if ( ! empty( $query['before'] ) )
    257473                        $where_parts[] = $wpdb->prepare( "$column $lt %s", $this->build_mysql_datetime( $query['before'], $inclusive ) );
    258474
    259                 // Specific value queries
     475                // Specific value queries.
    260476
    261477                if ( isset( $query['year'] ) && $value = $this->build_value( $compare, $query['year'] ) )
    262478                        $where_parts[] = "YEAR( $column ) $compare $value";
    class WP_Date_Query { 
    281497                        $where_parts[] = "DAYOFWEEK( $column ) $compare $value";
    282498
    283499                if ( isset( $query['hour'] ) || isset( $query['minute'] ) || isset( $query['second'] ) ) {
    284                         // Avoid notices
     500                        // Avoid notices.
    285501                        foreach ( array( 'hour', 'minute', 'second' ) as $unit ) {
    286                                 if ( ! isset( $query[$unit] ) ) {
    287                                         $query[$unit] = null;
     502                                if ( ! isset( $query[ $unit ] ) ) {
     503                                        $query[ $unit ] = null;
    288504                                }
    289505                        }
    290506
    class WP_Date_Query { 
    293509                        }
    294510                }
    295511
    296                 return $where_parts;
     512                /*
     513                 * Return an array of 'join' and 'where' for compatibility
     514                 * with other query classes.
     515                 */
     516                return array(
     517                        'where' => $where_parts,
     518                        'join'  => array(),
     519                );
    297520        }
    298521
    299522        /**
  • tests/phpunit/tests/date/query.php

    diff --git tests/phpunit/tests/date/query.php tests/phpunit/tests/date/query.php
    index e9dd191..e87e917 100644
    class Tests_WP_Date_Query extends WP_UnitTestCase { 
    5555                                        'year' => 2008,
    5656                                        'month' => 6,
    5757                                ),
     58                                'column' => 'post_date',
     59                                'compare' => '=',
     60                                'relation' => 'AND',
    5861                        ),
     62                        'column' => 'post_date',
     63                        'compare' => '=',
     64                        'relation' => 'AND',
    5965                );
    6066
    6167                $this->assertSame( $expected, $q->queries );
    class Tests_WP_Date_Query extends WP_UnitTestCase { 
    7379                        ),
    7480                ) );
    7581
    76                 // Note: WP_Date_Query does not reset indexes
    7782                $expected = array(
    78                         2 => array(
     83                        array(
    7984                                'before' => array(
    8085                                        'year' => 2008,
    8186                                        'month' => 6,
    8287                                ),
     88                                'column' => 'post_date',
     89                                'compare' => '=',
     90                                'relation' => 'AND',
    8391                        ),
     92                        'column' => 'post_date',
     93                        'compare' => '=',
     94                        'relation' => 'AND',
    8495                );
    8596
    86                 $this->assertSame( $expected, $q->queries );
     97                $this->assertEquals( $expected, $q->queries );
    8798        }
    8899
    89100        public function test_get_compare_empty() {
  • tests/phpunit/tests/query/dateQuery.php

    diff --git tests/phpunit/tests/query/dateQuery.php tests/phpunit/tests/query/dateQuery.php
    index 759a40a..9654c83 100644
    class Tests_Query_DateQuery extends WP_UnitTestCase { 
    629629
    630630                $this->assertEquals( $expected_dates, wp_list_pluck( $posts, 'post_date' ) );
    631631
    632                 $this->assertContains( "AND ( ( MONTH( post_date ) = 5 ) ) AND", $this->q->request );
    633 
    634                 $this->assertNotContains( "AND ( ( MONTH( post_date ) = 5 AND MONTH( post_date ) = 9 ) ) AND", $this->q->request );
     632                $this->assertContains( "MONTH( post_date ) = 5", $this->q->request );
     633                $this->assertNotContains( "MONTH( post_date ) = 9", $this->q->request );
    635634        }
    636635
    637636        public function test_date_params_week_w_duplicate() {
    class Tests_Query_DateQuery extends WP_UnitTestCase { 
    653652
    654653                $this->assertEquals( $expected_dates, wp_list_pluck( $posts, 'post_date' ) );
    655654
    656                 $this->assertContains( "AND ( ( WEEK( post_date, 1 ) = 21 ) ) AND", $this->q->request );
     655                $this->assertContains( "WEEK( post_date, 1 ) = 21", $this->q->request );
     656                $this->assertNotContains( "WEEK( post_date, 1 ) = 22", $this->q->request );
     657        }
     658
     659        /**
     660         * @ticket 29822
     661         */
     662        public function test_date_query_one_nested_query() {
     663                $this->create_posts();
     664
     665                $posts = $this->_get_query_result( array(
     666                        'date_query' => array(
     667                                'relation' => 'OR',
     668                                array(
     669                                        'relation' => 'AND',
     670                                        array(
     671                                                'year' => 2004,
     672                                        ),
     673                                        array(
     674                                                'month' => 1,
     675                                        ),
     676                                ),
     677                                array(
     678                                        'year' => 1984,
     679                                ),
     680                        ),
     681                ) );
     682
     683                $expected_dates = array(
     684                        '1984-07-28 19:28:56',
     685                        '2004-01-03 08:54:10',
     686                );
     687
     688                $this->assertEquals( $expected_dates, wp_list_pluck( $posts, 'post_date' ) );
     689        }
     690
     691        /**
     692         * @ticket 29822
     693         */
     694        public function test_date_query_one_nested_query_multiple_columns_relation_and() {
     695                $p1 = $this->factory->post->create( array(
     696                        'post_date' => '2012-03-05 15:30:55',
     697                ) );
     698                $this->update_post_modified( $p1, '2014-11-03 14:43:00' );
     699
     700                $p2 = $this->factory->post->create( array(
     701                        'post_date' => '2012-05-05 15:30:55',
     702                ) );
     703                $this->update_post_modified( $p2, '2014-10-03 14:43:00' );
     704
     705                $p3 = $this->factory->post->create( array(
     706                        'post_date' => '2013-05-05 15:30:55',
     707                ) );
     708                $this->update_post_modified( $p3, '2014-10-03 14:43:00' );
     709
     710                $p4 = $this->factory->post->create( array(
     711                        'post_date' => '2012-02-05 15:30:55',
     712                ) );
     713                $this->update_post_modified( $p4, '2012-12-03 14:43:00' );
     714
     715                $q = new WP_Query( array(
     716                        'date_query' => array(
     717                                'relation' => 'AND',
     718                                array(
     719                                        'column' => 'post_date',
     720                                        array(
     721                                                'year' => 2012,
     722                                        ),
     723                                ),
     724                                array(
     725                                        'column' => 'post_modified',
     726                                        array(
     727                                                'year' => 2014,
     728                                        ),
     729                                ),
     730                        ),
     731                        'fields' => 'ids',
     732                        'update_post_meta_cache' => false,
     733                        'update_post_term_cache' => false,
     734                        'post_status' => 'publish',
     735                ) );
     736
     737                $expected = array( $p1, $p2, );
    657738
    658                 $this->assertNotContains( "AND ( ( WEEK( post_date, 1 ) = 21 AND WEEK( post_date, 1 ) = 22 ) ) AND", $this->q->request );
     739                $this->assertEqualSets( $expected, $q->posts );
     740        }
     741
     742        /**
     743         * @ticket 29822
     744         */
     745        public function test_date_query_nested_query_multiple_columns_mixed_relations() {
     746                $p1 = $this->factory->post->create( array(
     747                        'post_date' => '2012-03-05 15:30:55',
     748                ) );
     749                $this->update_post_modified( $p1, '2014-11-03 14:43:00' );
     750
     751                $p2 = $this->factory->post->create( array(
     752                        'post_date' => '2012-05-05 15:30:55',
     753                ) );
     754                $this->update_post_modified( $p2, '2014-10-03 14:43:00' );
     755
     756                $p3 = $this->factory->post->create( array(
     757                        'post_date' => '2013-05-05 15:30:55',
     758                ) );
     759                $this->update_post_modified( $p3, '2014-10-03 14:43:00' );
     760
     761                $p4 = $this->factory->post->create( array(
     762                        'post_date' => '2012-02-05 15:30:55',
     763                ) );
     764                $this->update_post_modified( $p4, '2012-12-03 14:43:00' );
     765
     766                $p5 = $this->factory->post->create( array(
     767                        'post_date' => '2014-02-05 15:30:55',
     768                ) );
     769                $this->update_post_modified( $p5, '2013-12-03 14:43:00' );
     770
     771                $q = new WP_Query( array(
     772                        'date_query' => array(
     773                                'relation' => 'OR',
     774                                array(
     775                                        'relation' => 'AND',
     776                                        array(
     777                                                'column' => 'post_date',
     778                                                array(
     779                                                        'day' => 05,
     780                                                ),
     781                                        ),
     782                                        array(
     783                                                'column' => 'post_date',
     784                                                array(
     785                                                        'before' => array(
     786                                                                'year' => 2012,
     787                                                                'month' => 4,
     788                                                        ),
     789                                                ),
     790                                        ),
     791                                ),
     792                                array(
     793                                        'column' => 'post_modified',
     794                                        array(
     795                                                'month' => 12,
     796                                        ),
     797                                ),
     798                        ),
     799                        'fields' => 'ids',
     800                        'update_post_meta_cache' => false,
     801                        'update_post_term_cache' => false,
     802                        'post_status' => 'publish',
     803                ) );
     804
     805                $expected = array( $p1, $p4, $p5, );
     806                $this->assertEqualSets( $expected, $q->posts );
    659807        }
    660808
    661809        /** Helpers **********************************************************/
    class Tests_Query_DateQuery extends WP_UnitTestCase { 
    692840                        $this->factory->post->create( array( 'post_date' => $post_date ) );
    693841                }
    694842        }
     843
     844        /**
     845         * There's no way to change post_modified through the API.
     846         */
     847        protected function update_post_modified( $post_id, $date ) {
     848                global $wpdb;
     849                return $wpdb->update(
     850                        $wpdb->posts,
     851                        array(
     852                                'post_modified' => $date,
     853                                'post_modified_gmt' => $date,
     854                        ),
     855                        array(
     856                                'ID' => $post_id,
     857                        ),
     858                        array(
     859                                '%s',
     860                                '%s',
     861                        ),
     862                        array(
     863                                '%d',
     864                        )
     865                );
     866        }
    695867}