Ticket #29822: 29822.patch
File 29822.patch, 26.1 KB (added by , 11 years ago) |
---|
-
new file src/wp-includes/class-wp-recursive-query.php
diff --git src/wp-includes/class-wp-recursive-query.php src/wp-includes/class-wp-recursive-query.php new file mode 100644 index 0000000..5fec3f5
- + 1 <?php 2 3 /** 4 * Base class for creating query classes that generate SQL fragments for filtering results based on recursive query params. 5 * 6 * @since 4.1.0 7 */ 8 abstract class WP_Recursive_Query { 9 10 /** 11 * Query arguments passed to the constructor. 12 * 13 * @since 4.1.0 14 * @access public 15 * @var array 16 */ 17 public $queries = array(); 18 19 /** 20 * A flat list of table aliases used in JOIN clauses. 21 * 22 * @since 4.1.0 23 * @access protected 24 * @var array 25 */ 26 protected $table_aliases = array(); 27 28 /** 29 * Generate SQL clauses to be appended to a main query. 30 * 31 * Extending classes should call this method from within a publicly 32 * accessible get_sql() method, and manipulate the SQL as necessary. 33 * For example, {@link WP_Tax_Query::get_sql()} is merely a wrapper for 34 * get_sql_clauses(), while {@link WP_Date_Query::get_sql()} discards 35 * the empty 'join' clauses are discarded, and passes the 'where' 36 * clause through apply_filters(). 37 * 38 * @since 4.1.0 39 * @access protected 40 * 41 * @param string $primary_table 42 * @param string $primary_id_column 43 * @return array 44 */ 45 protected function get_sql_clauses() { 46 $sql = $this->get_sql_for_query( $this->queries ); 47 48 if ( ! empty( $sql['where'] ) ) { 49 $sql['where'] = ' AND ' . "\n" . $sql['where'] . "\n"; 50 } 51 52 return $sql; 53 } 54 55 /** 56 * Generate SQL clauses for a single query array. 57 * 58 * If nested subqueries are found, this method recurses the tree to 59 * produce the properly nested SQL. 60 * 61 * Subclasses generally do not need to call this method. It is invoked 62 * automatically from get_sql_clauses(). 63 * 64 * @since 4.1.0 65 * @access protected 66 * 67 * @param array $query Query to parse. 68 * @param int $depth Optional. Number of tree levels deep we 69 * currently are. Used to calculate indentation. 70 * @return array 71 */ 72 protected function get_sql_for_query( $query, $depth = 0 ) { 73 $sql_chunks = array( 74 'join' => array(), 75 'where' => array(), 76 ); 77 78 $sql = array( 79 'join' => '', 80 'where' => '', 81 ); 82 83 $indent = ''; 84 for ( $i = 0; $i < $depth; $i++ ) { 85 $indent .= "\t"; 86 } 87 88 foreach ( $query as $key => $clause ) { 89 if ( 'relation' === $key ) { 90 $relation = $query['relation']; 91 } else if ( is_array( $clause ) ) { 92 // This is a first-order clause 93 if ( $this->is_first_order_clause( $clause ) ) { 94 $clause_sql = $this->get_sql_for_clause( $clause, $query ); 95 96 $where_count = count( $clause_sql['where'] ); 97 if ( ! $where_count ) { 98 $sql_chunks['where'][] = ''; 99 } else if ( 1 === $where_count ) { 100 $sql_chunks['where'][] = $clause_sql['where'][0]; 101 } else { 102 $sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )'; 103 } 104 105 $sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] ); 106 // This is a subquery 107 } else { 108 $clause_sql = $this->get_sql_for_query( $clause, $depth + 1 ); 109 110 $sql_chunks['where'][] = $clause_sql['where']; 111 $sql_chunks['join'][] = $clause_sql['join']; 112 113 } 114 } 115 } 116 117 // Filter empties 118 $sql_chunks['join'] = array_filter( $sql_chunks['join'] ); 119 $sql_chunks['where'] = array_filter( $sql_chunks['where'] ); 120 121 if ( empty( $relation ) ) { 122 $relation = 'AND'; 123 } 124 125 if ( ! empty( $sql_chunks['join'] ) ) { 126 $sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) ); 127 } 128 129 if ( ! empty( $sql_chunks['where'] ) ) { 130 $sql['where'] = '( ' . "\n\t" . $indent . implode( ' ' . "\n\t" . $indent . $relation . ' ' . "\n\t" . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')' . "\n"; 131 } 132 133 return $sql; 134 } 135 136 /** 137 * Generate JOIN and WHERE clauses for a first-order clause. 138 * 139 * Must be overridden in a subclass. 140 * 141 * @since 4.1.0 142 * @access protected 143 * 144 * @param array $clause Array of arguments belonging to the clause. 145 * @param array $parent_query Parent query to which the clause belongs. 146 * @return array { 147 * @type array $join Array of subclauses for the JOIN statement. 148 * @type array $where Array of subclauses for the WHERE statement. 149 * } 150 */ 151 abstract protected function get_sql_for_clause( $clause, $parent_query ); 152 153 /** 154 * Determine whether a clause is first-order. 155 * 156 * Must be overridden in a subclass. 157 * 158 * @since 4.1.0 159 * @access protected 160 * 161 * @param array $q Clause to check. 162 * @return bool 163 */ 164 abstract protected function is_first_order_clause( $query ); 165 } -
src/wp-includes/date.php
diff --git src/wp-includes/date.php src/wp-includes/date.php index 1cf4c6d..b3e3ffe 100644
8 8 * 9 9 * @since 3.7.0 10 10 */ 11 class WP_Date_Query { 12 /** 13 * List of date queries. 14 * 15 * @since 3.7.0 16 * @access public 17 * @var array 18 */ 19 public $queries = array(); 11 class WP_Date_Query extends WP_Recursive_Query { 20 12 21 13 /** 22 * The relation between the queries. Can be either 'AND' or 'OR' and can be changed via the query arguments.14 * The column to query against. Can be changed via the query arguments. 23 15 * 24 16 * @since 3.7.0 25 17 * @access public 26 18 * @var string 27 19 */ 28 public $ relation = 'AND';20 public $column = 'post_date'; 29 21 30 22 /** 31 * The column to query against. Can be changed via the query arguments.23 * The value comparison operator. Can be changed via the query arguments. 32 24 * 33 25 * @since 3.7.0 34 26 * @access public 35 * @var string27 * @var array 36 28 */ 37 public $co lumn = 'post_date';29 public $compare = '='; 38 30 39 31 /** 40 * The value comparison operator. Can be changed via the query arguments.32 * Supported time-related parameter keys. 41 33 * 42 * @since 3.7.034 * @since 4.1.0 43 35 * @access public 44 36 * @var array 45 37 */ 46 public $compare = '='; 38 public $time_keys = array( 'after', 'before', 'year', 'month', 'monthnum', 'week', 'w', 'dayofyear', 'day', 'dayofweek', 'hour', 'minute', 'second' ); 39 47 40 48 41 /** 49 42 * Constructor. … … class WP_Date_Query { 109 102 * 'comment_date', 'comment_date_gmt'. 110 103 */ 111 104 public function __construct( $date_query, $default_column = 'post_date' ) { 112 if ( empty( $date_query ) || ! is_array( $date_query ) )113 return;114 105 115 if ( isset( $date_query['relation'] ) && strtoupper( $date_query['relation'] ) == 'OR' )106 if ( isset( $date_query['relation'] ) && 'OR' === strtoupper( $date_query['relation'] ) ) { 116 107 $this->relation = 'OR'; 117 else108 } else { 118 109 $this->relation = 'AND'; 110 } 119 111 120 if ( ! empty( $date_query['column'] ) ) 121 $this->column = esc_sql( $date_query['column'] ); 122 else 123 $this->column = esc_sql( $default_column ); 112 if ( ! is_array( $date_query ) ) { 113 return; 114 } 115 116 if ( ! isset( $date_query[0] ) && ! empty( $date_query ) ) { 117 $date_query = array( $date_query ); 118 } 119 120 if ( empty( $date_query ) ) { 121 return; 122 } 123 124 if ( ! empty( $date_query['column'] ) ) { 125 $date_query['column'] = esc_sql( $date_query['column'] ); 126 } else { 127 $date_query['column'] = esc_sql( $default_column ); 128 } 124 129 125 130 $this->column = $this->validate_column( $this->column ); 126 131 127 132 $this->compare = $this->get_compare( $date_query ); 128 133 129 // If an array of arrays wasn't passed, fix it 130 if ( ! isset( $date_query[0] ) ) 131 $date_query = array( $date_query ); 134 $this->queries = $this->sanitize_query( $date_query ); 135 136 return; 137 } 132 138 133 $this->queries = array(); 134 foreach ( $date_query as $key => $query ) { 135 if ( ! is_array( $query ) ) 139 /** 140 * Recursive-friendly query sanitizer. 141 * 142 * Ensures that each query-level clause has a 'relation' key, and that 143 * each first-order clause contains all the necessary keys from 144 * $defaults. 145 * 146 * @since 4.1.0 147 * 148 * @param array $query A tax_query query clause. 149 * @return array 150 */ 151 protected function sanitize_query( $query, $parent_query = null ) { 152 $sanitized_query = array(); 153 154 $defaults = array( 155 'column' => 'post_date', 156 'compare' => '=', 157 'relation' => 'AND', 158 ); 159 160 // Numeric keys should always have array values. 161 foreach ( $query as $qkey => $qvalue ) { 162 if ( is_numeric( $qkey ) && ! is_array( $qvalue ) ) { 163 unset( $query[ $qkey ] ); 164 } 165 } 166 167 // Each layer of query should have a value for each default key. 168 foreach ( $defaults as $dkey => $dvalue ) { 169 if ( isset( $query[ $dkey ] ) ) { 136 170 continue; 171 } 137 172 138 $this->queries[$key] = $query; 173 if ( isset( $parent_query[ $dkey ] ) ) { 174 $query[ $dkey ] = $parent_query[ $dkey ]; 175 } else { 176 $query[ $dkey ] = $dvalue; 177 } 139 178 } 179 180 foreach ( $query as $key => $q ) { 181 if ( ! is_array( $q ) || in_array( $key, $this->time_keys, true ) ) { 182 $sanitized_query[ $key ] = $q; 183 } else { 184 $sanitized_query[] = $this->sanitize_query( $q, $query ); 185 } 186 } 187 188 return $sanitized_query; 140 189 } 141 190 142 191 /** … … class WP_Date_Query { 192 241 * @return string MySQL WHERE parameters 193 242 */ 194 243 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 } 244 $sql = $this->get_sql_clauses(); 205 245 206 // Combine the subquery strings into a single string 207 if ( $where ) 208 $where = ' AND ( ' . implode( " {$this->relation} ", $where ) . ' )'; 209 else 210 $where = ''; 246 $where = $sql['where']; 211 247 212 248 /** 213 249 * Filter the date query WHERE clause. … … class WP_Date_Query { 221 257 } 222 258 223 259 /** 224 * Turns a single date subqueryinto pieces for a WHERE clause.260 * Turns a single date clause into pieces for a WHERE clause. 225 261 * 226 * @since 3.7.0 227 * return array 262 * A wrapper for get_sql_for_clause(), included here for backward 263 * compatibility while retaining the naming convention across Query 264 * classes. 265 * 266 * @since 3.7.0 267 * @access protected 268 * 269 * @param array $query Date query arguments. 270 * @return array 228 271 */ 229 272 protected function get_sql_for_subquery( $query ) { 273 return $this->get_sql_for_clause( $query, '' ); 274 } 275 276 /** 277 * Turns a single date clause into pieces for a WHERE clause. 278 * 279 * @since 4.1.0 280 * @access protected 281 * 282 * @param array $query Date query clause. 283 * @param array $parent_query Parent query of the current date query. 284 * @return array 285 */ 286 protected function get_sql_for_clause( $query, $parent_query ) { 230 287 global $wpdb; 231 288 232 289 // The sub-parts of a $where part … … class WP_Date_Query { 293 350 } 294 351 } 295 352 296 return $where_parts; 353 // Return an array of 'join' and 'where' for compatibility 354 // with other query classes. 355 return array( 356 'where' => $where_parts, 357 'join' => array(), 358 ); 359 } 360 361 /** 362 * Determine whether this is a first-order clause. 363 * 364 * Essentially, this checks to see if the current clause has any time- 365 * related keys. If so, it's first-order. 366 * 367 * @param array $query Query clause. 368 * @return bool 369 */ 370 protected function is_first_order_clause( $query ) { 371 return isset( $query['after'] ) || isset( $query['before'] ) || isset( $query['year'] ) || isset( $query['month'] ) || isset( $query['monthnum'] ) || isset( $query['week'] ) || isset( $query['w'] ) || isset( $query['dayofyear'] ) || isset( $query['day'] ) || isset( $query['dayofweek'] ) || isset( $query['hour'] ) || isset( $query['minute'] ) || isset( $query['second'] ); 297 372 } 298 373 299 374 /** -
src/wp-settings.php
diff --git src/wp-settings.php src/wp-settings.php index 9795971..5dca996 100644
wp_not_installed(); 111 111 // Load most of WordPress. 112 112 require( ABSPATH . WPINC . '/class-wp-walker.php' ); 113 113 require( ABSPATH . WPINC . '/class-wp-ajax-response.php' ); 114 require( ABSPATH . WPINC . '/class-wp-recursive-query.php' ); 114 115 require( ABSPATH . WPINC . '/formatting.php' ); 115 116 require( ABSPATH . WPINC . '/capabilities.php' ); 116 117 require( ABSPATH . WPINC . '/query.php' ); -
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 { 55 55 'year' => 2008, 56 56 'month' => 6, 57 57 ), 58 'column' => 'post_date', 59 'compare' => '=', 60 'relation' => 'AND', 58 61 ), 62 'column' => 'post_date', 63 'compare' => '=', 64 'relation' => 'AND', 59 65 ); 60 66 61 67 $this->assertSame( $expected, $q->queries ); … … class Tests_WP_Date_Query extends WP_UnitTestCase { 73 79 ), 74 80 ) ); 75 81 76 // Note: WP_Date_Query does not reset indexes77 82 $expected = array( 78 2 =>array(83 array( 79 84 'before' => array( 80 85 'year' => 2008, 81 86 'month' => 6, 82 87 ), 88 'column' => 'post_date', 89 'compare' => '=', 90 'relation' => 'AND', 83 91 ), 92 'column' => 'post_date', 93 'compare' => '=', 94 'relation' => 'AND', 84 95 ); 85 96 86 $this->assert Same( $expected, $q->queries );97 $this->assertEquals( $expected, $q->queries ); 87 98 } 88 99 89 100 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 2f94c4a..0d519ce 100644
class Tests_Query_DateQuery extends WP_UnitTestCase { 15 15 16 16 public function setUp() { 17 17 parent::setUp(); 18 19 // Be careful modifying this. Tests are coded to expect this exact sample data.20 $post_dates = array(21 '1972-05-24 14:53:45',22 '1984-07-28 19:28:56',23 '2003-05-27 22:45:07',24 '2004-01-03 08:54:10',25 '2004-05-22 12:34:12',26 '2005-02-17 00:00:15',27 '2005-12-31 23:59:20',28 '2007-01-22 03:49:21',29 '2007-05-16 17:32:22',30 '2007-09-24 07:17:23',31 '2008-03-29 09:04:25',32 '2008-07-15 11:32:26',33 '2008-12-10 13:06:27',34 '2009-06-11 21:30:28',35 '2009-12-18 10:42:29',36 '2010-06-17 17:09:30',37 '2011-02-23 12:12:31',38 '2011-07-04 01:56:32',39 '2011-12-12 16:39:33',40 '2012-06-13 14:03:34',41 '2025-04-20 10:13:00',42 '2025-04-20 10:13:01',43 '2025-05-20 10:13:01',44 );45 46 foreach ( $post_dates as $post_date ) {47 $this->factory->post->create( array( 'post_date' => $post_date ) );48 }49 50 18 unset( $this->q ); 51 19 $this->q = new WP_Query(); 52 20 } … … class Tests_Query_DateQuery extends WP_UnitTestCase { 65 33 } 66 34 67 35 public function test_date_query_before_array() { 36 $this->create_posts(); 37 68 38 $posts = $this->_get_query_result( array( 69 39 'date_query' => array( 70 40 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 98 68 * their minimum values when being used with "before". 99 69 */ 100 70 public function test_date_query_before_array_test_defaulting() { 71 $this->create_posts(); 72 101 73 $posts = $this->_get_query_result( array( 102 74 'date_query' => array( 103 75 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 125 97 } 126 98 127 99 public function test_date_query_before_string() { 100 $this->create_posts(); 101 128 102 $posts = $this->_get_query_result( array( 129 103 'date_query' => array( 130 104 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 151 125 } 152 126 153 127 public function test_date_query_after_array() { 128 $this->create_posts(); 129 154 130 $posts = $this->_get_query_result( array( 155 131 'date_query' => array( 156 132 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 182 158 * their maximum values when being used with "after". 183 159 */ 184 160 public function test_date_query_after_array_test_defaulting() { 161 $this->create_posts(); 162 185 163 $posts = $this->_get_query_result( array( 186 164 'date_query' => array( 187 165 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 209 187 } 210 188 211 189 public function test_date_query_after_string() { 190 $this->create_posts(); 191 212 192 $posts = $this->_get_query_result( array( 213 193 'date_query' => array( 214 194 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 232 212 } 233 213 234 214 public function test_date_query_after_string_inclusive() { 215 $this->create_posts(); 216 235 217 $posts = $this->_get_query_result( array( 236 218 'date_query' => array( 237 219 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 260 242 * @ticket 26653 261 243 */ 262 244 public function test_date_query_inclusive_between_dates() { 245 $this->create_posts(); 246 263 247 $posts = $this->_get_query_result( array( 264 248 'date_query' => array( 265 249 'after' => array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 288 272 } 289 273 290 274 public function test_date_query_year_expecting_results() { 275 $this->create_posts(); 276 291 277 $posts = $this->_get_query_result( array( 292 278 'date_query' => array( 293 279 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 305 291 } 306 292 307 293 public function test_date_query_year_expecting_noresults() { 294 $this->create_posts(); 295 308 296 $posts = $this->_get_query_result( array( 309 297 'date_query' => array( 310 298 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 317 305 } 318 306 319 307 public function test_date_query_month_expecting_results() { 308 $this->create_posts(); 309 320 310 $posts = $this->_get_query_result( array( 321 311 'date_query' => array( 322 312 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 336 326 } 337 327 338 328 public function test_date_query_month_expecting_noresults() { 329 $this->create_posts(); 330 339 331 $posts = $this->_get_query_result( array( 340 332 'date_query' => array( 341 333 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 348 340 } 349 341 350 342 public function test_date_query_week_expecting_results() { 343 $this->create_posts(); 344 351 345 $posts = $this->_get_query_result( array( 352 346 'date_query' => array( 353 347 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 364 358 } 365 359 366 360 public function test_date_query_week_expecting_noresults() { 361 $this->create_posts(); 362 367 363 $posts = $this->_get_query_result( array( 368 364 'date_query' => array( 369 365 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 376 372 } 377 373 378 374 public function test_date_query_day_expecting_results() { 375 $this->create_posts(); 376 379 377 $posts = $this->_get_query_result( array( 380 378 'date_query' => array( 381 379 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 393 391 } 394 392 395 393 public function test_date_query_day_expecting_noresults() { 394 $this->create_posts(); 395 396 396 $posts = $this->_get_query_result( array( 397 397 'date_query' => array( 398 398 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 405 405 } 406 406 407 407 public function test_date_query_dayofweek_expecting_results() { 408 $this->create_posts(); 409 408 410 $posts = $this->_get_query_result( array( 409 411 'date_query' => array( 410 412 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 425 427 } 426 428 427 429 public function test_date_query_hour_expecting_results() { 430 $this->create_posts(); 431 428 432 $posts = $this->_get_query_result( array( 429 433 'date_query' => array( 430 434 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 441 445 } 442 446 443 447 public function test_date_query_hour_expecting_noresults() { 448 $this->create_posts(); 449 444 450 $posts = $this->_get_query_result( array( 445 451 'date_query' => array( 446 452 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 453 459 } 454 460 455 461 public function test_date_query_minute_expecting_results() { 462 $this->create_posts(); 463 456 464 $posts = $this->_get_query_result( array( 457 465 'date_query' => array( 458 466 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 469 477 } 470 478 471 479 public function test_date_query_minute_expecting_noresults() { 480 $this->create_posts(); 481 472 482 $posts = $this->_get_query_result( array( 473 483 'date_query' => array( 474 484 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 481 491 } 482 492 483 493 public function test_date_query_second_expecting_results() { 494 $this->create_posts(); 495 484 496 $posts = $this->_get_query_result( array( 485 497 'date_query' => array( 486 498 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 497 509 } 498 510 499 511 public function test_date_query_second_expecting_noresults() { 512 $this->create_posts(); 513 500 514 $posts = $this->_get_query_result( array( 501 515 'date_query' => array( 502 516 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 509 523 } 510 524 511 525 public function test_date_query_between_two_times() { 526 $this->create_posts(); 527 512 528 $posts = $this->_get_query_result( array( 513 529 'date_query' => array( 514 530 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 542 558 $this->assertEquals( $expected_dates, wp_list_pluck( $posts, 'post_date' ) ); 543 559 } 544 560 561 public function test_date_query_one_nested_clause_one_unnested_clause() { 562 $this->create_posts(); 563 564 $posts = $this->_get_query_result( array( 565 'date_query' => array( 566 array( 567 'hour' => 9, 568 'minute' => 0, 569 'compare' => '=', 570 ), 571 array( 572 'hour' => '17', 573 'minute' => '0', 574 'compare' => '=', 575 ), 576 ), 577 ) ); 578 } 579 545 580 public function test_date_query_relation_or() { 581 $this->create_posts(); 582 546 583 $posts = $this->_get_query_result( array( 547 584 'date_query' => array( 548 585 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 564 601 $this->assertEquals( $expected_dates, wp_list_pluck( $posts, 'post_date' ) ); 565 602 } 566 603 604 public function test_date_query_one_nested_query() { 605 $this->create_posts(); 606 607 $posts = $this->_get_query_result( array( 608 'date_query' => array( 609 'relation' => 'OR', 610 array( 611 'relation' => 'AND', 612 array( 613 'year' => 2004, 614 ), 615 array( 616 'month' => 1, 617 ), 618 ), 619 array( 620 'year' => 1984, 621 ), 622 ), 623 ) ); 624 625 $expected_dates = array( 626 '1984-07-28 19:28:56', 627 '2004-01-03 08:54:10', 628 ); 629 630 $this->assertEquals( $expected_dates, wp_list_pluck( $posts, 'post_date' ) ); 631 } 632 633 public function test_date_query_one_nested_query_multiple_columns_relation_and() { 634 $p1 = $this->factory->post->create( array( 635 'post_date' => '2012-03-05 15:30:55', 636 ) ); 637 $this->update_post_modified( $p1, '2014-11-03 14:43:00' ); 638 639 $p2 = $this->factory->post->create( array( 640 'post_date' => '2012-05-05 15:30:55', 641 ) ); 642 $this->update_post_modified( $p2, '2014-10-03 14:43:00' ); 643 644 $p3 = $this->factory->post->create( array( 645 'post_date' => '2013-05-05 15:30:55', 646 ) ); 647 $this->update_post_modified( $p3, '2014-10-03 14:43:00' ); 648 649 $p4 = $this->factory->post->create( array( 650 'post_date' => '2012-02-05 15:30:55', 651 ) ); 652 $this->update_post_modified( $p4, '2012-12-03 14:43:00' ); 653 654 global $wpdb; 655 656 $q = new WP_Query( array( 657 'date_query' => array( 658 'relation' => 'AND', 659 array( 660 'column' => 'post_date', 661 array( 662 'year' => 2012, 663 ), 664 ), 665 array( 666 'column' => 'post_modified', 667 array( 668 'year' => 2014, 669 ), 670 ), 671 ), 672 'fields' => 'ids', 673 'update_post_meta_cache' => false, 674 'update_post_term_cache' => false, 675 'post_status' => 'publish', 676 ) ); 677 678 $expected = array( 679 $p1, 680 $p2, 681 ); 682 683 $this->assertEqualSets( $expected, $q->posts ); 684 } 685 567 686 public function test_date_query_compare_greater_than_or_equal_to() { 687 $this->create_posts(); 688 568 689 $posts = $this->_get_query_result( array( 569 690 'date_query' => array( 570 691 array( … … class Tests_Query_DateQuery extends WP_UnitTestCase { 590 711 } 591 712 592 713 public function test_date_params_monthnum_m_duplicate() { 714 $this->create_posts(); 715 593 716 $posts = $this->_get_query_result( array( 594 717 'date_query' => array( 595 718 'month' => 5, … … class Tests_Query_DateQuery extends WP_UnitTestCase { 607 730 608 731 $this->assertEquals( $expected_dates, wp_list_pluck( $posts, 'post_date' ) ); 609 732 610 $this->assertContains( " AND ( ( MONTH( post_date ) = 5 ) ) AND", $this->q->request );733 $this->assertContains( "MONTH( post_date ) = 5", $this->q->request ); 611 734 612 $this->assertNotContains( " AND ( ( MONTH( post_date ) = 5 AND MONTH( post_date ) = 9 ) ) AND", $this->q->request );735 $this->assertNotContains( "MONTH( post_date ) = 5 AND MONTH( post_date ) = 9", $this->q->request ); 613 736 } 614 737 615 738 public function test_date_params_week_w_duplicate() { 739 $this->create_posts(); 740 616 741 $posts = $this->_get_query_result( array( 617 742 'date_query' => array( 618 743 'week' => 21, … … class Tests_Query_DateQuery extends WP_UnitTestCase { 629 754 630 755 $this->assertEquals( $expected_dates, wp_list_pluck( $posts, 'post_date' ) ); 631 756 632 $this->assertContains( "AND ( ( WEEK( post_date, 1 ) = 21 ) ) AND", $this->q->request ); 757 $this->assertContains( "WEEK( post_date, 1 ) = 21", $this->q->request ); 758 759 $this->assertNotContains( "WEEK( post_date, 1 ) = 21 AND WEEK( post_date, 1 ) = 22", $this->q->request ); 760 } 761 762 /** Helpers **********************************************************/ 763 764 protected function create_posts() { 765 // Be careful modifying this. Tests are coded to expect this exact sample data. 766 $post_dates = array( 767 '1972-05-24 14:53:45', 768 '1984-07-28 19:28:56', 769 '2003-05-27 22:45:07', 770 '2004-01-03 08:54:10', 771 '2004-05-22 12:34:12', 772 '2005-02-17 00:00:15', 773 '2005-12-31 23:59:20', 774 '2007-01-22 03:49:21', 775 '2007-05-16 17:32:22', 776 '2007-09-24 07:17:23', 777 '2008-03-29 09:04:25', 778 '2008-07-15 11:32:26', 779 '2008-12-10 13:06:27', 780 '2009-06-11 21:30:28', 781 '2009-12-18 10:42:29', 782 '2010-06-17 17:09:30', 783 '2011-02-23 12:12:31', 784 '2011-07-04 01:56:32', 785 '2011-12-12 16:39:33', 786 '2012-06-13 14:03:34', 787 '2025-04-20 10:13:00', 788 '2025-04-20 10:13:01', 789 '2025-05-20 10:13:01', 790 ); 791 792 foreach ( $post_dates as $post_date ) { 793 $this->factory->post->create( array( 'post_date' => $post_date ) ); 794 } 795 } 633 796 634 $this->assertNotContains( "AND ( ( WEEK( post_date, 1 ) = 21 AND WEEK( post_date, 1 ) = 22 ) ) AND", $this->q->request ); 797 protected function update_post_modified( $post_id, $date ) { 798 global $wpdb; 799 return $wpdb->update( 800 $wpdb->posts, 801 array( 802 'post_modified' => $date, 803 'post_modified_gmt' => $date, 804 ), 805 array( 806 'ID' => $post_id, 807 ), 808 array( 809 '%s', 810 '%s', 811 ), 812 array( 813 '%d', 814 ) 815 ); 635 816 } 636 } 637 No newline at end of file 817 }