equal
deleted
inserted
replaced
12 * |
12 * |
13 * @link https://developer.wordpress.org/reference/classes/wp_query/ |
13 * @link https://developer.wordpress.org/reference/classes/wp_query/ |
14 * |
14 * |
15 * @since 3.7.0 |
15 * @since 3.7.0 |
16 */ |
16 */ |
|
17 #[AllowDynamicProperties] |
17 class WP_Date_Query { |
18 class WP_Date_Query { |
18 /** |
19 /** |
19 * Array of date queries. |
20 * Array of date queries. |
20 * |
21 * |
21 * See WP_Date_Query::__construct() for information on date query arguments. |
22 * See WP_Date_Query::__construct() for information on date query arguments. |
147 public function __construct( $date_query, $default_column = 'post_date' ) { |
148 public function __construct( $date_query, $default_column = 'post_date' ) { |
148 if ( empty( $date_query ) || ! is_array( $date_query ) ) { |
149 if ( empty( $date_query ) || ! is_array( $date_query ) ) { |
149 return; |
150 return; |
150 } |
151 } |
151 |
152 |
152 if ( isset( $date_query['relation'] ) && 'OR' === strtoupper( $date_query['relation'] ) ) { |
153 if ( isset( $date_query['relation'] ) ) { |
153 $this->relation = 'OR'; |
154 $this->relation = $this->sanitize_relation( $date_query['relation'] ); |
154 } else { |
155 } else { |
155 $this->relation = 'AND'; |
156 $this->relation = 'AND'; |
156 } |
157 } |
157 |
158 |
158 // Support for passing time-based keys in the top level of the $date_query array. |
159 // Support for passing time-based keys in the top level of the $date_query array. |
216 |
217 |
217 // Validate the dates passed in the query. |
218 // Validate the dates passed in the query. |
218 if ( $this->is_first_order_clause( $queries ) ) { |
219 if ( $this->is_first_order_clause( $queries ) ) { |
219 $this->validate_date_values( $queries ); |
220 $this->validate_date_values( $queries ); |
220 } |
221 } |
|
222 |
|
223 // Sanitize the relation parameter. |
|
224 $queries['relation'] = $this->sanitize_relation( $queries['relation'] ); |
221 |
225 |
222 foreach ( $queries as $key => $q ) { |
226 foreach ( $queries as $key => $q ) { |
223 if ( ! is_array( $q ) || in_array( $key, $this->time_keys, true ) ) { |
227 if ( ! is_array( $q ) || in_array( $key, $this->time_keys, true ) ) { |
224 // This is a first-order query. Trust the values and sanitize when building SQL. |
228 // This is a first-order query. Trust the values and sanitize when building SQL. |
225 $cleaned_query[ $key ] = $q; |
229 $cleaned_query[ $key ] = $q; |
231 |
235 |
232 return $cleaned_query; |
236 return $cleaned_query; |
233 } |
237 } |
234 |
238 |
235 /** |
239 /** |
236 * Determine whether this is a first-order clause. |
240 * Determines whether this is a first-order clause. |
237 * |
241 * |
238 * Checks to see if the current clause has any time-related keys. |
242 * Checks to see if the current clause has any time-related keys. |
239 * If so, it's first-order. |
243 * If so, it's first-order. |
240 * |
244 * |
241 * @since 4.1.0 |
245 * @since 4.1.0 |
274 * This method only generates debug notices for these cases. |
278 * This method only generates debug notices for these cases. |
275 * |
279 * |
276 * @since 4.1.0 |
280 * @since 4.1.0 |
277 * |
281 * |
278 * @param array $date_query The date_query array. |
282 * @param array $date_query The date_query array. |
279 * @return bool True if all values in the query are valid, false if one or more fail. |
283 * @return bool True if all values in the query are valid, false if one or more fail. |
280 */ |
284 */ |
281 public function validate_date_values( $date_query = array() ) { |
285 public function validate_date_values( $date_query = array() ) { |
282 if ( empty( $date_query ) ) { |
286 if ( empty( $date_query ) ) { |
283 return false; |
287 return false; |
284 } |
288 } |
467 * prepended. Prefixed column names (such as 'wp_posts.post_date') bypass this allowed |
471 * prepended. Prefixed column names (such as 'wp_posts.post_date') bypass this allowed |
468 * check, and are only sanitized to remove illegal characters. |
472 * check, and are only sanitized to remove illegal characters. |
469 * |
473 * |
470 * @since 3.7.0 |
474 * @since 3.7.0 |
471 * |
475 * |
|
476 * @global wpdb $wpdb WordPress database abstraction object. |
|
477 * |
472 * @param string $column The user-supplied column name. |
478 * @param string $column The user-supplied column name. |
473 * @return string A validated column name value. |
479 * @return string A validated column name value. |
474 */ |
480 */ |
475 public function validate_column( $column ) { |
481 public function validate_column( $column ) { |
476 global $wpdb; |
482 global $wpdb; |
486 'registered', |
492 'registered', |
487 'last_updated', |
493 'last_updated', |
488 ); |
494 ); |
489 |
495 |
490 // Attempt to detect a table prefix. |
496 // Attempt to detect a table prefix. |
491 if ( false === strpos( $column, '.' ) ) { |
497 if ( ! str_contains( $column, '.' ) ) { |
492 /** |
498 /** |
493 * Filters the list of valid date query columns. |
499 * Filters the list of valid date query columns. |
494 * |
500 * |
495 * @since 3.7.0 |
501 * @since 3.7.0 |
496 * @since 4.1.0 Added 'user_registered' to the default recognized columns. |
502 * @since 4.1.0 Added 'user_registered' to the default recognized columns. |
537 // Remove unsafe characters. |
543 // Remove unsafe characters. |
538 return preg_replace( '/[^a-zA-Z0-9_$\.]/', '', $column ); |
544 return preg_replace( '/[^a-zA-Z0-9_$\.]/', '', $column ); |
539 } |
545 } |
540 |
546 |
541 /** |
547 /** |
542 * Generate WHERE clause to be appended to a main query. |
548 * Generates WHERE clause to be appended to a main query. |
543 * |
549 * |
544 * @since 3.7.0 |
550 * @since 3.7.0 |
545 * |
551 * |
546 * @return string MySQL WHERE clause. |
552 * @return string MySQL WHERE clause. |
547 */ |
553 */ |
560 */ |
566 */ |
561 return apply_filters( 'get_date_sql', $where, $this ); |
567 return apply_filters( 'get_date_sql', $where, $this ); |
562 } |
568 } |
563 |
569 |
564 /** |
570 /** |
565 * Generate SQL clauses to be appended to a main query. |
571 * Generates SQL clauses to be appended to a main query. |
566 * |
572 * |
567 * Called by the public WP_Date_Query::get_sql(), this method is abstracted |
573 * Called by the public WP_Date_Query::get_sql(), this method is abstracted |
568 * out to maintain parity with the other Query classes. |
574 * out to maintain parity with the other Query classes. |
569 * |
575 * |
570 * @since 4.1.0 |
576 * @since 4.1.0 |
585 |
591 |
586 return $sql; |
592 return $sql; |
587 } |
593 } |
588 |
594 |
589 /** |
595 /** |
590 * Generate SQL clauses for a single query array. |
596 * Generates SQL clauses for a single query array. |
591 * |
597 * |
592 * If nested subqueries are found, this method recurses the tree to |
598 * If nested subqueries are found, this method recurses the tree to |
593 * produce the properly nested SQL. |
599 * produce the properly nested SQL. |
594 * |
600 * |
595 * @since 4.1.0 |
601 * @since 4.1.0 |
677 * compatibility while retaining the naming convention across Query classes. |
683 * compatibility while retaining the naming convention across Query classes. |
678 * |
684 * |
679 * @since 3.7.0 |
685 * @since 3.7.0 |
680 * |
686 * |
681 * @param array $query Date query arguments. |
687 * @param array $query Date query arguments. |
682 * @return string[] { |
688 * @return array { |
683 * Array containing JOIN and WHERE SQL clauses to append to the main query. |
689 * Array containing JOIN and WHERE SQL clauses to append to the main query. |
684 * |
690 * |
685 * @type string $join SQL fragment to append to the main JOIN clause. |
691 * @type string[] $join Array of SQL fragments to append to the main JOIN clause. |
686 * @type string $where SQL fragment to append to the main WHERE clause. |
692 * @type string[] $where Array of SQL fragments to append to the main WHERE clause. |
687 * } |
693 * } |
688 */ |
694 */ |
689 protected function get_sql_for_subquery( $query ) { |
695 protected function get_sql_for_subquery( $query ) { |
690 return $this->get_sql_for_clause( $query, '' ); |
696 return $this->get_sql_for_clause( $query, '' ); |
691 } |
697 } |
693 /** |
699 /** |
694 * Turns a first-order date query into SQL for a WHERE clause. |
700 * Turns a first-order date query into SQL for a WHERE clause. |
695 * |
701 * |
696 * @since 4.1.0 |
702 * @since 4.1.0 |
697 * |
703 * |
|
704 * @global wpdb $wpdb WordPress database abstraction object. |
|
705 * |
698 * @param array $query Date query clause. |
706 * @param array $query Date query clause. |
699 * @param array $parent_query Parent query of the current date query. |
707 * @param array $parent_query Parent query of the current date query. |
700 * @return string[] { |
708 * @return array { |
701 * Array containing JOIN and WHERE SQL clauses to append to the main query. |
709 * Array containing JOIN and WHERE SQL clauses to append to the main query. |
702 * |
710 * |
703 * @type string $join SQL fragment to append to the main JOIN clause. |
711 * @type string[] $join Array of SQL fragments to append to the main JOIN clause. |
704 * @type string $where SQL fragment to append to the main WHERE clause. |
712 * @type string[] $where Array of SQL fragments to append to the main WHERE clause. |
705 * } |
713 * } |
706 */ |
714 */ |
707 protected function get_sql_for_clause( $query, $parent_query ) { |
715 protected function get_sql_for_clause( $query, $parent_query ) { |
708 global $wpdb; |
716 global $wpdb; |
709 |
717 |
856 * either the maximum or minimum values (controlled by the $default_to parameter). Alternatively you can |
864 * either the maximum or minimum values (controlled by the $default_to parameter). Alternatively you can |
857 * pass a string that will be passed to date_create(). |
865 * pass a string that will be passed to date_create(). |
858 * |
866 * |
859 * @since 3.7.0 |
867 * @since 3.7.0 |
860 * |
868 * |
861 * @param string|array $datetime An array of parameters or a strotime() string |
869 * @param string|array $datetime An array of parameters or a strtotime() string. |
862 * @param bool $default_to_max Whether to round up incomplete dates. Supported by values |
870 * @param bool $default_to_max Whether to round up incomplete dates. Supported by values |
863 * of $datetime that are arrays, or string values that are a |
871 * of $datetime that are arrays, or string values that are a |
864 * subset of MySQL date format ('Y', 'Y-m', 'Y-m-d', 'Y-m-d H:i'). |
872 * subset of MySQL date format ('Y', 'Y-m', 'Y-m-d', 'Y-m-d H:i'). |
865 * Default: false. |
873 * Default: false. |
866 * @return string|false A MySQL format date/time or false on failure |
874 * @return string|false A MySQL format date/time or false on failure. |
867 */ |
875 */ |
868 public function build_mysql_datetime( $datetime, $default_to_max = false ) { |
876 public function build_mysql_datetime( $datetime, $default_to_max = false ) { |
869 if ( ! is_array( $datetime ) ) { |
877 if ( ! is_array( $datetime ) ) { |
870 |
878 |
871 /* |
879 /* |
955 * However if multiple values are passed, a pseudo-decimal time will be created |
963 * However if multiple values are passed, a pseudo-decimal time will be created |
956 * in order to be able to accurately compare against. |
964 * in order to be able to accurately compare against. |
957 * |
965 * |
958 * @since 3.7.0 |
966 * @since 3.7.0 |
959 * |
967 * |
|
968 * @global wpdb $wpdb WordPress database abstraction object. |
|
969 * |
960 * @param string $column The column to query against. Needs to be pre-validated! |
970 * @param string $column The column to query against. Needs to be pre-validated! |
961 * @param string $compare The comparison operator. Needs to be pre-validated! |
971 * @param string $compare The comparison operator. Needs to be pre-validated! |
962 * @param int|null $hour Optional. An hour value (0-23). |
972 * @param int|null $hour Optional. An hour value (0-23). |
963 * @param int|null $minute Optional. A minute value (0-59). |
973 * @param int|null $minute Optional. A minute value (0-59). |
964 * @param int|null $second Optional. A second value (0-59). |
974 * @param int|null $second Optional. A second value (0-59). |
1038 $time .= sprintf( '%02d', $second ); |
1048 $time .= sprintf( '%02d', $second ); |
1039 } |
1049 } |
1040 |
1050 |
1041 return $wpdb->prepare( "DATE_FORMAT( $column, %s ) $compare %f", $format, $time ); |
1051 return $wpdb->prepare( "DATE_FORMAT( $column, %s ) $compare %f", $format, $time ); |
1042 } |
1052 } |
|
1053 |
|
1054 /** |
|
1055 * Sanitizes a 'relation' operator. |
|
1056 * |
|
1057 * @since 6.0.3 |
|
1058 * |
|
1059 * @param string $relation Raw relation key from the query argument. |
|
1060 * @return string Sanitized relation. Either 'AND' or 'OR'. |
|
1061 */ |
|
1062 public function sanitize_relation( $relation ) { |
|
1063 if ( 'OR' === strtoupper( $relation ) ) { |
|
1064 return 'OR'; |
|
1065 } else { |
|
1066 return 'AND'; |
|
1067 } |
|
1068 } |
1043 } |
1069 } |