run:R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
23.8 KB
2026-03-11 16:18:51
R W Run
7.8 KB
2026-03-11 16:18:52
R W Run
36.1 KB
2026-03-11 16:18:51
R W Run
11.9 KB
2026-03-11 16:18:52
R W Run
18.94 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:52
R W Run
28.6 KB
2026-03-11 16:18:51
R W Run
316 By
2026-03-11 16:18:51
R W Run
12.9 KB
2026-03-11 16:18:51
R W Run
61.02 KB
2026-03-11 16:18:52
R W Run
15 KB
2026-03-11 16:18:51
R W Run
112.05 KB
2026-03-11 16:18:51
R W Run
12.47 KB
2026-03-11 16:18:51
R W Run
15.07 KB
2026-03-11 16:18:52
R W Run
9.84 KB
2026-03-11 16:18:52
R W Run
13.17 KB
2026-03-11 16:18:52
R W Run
33.83 KB
2026-03-11 16:18:51
R W Run
42.63 KB
2026-03-11 16:18:51
R W Run
55.71 KB
2026-03-11 16:18:52
R W Run
12.53 KB
2026-03-11 16:18:51
R W Run
2.55 KB
2026-03-11 16:18:52
R W Run
28.92 KB
2026-03-11 16:18:52
R W Run
539 By
2026-03-11 16:18:51
R W Run
367 By
2026-03-11 16:18:52
R W Run
42.65 KB
2026-03-11 16:18:51
R W Run
401 By
2026-03-11 16:18:51
R W Run
6.61 KB
2026-03-11 16:18:51
R W Run
664 By
2026-03-11 16:18:52
R W Run
20.63 KB
2026-03-11 16:18:51
R W Run
2.18 KB
2026-03-11 16:18:52
R W Run
453 By
2026-03-11 16:18:52
R W Run
457 By
2026-03-11 16:18:51
R W Run
36.83 KB
2026-03-11 16:18:52
R W Run
2.41 KB
2026-03-11 16:18:52
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
13.89 KB
2026-03-11 16:18:51
R W Run
11.76 KB
2026-03-11 16:18:51
R W Run
2.65 KB
2026-03-11 16:18:51
R W Run
7.43 KB
2026-03-11 16:18:51
R W Run
17.46 KB
2026-03-11 16:18:51
R W Run
5.14 KB
2026-03-11 16:18:52
R W Run
16.7 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:52
R W Run
2.92 KB
2026-03-11 16:18:52
R W Run
1.32 KB
2026-03-11 16:18:51
R W Run
4.6 KB
2026-03-11 16:18:52
R W Run
11.62 KB
2026-03-11 16:18:52
R W Run
2.5 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
11.25 KB
2026-03-11 16:18:52
R W Run
5.32 KB
2026-03-11 16:18:51
R W Run
10.99 KB
2026-03-11 16:18:52
R W Run
68.32 KB
2026-03-11 16:18:51
R W Run
6.34 KB
2026-03-11 16:18:51
R W Run
5.49 KB
2026-03-11 16:18:51
R W Run
1.99 KB
2026-03-11 16:18:52
R W Run
7.02 KB
2026-03-11 16:18:51
R W Run
4.91 KB
2026-03-11 16:18:52
R W Run
16.86 KB
2026-03-11 16:18:51
R W Run
24.23 KB
2026-03-11 16:18:51
R W Run
3.97 KB
2026-03-11 16:18:51
R W Run
47.66 KB
2026-03-11 16:18:51
R W Run
9.22 KB
2026-03-11 16:18:51
R W Run
25.51 KB
2026-03-11 16:18:51
R W Run
198.38 KB
2026-03-11 16:18:52
R W Run
56.65 KB
2026-03-11 16:18:51
R W Run
10.46 KB
2026-03-11 16:18:51
R W Run
10.95 KB
2026-03-11 16:18:52
R W Run
29.26 KB
2026-03-11 16:18:51
R W Run
70.91 KB
2026-03-11 16:18:52
R W Run
35.3 KB
2026-03-11 16:18:52
R W Run
16.61 KB
2026-03-11 16:18:52
R W Run
2.57 KB
2026-03-11 16:18:52
R W Run
39.83 KB
2026-03-11 16:18:51
R W Run
70.64 KB
2026-03-11 16:18:51
R W Run
15.56 KB
2026-03-11 16:18:52
R W Run
7.33 KB
2026-03-11 16:18:52
R W Run
253 By
2026-03-11 16:18:51
R W Run
7.96 KB
2026-03-11 16:18:52
R W Run
3.23 KB
2026-03-11 16:18:52
R W Run
969 By
2026-03-11 16:18:52
R W Run
16.28 KB
2026-03-11 16:18:51
R W Run
7.22 KB
2026-03-11 16:18:51
R W Run
12.95 KB
2026-03-11 16:18:51
R W Run
6.53 KB
2026-03-11 16:18:51
R W Run
3.42 KB
2026-03-11 16:18:52
R W Run
5.84 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
4.3 KB
2026-03-11 16:18:52
R W Run
2.91 KB
2026-03-11 16:18:51
R W Run
16.46 KB
2026-03-11 16:18:52
R W Run
40.6 KB
2026-03-11 16:18:51
R W Run
20.22 KB
2026-03-11 16:18:51
R W Run
36.11 KB
2026-03-11 16:18:52
R W Run
17.01 KB
2026-03-11 16:18:51
R W Run
7.27 KB
2026-03-11 16:18:52
R W Run
6.62 KB
2026-03-11 16:18:52
R W Run
16.49 KB
2026-03-11 16:18:52
R W Run
1.79 KB
2026-03-11 16:18:52
R W Run
29.82 KB
2026-03-11 16:18:51
R W Run
6.67 KB
2026-03-11 16:18:52
R W Run
8.98 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:51
R W Run
12.01 KB
2026-03-11 16:18:51
R W Run
17.11 KB
2026-03-11 16:18:51
R W Run
6.74 KB
2026-03-11 16:18:52
R W Run
30.93 KB
2026-03-11 16:18:51
R W Run
4.99 KB
2026-03-11 16:18:51
R W Run
4.25 KB
2026-03-11 16:18:51
R W Run
24.72 KB
2026-03-11 16:18:51
R W Run
29.96 KB
2026-03-11 16:18:52
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
160 KB
2026-03-11 16:18:51
R W Run
6.72 KB
2026-03-11 16:18:52
R W Run
10.92 KB
2026-03-11 16:18:51
R W Run
4.77 KB
2026-03-11 16:18:51
R W Run
3.38 KB
2026-03-11 16:18:51
R W Run
11.18 KB
2026-03-11 16:18:51
R W Run
62.19 KB
2026-03-11 16:18:51
R W Run
2.46 KB
2026-03-11 16:18:51
R W Run
9.17 KB
2026-03-11 16:18:51
R W Run
32.15 KB
2026-03-11 16:18:51
R W Run
34.05 KB
2026-03-11 16:18:52
R W Run
7.15 KB
2026-03-11 16:18:51
R W Run
3.47 KB
2026-03-11 16:18:52
R W Run
1.87 KB
2026-03-11 16:18:52
R W Run
30.91 KB
2026-03-11 16:18:51
R W Run
7.29 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:51
R W Run
12.54 KB
2026-03-11 16:18:51
R W Run
19.12 KB
2026-03-11 16:18:51
R W Run
18.12 KB
2026-03-11 16:18:52
R W Run
39.99 KB
2026-03-11 16:18:52
R W Run
5.17 KB
2026-03-11 16:18:52
R W Run
979 By
2026-03-11 16:18:51
R W Run
18.44 KB
2026-03-11 16:18:52
R W Run
10.24 KB
2026-03-11 16:18:51
R W Run
1.77 KB
2026-03-11 16:18:52
R W Run
34.9 KB
2026-03-11 16:18:51
R W Run
7.19 KB
2026-03-11 16:18:52
R W Run
160.5 KB
2026-03-11 16:18:51
R W Run
64.27 KB
2026-03-11 16:18:51
R W Run
27.95 KB
2026-03-11 16:18:51
R W Run
4.69 KB
2026-03-11 16:18:51
R W Run
2.94 KB
2026-03-11 16:18:51
R W Run
43.13 KB
2026-03-11 16:18:52
R W Run
2.25 KB
2026-03-11 16:18:52
R W Run
22.5 KB
2026-03-11 16:18:51
R W Run
13.01 KB
2026-03-11 16:18:52
R W Run
3.27 KB
2026-03-11 16:18:51
R W Run
18 KB
2026-03-11 16:18:51
R W Run
210.4 KB
2026-03-11 16:18:52
R W Run
25.86 KB
2026-03-11 16:18:52
R W Run
115.85 KB
2026-03-11 16:18:51
R W Run
373 By
2026-03-11 16:18:52
R W Run
343 By
2026-03-11 16:18:52
R W Run
338 By
2026-03-11 16:18:51
R W Run
100.73 KB
2026-03-11 16:18:52
R W Run
130.93 KB
2026-03-11 16:18:51
R W Run
19.1 KB
2026-03-11 16:18:51
R W Run
17.41 KB
2026-03-11 16:18:52
R W Run
41.98 KB
2026-03-11 16:18:52
R W Run
400 By
2026-03-11 16:18:52
R W Run
11.1 KB
2026-03-11 16:18:52
R W Run
37.02 KB
2026-03-11 16:18:51
R W Run
2.24 KB
2026-03-11 16:18:51
R W Run
188.13 KB
2026-03-11 16:18:51
R W Run
338 By
2026-03-11 16:18:51
R W Run
38 KB
2026-03-11 16:18:51
R W Run
4.02 KB
2026-03-11 16:18:52
R W Run
5.38 KB
2026-03-11 16:18:51
R W Run
3.05 KB
2026-03-11 16:18:52
R W Run
2.61 KB
2026-03-11 16:18:51
R W Run
1.16 KB
2026-03-11 16:18:52
R W Run
4.04 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
24.6 KB
2026-03-11 16:18:51
R W Run
9.56 KB
2026-03-11 16:18:51
R W Run
346.43 KB
2026-03-11 16:18:52
R W Run
281.84 KB
2026-03-11 16:18:52
R W Run
14.95 KB
2026-03-11 16:18:51
R W Run
8.44 KB
2026-03-11 16:18:52
R W Run
168.95 KB
2026-03-11 16:18:52
R W Run
20.71 KB
2026-03-11 16:18:52
R W Run
25.27 KB
2026-03-11 16:18:51
R W Run
5.72 KB
2026-03-11 16:18:51
R W Run
4.63 KB
2026-03-11 16:18:52
R W Run
81.73 KB
2026-03-11 16:18:51
R W Run
67.18 KB
2026-03-11 16:18:51
R W Run
156.36 KB
2026-03-11 16:18:52
R W Run
55.19 KB
2026-03-11 16:18:51
R W Run
162 By
2026-03-11 16:18:51
R W Run
61.72 KB
2026-03-11 16:18:51
R W Run
216.06 KB
2026-03-11 16:18:52
R W Run
65.09 KB
2026-03-11 16:18:51
R W Run
25.24 KB
2026-03-11 16:18:52
R W Run
4.81 KB
2026-03-11 16:18:51
R W Run
6.48 KB
2026-03-11 16:18:52
R W Run
21.25 KB
2026-03-11 16:18:51
R W Run
2.79 KB
2026-03-11 16:18:52
R W Run
89.69 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:52
R W Run
3.69 KB
2026-03-11 16:18:52
R W Run
4.11 KB
2026-03-11 16:18:51
R W Run
40.74 KB
2026-03-11 16:18:51
R W Run
25.38 KB
2026-03-11 16:18:51
R W Run
43.31 KB
2026-03-11 16:18:52
R W Run
102.57 KB
2026-03-11 16:18:52
R W Run
6.18 KB
2026-03-11 16:18:51
R W Run
124.47 KB
2026-03-11 16:18:52
R W Run
35.65 KB
2026-03-11 16:18:52
R W Run
6.94 KB
2026-03-11 16:18:52
R W Run
67.04 KB
2026-03-11 16:18:52
R W Run
10.62 KB
2026-03-11 16:18:51
R W Run
289.35 KB
2026-03-11 16:18:52
R W Run
36.23 KB
2026-03-11 16:18:51
R W Run
200 By
2026-03-11 16:18:52
R W Run
200 By
2026-03-11 16:18:52
R W Run
98.29 KB
2026-03-11 16:18:52
R W Run
30.02 KB
2026-03-11 16:18:52
R W Run
19.03 KB
2026-03-11 16:18:52
R W Run
5.06 KB
2026-03-11 16:18:52
R W Run
255 By
2026-03-11 16:18:51
R W Run
22.66 KB
2026-03-11 16:18:52
R W Run
154.63 KB
2026-03-11 16:18:51
R W Run
9.68 KB
2026-03-11 16:18:51
R W Run
258 By
2026-03-11 16:18:51
R W Run
23.49 KB
2026-03-11 16:18:51
R W Run
3.16 KB
2026-03-11 16:18:51
R W Run
8.4 KB
2026-03-11 16:18:52
R W Run
441 By
2026-03-11 16:18:51
R W Run
7.39 KB
2026-03-11 16:18:51
R W Run
173 KB
2026-03-11 16:18:52
R W Run
544 By
2026-03-11 16:18:52
R W Run
4.17 KB
2026-03-11 16:18:51
R W Run
35.97 KB
2026-03-11 16:18:52
R W Run
1.69 KB
2026-03-11 16:18:51
R W Run
2.84 KB
2026-03-11 16:18:52
R W Run
6.09 KB
2026-03-11 16:18:51
R W Run
8.71 KB
2026-03-11 16:18:51
R W Run
131.84 KB
2026-03-11 16:18:51
R W Run
37.45 KB
2026-03-11 16:18:51
R W Run
173.89 KB
2026-03-11 16:18:51
R W Run
7.09 KB
2026-03-11 16:18:51
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
1.08 KB
2026-03-11 16:18:51
R W Run
69.46 KB
2026-03-11 16:18:52
R W Run
445 By
2026-03-11 16:18:51
R W Run
799 By
2026-03-11 16:18:52
R W Run
error_log
📄class-wp-date-query.php
1<?php
2/**
3 * Class for generating SQL clauses that filter a primary query according to date.
4 *
5 * WP_Date_Query is a helper that allows primary query classes, such as WP_Query, to filter
6 * their results by date columns, by generating `WHERE` subclauses to be attached to the
7 * primary SQL query string.
8 *
9 * Attempting to filter by an invalid date value (eg month=13) will generate SQL that will
10 * return no results. In these cases, a _doing_it_wrong() error notice is also thrown.
11 * See WP_Date_Query::validate_date_values().
12 *
13 * @link https://developer.wordpress.org/reference/classes/wp_query/
14 *
15 * @since 3.7.0
16 */
17#[AllowDynamicProperties]
18class WP_Date_Query {
19 /**
20 * Array of date queries.
21 *
22 * See WP_Date_Query::__construct() for information on date query arguments.
23 *
24 * @since 3.7.0
25 * @var array
26 */
27 public $queries = array();
28
29 /**
30 * The default relation between top-level queries. Can be either 'AND' or 'OR'.
31 *
32 * @since 3.7.0
33 * @var string
34 */
35 public $relation = 'AND';
36
37 /**
38 * The column to query against. Can be changed via the query arguments.
39 *
40 * @since 3.7.0
41 * @var string
42 */
43 public $column = 'post_date';
44
45 /**
46 * The value comparison operator. Can be changed via the query arguments.
47 *
48 * @since 3.7.0
49 * @var string
50 */
51 public $compare = '=';
52
53 /**
54 * Supported time-related parameter keys.
55 *
56 * @since 4.1.0
57 * @var string[]
58 */
59 public $time_keys = array( 'after', 'before', 'year', 'month', 'monthnum', 'week', 'w', 'dayofyear', 'day', 'dayofweek', 'dayofweek_iso', 'hour', 'minute', 'second' );
60
61 /**
62 * Constructor.
63 *
64 * Time-related parameters that normally require integer values ('year', 'month', 'week', 'dayofyear', 'day',
65 * 'dayofweek', 'dayofweek_iso', 'hour', 'minute', 'second') accept arrays of integers for some values of
66 * 'compare'. When 'compare' is 'IN' or 'NOT IN', arrays are accepted; when 'compare' is 'BETWEEN' or 'NOT
67 * BETWEEN', arrays of two valid values are required. See individual argument descriptions for accepted values.
68 *
69 * @since 3.7.0
70 * @since 4.0.0 The $inclusive logic was updated to include all times within the date range.
71 * @since 4.1.0 Introduced 'dayofweek_iso' time type parameter.
72 *
73 * @param array $date_query {
74 * Array of date query clauses.
75 *
76 * @type array ...$0 {
77 * @type string $column Optional. The column to query against. If undefined, inherits the value of
78 * the `$default_column` parameter. See WP_Date_Query::validate_column() and
79 * the {@see 'date_query_valid_columns'} filter for the list of accepted values.
80 * Default 'post_date'.
81 * @type string $compare Optional. The comparison operator. Accepts '=', '!=', '>', '>=', '<', '<=',
82 * 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'. Default '='.
83 * @type string $relation Optional. The boolean relationship between the date queries. Accepts 'OR' or 'AND'.
84 * Default 'OR'.
85 * @type array ...$0 {
86 * Optional. An array of first-order clause parameters, or another fully-formed date query.
87 *
88 * @type string|array $before {
89 * Optional. Date to retrieve posts before. Accepts `strtotime()`-compatible string,
90 * or array of 'year', 'month', 'day' values.
91 *
92 * @type string $year The four-digit year. Default empty. Accepts any four-digit year.
93 * @type string $month Optional when passing array.The month of the year.
94 * Default (string:empty)|(array:1). Accepts numbers 1-12.
95 * @type string $day Optional when passing array.The day of the month.
96 * Default (string:empty)|(array:1). Accepts numbers 1-31.
97 * }
98 * @type string|array $after {
99 * Optional. Date to retrieve posts after. Accepts `strtotime()`-compatible string,
100 * or array of 'year', 'month', 'day' values.
101 *
102 * @type string $year The four-digit year. Accepts any four-digit year. Default empty.
103 * @type string $month Optional when passing array. The month of the year. Accepts numbers 1-12.
104 * Default (string:empty)|(array:12).
105 * @type string $day Optional when passing array.The day of the month. Accepts numbers 1-31.
106 * Default (string:empty)|(array:last day of month).
107 * }
108 * @type string $column Optional. Used to add a clause comparing a column other than
109 * the column specified in the top-level `$column` parameter.
110 * See WP_Date_Query::validate_column() and
111 * the {@see 'date_query_valid_columns'} filter for the list
112 * of accepted values. Default is the value of top-level `$column`.
113 * @type string $compare Optional. The comparison operator. Accepts '=', '!=', '>', '>=',
114 * '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'. 'IN',
115 * 'NOT IN', 'BETWEEN', and 'NOT BETWEEN'. Comparisons support
116 * arrays in some time-related parameters. Default '='.
117 * @type bool $inclusive Optional. Include results from dates specified in 'before' or
118 * 'after'. Default false.
119 * @type int|int[] $year Optional. The four-digit year number. Accepts any four-digit year
120 * or an array of years if `$compare` supports it. Default empty.
121 * @type int|int[] $month Optional. The two-digit month number. Accepts numbers 1-12 or an
122 * array of valid numbers if `$compare` supports it. Default empty.
123 * @type int|int[] $week Optional. The week number of the year. Accepts numbers 0-53 or an
124 * array of valid numbers if `$compare` supports it. Default empty.
125 * @type int|int[] $dayofyear Optional. The day number of the year. Accepts numbers 1-366 or an
126 * array of valid numbers if `$compare` supports it.
127 * @type int|int[] $day Optional. The day of the month. Accepts numbers 1-31 or an array
128 * of valid numbers if `$compare` supports it. Default empty.
129 * @type int|int[] $dayofweek Optional. The day number of the week. Accepts numbers 1-7 (1 is
130 * Sunday) or an array of valid numbers if `$compare` supports it.
131 * Default empty.
132 * @type int|int[] $dayofweek_iso Optional. The day number of the week (ISO). Accepts numbers 1-7
133 * (1 is Monday) or an array of valid numbers if `$compare` supports it.
134 * Default empty.
135 * @type int|int[] $hour Optional. The hour of the day. Accepts numbers 0-23 or an array
136 * of valid numbers if `$compare` supports it. Default empty.
137 * @type int|int[] $minute Optional. The minute of the hour. Accepts numbers 0-59 or an array
138 * of valid numbers if `$compare` supports it. Default empty.
139 * @type int|int[] $second Optional. The second of the minute. Accepts numbers 0-59 or an
140 * array of valid numbers if `$compare` supports it. Default empty.
141 * }
142 * }
143 * }
144 * @param string $default_column Optional. Default column to query against. See WP_Date_Query::validate_column()
145 * and the {@see 'date_query_valid_columns'} filter for the list of accepted values.
146 * Default 'post_date'.
147 */
148 public function __construct( $date_query, $default_column = 'post_date' ) {
149 if ( empty( $date_query ) || ! is_array( $date_query ) ) {
150 return;
151 }
152
153 if ( isset( $date_query['relation'] ) ) {
154 $this->relation = $this->sanitize_relation( $date_query['relation'] );
155 } else {
156 $this->relation = 'AND';
157 }
158
159 // Support for passing time-based keys in the top level of the $date_query array.
160 if ( ! isset( $date_query[0] ) ) {
161 $date_query = array( $date_query );
162 }
163
164 if ( ! empty( $date_query['column'] ) ) {
165 $date_query['column'] = esc_sql( $date_query['column'] );
166 } else {
167 $date_query['column'] = esc_sql( $default_column );
168 }
169
170 $this->column = $this->validate_column( $this->column );
171
172 $this->compare = $this->get_compare( $date_query );
173
174 $this->queries = $this->sanitize_query( $date_query );
175 }
176
177 /**
178 * Recursive-friendly query sanitizer.
179 *
180 * Ensures that each query-level clause has a 'relation' key, and that
181 * each first-order clause contains all the necessary keys from `$defaults`.
182 *
183 * @since 4.1.0
184 *
185 * @param array $queries
186 * @param array $parent_query
187 * @return array Sanitized queries.
188 */
189 public function sanitize_query( $queries, $parent_query = null ) {
190 $cleaned_query = array();
191
192 $defaults = array(
193 'column' => 'post_date',
194 'compare' => '=',
195 'relation' => 'AND',
196 );
197
198 // Numeric keys should always have array values.
199 foreach ( $queries as $qkey => $qvalue ) {
200 if ( is_numeric( $qkey ) && ! is_array( $qvalue ) ) {
201 unset( $queries[ $qkey ] );
202 }
203 }
204
205 // Each query should have a value for each default key. Inherit from the parent when possible.
206 foreach ( $defaults as $dkey => $dvalue ) {
207 if ( isset( $queries[ $dkey ] ) ) {
208 continue;
209 }
210
211 if ( isset( $parent_query[ $dkey ] ) ) {
212 $queries[ $dkey ] = $parent_query[ $dkey ];
213 } else {
214 $queries[ $dkey ] = $dvalue;
215 }
216 }
217
218 // Validate the dates passed in the query.
219 if ( $this->is_first_order_clause( $queries ) ) {
220 $this->validate_date_values( $queries );
221 }
222
223 // Sanitize the relation parameter.
224 $queries['relation'] = $this->sanitize_relation( $queries['relation'] );
225
226 foreach ( $queries as $key => $q ) {
227 if ( ! is_array( $q ) || in_array( $key, $this->time_keys, true ) ) {
228 // This is a first-order query. Trust the values and sanitize when building SQL.
229 $cleaned_query[ $key ] = $q;
230 } else {
231 // Any array without a time key is another query, so we recurse.
232 $cleaned_query[] = $this->sanitize_query( $q, $queries );
233 }
234 }
235
236 return $cleaned_query;
237 }
238
239 /**
240 * Determines whether this is a first-order clause.
241 *
242 * Checks to see if the current clause has any time-related keys.
243 * If so, it's first-order.
244 *
245 * @since 4.1.0
246 *
247 * @param array $query Query clause.
248 * @return bool True if this is a first-order clause.
249 */
250 protected function is_first_order_clause( $query ) {
251 $time_keys = array_intersect( $this->time_keys, array_keys( $query ) );
252 return ! empty( $time_keys );
253 }
254
255 /**
256 * Determines and validates what comparison operator to use.
257 *
258 * @since 3.7.0
259 *
260 * @param array $query A date query or a date subquery.
261 * @return string The comparison operator.
262 */
263 public function get_compare( $query ) {
264 if ( ! empty( $query['compare'] )
265 && in_array( $query['compare'], array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ), true )
266 ) {
267 return strtoupper( $query['compare'] );
268 }
269
270 return $this->compare;
271 }
272
273 /**
274 * Validates the given date_query values and triggers errors if something is not valid.
275 *
276 * Note that date queries with invalid date ranges are allowed to
277 * continue (though of course no items will be found for impossible dates).
278 * This method only generates debug notices for these cases.
279 *
280 * @since 4.1.0
281 *
282 * @param array $date_query The date_query array.
283 * @return bool True if all values in the query are valid, false if one or more fail.
284 */
285 public function validate_date_values( $date_query = array() ) {
286 if ( empty( $date_query ) ) {
287 return false;
288 }
289
290 $valid = true;
291
292 /*
293 * Validate 'before' and 'after' up front, then let the
294 * validation routine continue to be sure that all invalid
295 * values generate errors too.
296 */
297 if ( array_key_exists( 'before', $date_query ) && is_array( $date_query['before'] ) ) {
298 $valid = $this->validate_date_values( $date_query['before'] );
299 }
300
301 if ( array_key_exists( 'after', $date_query ) && is_array( $date_query['after'] ) ) {
302 $valid = $this->validate_date_values( $date_query['after'] );
303 }
304
305 // Array containing all min-max checks.
306 $min_max_checks = array();
307
308 // Days per year.
309 if ( array_key_exists( 'year', $date_query ) ) {
310 /*
311 * If a year exists in the date query, we can use it to get the days.
312 * If multiple years are provided (as in a BETWEEN), use the first one.
313 */
314 if ( is_array( $date_query['year'] ) ) {
315 $_year = reset( $date_query['year'] );
316 } else {
317 $_year = $date_query['year'];
318 }
319
320 $max_days_of_year = (int) gmdate( 'z', mktime( 0, 0, 0, 12, 31, $_year ) ) + 1;
321 } else {
322 // Otherwise we use the max of 366 (leap-year).
323 $max_days_of_year = 366;
324 }
325
326 $min_max_checks['dayofyear'] = array(
327 'min' => 1,
328 'max' => $max_days_of_year,
329 );
330
331 // Days per week.
332 $min_max_checks['dayofweek'] = array(
333 'min' => 1,
334 'max' => 7,
335 );
336
337 // Days per week.
338 $min_max_checks['dayofweek_iso'] = array(
339 'min' => 1,
340 'max' => 7,
341 );
342
343 // Months per year.
344 $min_max_checks['month'] = array(
345 'min' => 1,
346 'max' => 12,
347 );
348
349 // Weeks per year.
350 if ( isset( $_year ) ) {
351 /*
352 * If we have a specific year, use it to calculate number of weeks.
353 * Note: the number of weeks in a year is the date in which Dec 28 appears.
354 */
355 $week_count = gmdate( 'W', mktime( 0, 0, 0, 12, 28, $_year ) );
356
357 } else {
358 // Otherwise set the week-count to a maximum of 53.
359 $week_count = 53;
360 }
361
362 $min_max_checks['week'] = array(
363 'min' => 1,
364 'max' => $week_count,
365 );
366
367 // Days per month.
368 $min_max_checks['day'] = array(
369 'min' => 1,
370 'max' => 31,
371 );
372
373 // Hours per day.
374 $min_max_checks['hour'] = array(
375 'min' => 0,
376 'max' => 23,
377 );
378
379 // Minutes per hour.
380 $min_max_checks['minute'] = array(
381 'min' => 0,
382 'max' => 59,
383 );
384
385 // Seconds per minute.
386 $min_max_checks['second'] = array(
387 'min' => 0,
388 'max' => 59,
389 );
390
391 // Concatenate and throw a notice for each invalid value.
392 foreach ( $min_max_checks as $key => $check ) {
393 if ( ! array_key_exists( $key, $date_query ) ) {
394 continue;
395 }
396
397 // Throw a notice for each failing value.
398 foreach ( (array) $date_query[ $key ] as $_value ) {
399 $is_between = $_value >= $check['min'] && $_value <= $check['max'];
400
401 if ( ! is_numeric( $_value ) || ! $is_between ) {
402 $error = sprintf(
403 /* translators: Date query invalid date message. 1: Invalid value, 2: Type of value, 3: Minimum valid value, 4: Maximum valid value. */
404 __( 'Invalid value %1$s for %2$s. Expected value should be between %3$s and %4$s.' ),
405 '<code>' . esc_html( $_value ) . '</code>',
406 '<code>' . esc_html( $key ) . '</code>',
407 '<code>' . esc_html( $check['min'] ) . '</code>',
408 '<code>' . esc_html( $check['max'] ) . '</code>'
409 );
410
411 _doing_it_wrong( __CLASS__, $error, '4.1.0' );
412
413 $valid = false;
414 }
415 }
416 }
417
418 // If we already have invalid date messages, don't bother running through checkdate().
419 if ( ! $valid ) {
420 return $valid;
421 }
422
423 $day_month_year_error_msg = '';
424
425 $day_exists = array_key_exists( 'day', $date_query ) && is_numeric( $date_query['day'] );
426 $month_exists = array_key_exists( 'month', $date_query ) && is_numeric( $date_query['month'] );
427 $year_exists = array_key_exists( 'year', $date_query ) && is_numeric( $date_query['year'] );
428
429 if ( $day_exists && $month_exists && $year_exists ) {
430 // 1. Checking day, month, year combination.
431 if ( ! wp_checkdate( $date_query['month'], $date_query['day'], $date_query['year'], sprintf( '%s-%s-%s', $date_query['year'], $date_query['month'], $date_query['day'] ) ) ) {
432 $day_month_year_error_msg = sprintf(
433 /* translators: 1: Year, 2: Month, 3: Day of month. */
434 __( 'The following values do not describe a valid date: year %1$s, month %2$s, day %3$s.' ),
435 '<code>' . esc_html( $date_query['year'] ) . '</code>',
436 '<code>' . esc_html( $date_query['month'] ) . '</code>',
437 '<code>' . esc_html( $date_query['day'] ) . '</code>'
438 );
439
440 $valid = false;
441 }
442 } elseif ( $day_exists && $month_exists ) {
443 /*
444 * 2. checking day, month combination
445 * We use 2012 because, as a leap year, it's the most permissive.
446 */
447 if ( ! wp_checkdate( $date_query['month'], $date_query['day'], 2012, sprintf( '2012-%s-%s', $date_query['month'], $date_query['day'] ) ) ) {
448 $day_month_year_error_msg = sprintf(
449 /* translators: 1: Month, 2: Day of month. */
450 __( 'The following values do not describe a valid date: month %1$s, day %2$s.' ),
451 '<code>' . esc_html( $date_query['month'] ) . '</code>',
452 '<code>' . esc_html( $date_query['day'] ) . '</code>'
453 );
454
455 $valid = false;
456 }
457 }
458
459 if ( ! empty( $day_month_year_error_msg ) ) {
460 _doing_it_wrong( __CLASS__, $day_month_year_error_msg, '4.1.0' );
461 }
462
463 return $valid;
464 }
465
466 /**
467 * Validates a column name parameter.
468 *
469 * Column names without a table prefix (like 'post_date') are checked against a list of
470 * allowed and known tables, and then, if found, have a table prefix (such as 'wp_posts.')
471 * prepended. Prefixed column names (such as 'wp_posts.post_date') bypass this allowed
472 * check, and are only sanitized to remove illegal characters.
473 *
474 * @since 3.7.0
475 *
476 * @global wpdb $wpdb WordPress database abstraction object.
477 *
478 * @param string $column The user-supplied column name.
479 * @return string A validated column name value.
480 */
481 public function validate_column( $column ) {
482 global $wpdb;
483
484 $valid_columns = array(
485 'post_date', // Part of $wpdb->posts.
486 'post_date_gmt', // Part of $wpdb->posts.
487 'post_modified', // Part of $wpdb->posts.
488 'post_modified_gmt', // Part of $wpdb->posts.
489 'comment_date', // Part of $wpdb->comments.
490 'comment_date_gmt', // Part of $wpdb->comments.
491 'user_registered', // Part of $wpdb->users.
492 );
493
494 if ( is_multisite() ) {
495 $valid_columns = array_merge(
496 $valid_columns,
497 array(
498 'registered', // Part of $wpdb->blogs.
499 'last_updated', // Part of $wpdb->blogs.
500 )
501 );
502 }
503
504 // Attempt to detect a table prefix.
505 if ( ! str_contains( $column, '.' ) ) {
506 /**
507 * Filters the list of valid date query columns.
508 *
509 * @since 3.7.0
510 * @since 4.1.0 Added 'user_registered' to the default recognized columns.
511 * @since 4.6.0 Added 'registered' and 'last_updated' to the default recognized columns.
512 *
513 * @param string[] $valid_columns An array of valid date query columns. Defaults
514 * are 'post_date', 'post_date_gmt', 'post_modified',
515 * 'post_modified_gmt', 'comment_date', 'comment_date_gmt',
516 * 'user_registered', 'registered', 'last_updated'.
517 */
518 if ( ! in_array( $column, apply_filters( 'date_query_valid_columns', $valid_columns ), true ) ) {
519 $column = 'post_date';
520 }
521
522 $known_columns = array(
523 $wpdb->posts => array(
524 'post_date',
525 'post_date_gmt',
526 'post_modified',
527 'post_modified_gmt',
528 ),
529 $wpdb->comments => array(
530 'comment_date',
531 'comment_date_gmt',
532 ),
533 $wpdb->users => array(
534 'user_registered',
535 ),
536 );
537
538 if ( is_multisite() ) {
539 $known_columns[ $wpdb->blogs ] = array(
540 'registered',
541 'last_updated',
542 );
543 }
544
545 // If it's a known column name, add the appropriate table prefix.
546 foreach ( $known_columns as $table_name => $table_columns ) {
547 if ( in_array( $column, $table_columns, true ) ) {
548 $column = $table_name . '.' . $column;
549 break;
550 }
551 }
552 }
553
554 // Remove unsafe characters.
555 return preg_replace( '/[^a-zA-Z0-9_$\.]/', '', $column );
556 }
557
558 /**
559 * Generates WHERE clause to be appended to a main query.
560 *
561 * @since 3.7.0
562 *
563 * @return string MySQL WHERE clause.
564 */
565 public function get_sql() {
566 $sql = $this->get_sql_clauses();
567
568 $where = $sql['where'];
569
570 /**
571 * Filters the date query WHERE clause.
572 *
573 * @since 3.7.0
574 *
575 * @param string $where WHERE clause of the date query.
576 * @param WP_Date_Query $query The WP_Date_Query instance.
577 */
578 return apply_filters( 'get_date_sql', $where, $this );
579 }
580
581 /**
582 * Generates SQL clauses to be appended to a main query.
583 *
584 * Called by the public WP_Date_Query::get_sql(), this method is abstracted
585 * out to maintain parity with the other Query classes.
586 *
587 * @since 4.1.0
588 *
589 * @return string[] {
590 * Array containing JOIN and WHERE SQL clauses to append to the main query.
591 *
592 * @type string $join SQL fragment to append to the main JOIN clause.
593 * @type string $where SQL fragment to append to the main WHERE clause.
594 * }
595 */
596 protected function get_sql_clauses() {
597 $sql = $this->get_sql_for_query( $this->queries );
598
599 if ( ! empty( $sql['where'] ) ) {
600 $sql['where'] = ' AND ' . $sql['where'];
601 }
602
603 return $sql;
604 }
605
606 /**
607 * Generates SQL clauses for a single query array.
608 *
609 * If nested subqueries are found, this method recurses the tree to
610 * produce the properly nested SQL.
611 *
612 * @since 4.1.0
613 *
614 * @param array $query Query to parse.
615 * @param int $depth Optional. Number of tree levels deep we currently are.
616 * Used to calculate indentation. Default 0.
617 * @return array {
618 * Array containing JOIN and WHERE SQL clauses to append to a single query array.
619 *
620 * @type string $join SQL fragment to append to the main JOIN clause.
621 * @type string $where SQL fragment to append to the main WHERE clause.
622 * }
623 */
624 protected function get_sql_for_query( $query, $depth = 0 ) {
625 $sql_chunks = array(
626 'join' => array(),
627 'where' => array(),
628 );
629
630 $sql = array(
631 'join' => '',
632 'where' => '',
633 );
634
635 $indent = '';
636 for ( $i = 0; $i < $depth; $i++ ) {
637 $indent .= ' ';
638 }
639
640 foreach ( $query as $key => $clause ) {
641 if ( 'relation' === $key ) {
642 $relation = $query['relation'];
643 } elseif ( is_array( $clause ) ) {
644
645 // This is a first-order clause.
646 if ( $this->is_first_order_clause( $clause ) ) {
647 $clause_sql = $this->get_sql_for_clause( $clause, $query );
648
649 $where_count = count( $clause_sql['where'] );
650 if ( ! $where_count ) {
651 $sql_chunks['where'][] = '';
652 } elseif ( 1 === $where_count ) {
653 $sql_chunks['where'][] = $clause_sql['where'][0];
654 } else {
655 $sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )';
656 }
657
658 $sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] );
659 // This is a subquery, so we recurse.
660 } else {
661 $clause_sql = $this->get_sql_for_query( $clause, $depth + 1 );
662
663 $sql_chunks['where'][] = $clause_sql['where'];
664 $sql_chunks['join'][] = $clause_sql['join'];
665 }
666 }
667 }
668
669 // Filter to remove empties.
670 $sql_chunks['join'] = array_filter( $sql_chunks['join'] );
671 $sql_chunks['where'] = array_filter( $sql_chunks['where'] );
672
673 if ( empty( $relation ) ) {
674 $relation = 'AND';
675 }
676
677 // Filter duplicate JOIN clauses and combine into a single string.
678 if ( ! empty( $sql_chunks['join'] ) ) {
679 $sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) );
680 }
681
682 // Generate a single WHERE clause with proper brackets and indentation.
683 if ( ! empty( $sql_chunks['where'] ) ) {
684 $sql['where'] = '( ' . "\n " . $indent . implode( ' ' . "\n " . $indent . $relation . ' ' . "\n " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')';
685 }
686
687 return $sql;
688 }
689
690 /**
691 * Turns a single date clause into pieces for a WHERE clause.
692 *
693 * A wrapper for get_sql_for_clause(), included here for backward
694 * compatibility while retaining the naming convention across Query classes.
695 *
696 * @since 3.7.0
697 *
698 * @param array $query Date query arguments.
699 * @return array {
700 * Array containing JOIN and WHERE SQL clauses to append to the main query.
701 *
702 * @type string[] $join Array of SQL fragments to append to the main JOIN clause.
703 * @type string[] $where Array of SQL fragments to append to the main WHERE clause.
704 * }
705 */
706 protected function get_sql_for_subquery( $query ) {
707 return $this->get_sql_for_clause( $query, '' );
708 }
709
710 /**
711 * Turns a first-order date query into SQL for a WHERE clause.
712 *
713 * @since 4.1.0
714 *
715 * @global wpdb $wpdb WordPress database abstraction object.
716 *
717 * @param array $query Date query clause.
718 * @param array $parent_query Parent query of the current date query.
719 * @return array {
720 * Array containing JOIN and WHERE SQL clauses to append to the main query.
721 *
722 * @type string[] $join Array of SQL fragments to append to the main JOIN clause.
723 * @type string[] $where Array of SQL fragments to append to the main WHERE clause.
724 * }
725 */
726 protected function get_sql_for_clause( $query, $parent_query ) {
727 global $wpdb;
728
729 // The sub-parts of a $where part.
730 $where_parts = array();
731
732 $column = ( ! empty( $query['column'] ) ) ? esc_sql( $query['column'] ) : $this->column;
733
734 $column = $this->validate_column( $column );
735
736 $compare = $this->get_compare( $query );
737
738 $inclusive = ! empty( $query['inclusive'] );
739
740 // Assign greater- and less-than values.
741 $lt = '<';
742 $gt = '>';
743
744 if ( $inclusive ) {
745 $lt .= '=';
746 $gt .= '=';
747 }
748
749 // Range queries.
750 if ( ! empty( $query['after'] ) ) {
751 $where_parts[] = $wpdb->prepare( "$column $gt %s", $this->build_mysql_datetime( $query['after'], ! $inclusive ) );
752 }
753 if ( ! empty( $query['before'] ) ) {
754 $where_parts[] = $wpdb->prepare( "$column $lt %s", $this->build_mysql_datetime( $query['before'], $inclusive ) );
755 }
756 // Specific value queries.
757
758 $date_units = array(
759 'YEAR' => array( 'year' ),
760 'MONTH' => array( 'month', 'monthnum' ),
761 '_wp_mysql_week' => array( 'week', 'w' ),
762 'DAYOFYEAR' => array( 'dayofyear' ),
763 'DAYOFMONTH' => array( 'day' ),
764 'DAYOFWEEK' => array( 'dayofweek' ),
765 'WEEKDAY' => array( 'dayofweek_iso' ),
766 );
767
768 // Check of the possible date units and add them to the query.
769 foreach ( $date_units as $sql_part => $query_parts ) {
770 foreach ( $query_parts as $query_part ) {
771 if ( isset( $query[ $query_part ] ) ) {
772 $value = $this->build_value( $compare, $query[ $query_part ] );
773 if ( $value ) {
774 switch ( $sql_part ) {
775 case '_wp_mysql_week':
776 $where_parts[] = _wp_mysql_week( $column ) . " $compare $value";
777 break;
778 case 'WEEKDAY':
779 $where_parts[] = "$sql_part( $column ) + 1 $compare $value";
780 break;
781 default:
782 $where_parts[] = "$sql_part( $column ) $compare $value";
783 }
784
785 break;
786 }
787 }
788 }
789 }
790
791 if ( isset( $query['hour'] ) || isset( $query['minute'] ) || isset( $query['second'] ) ) {
792 // Avoid notices.
793 foreach ( array( 'hour', 'minute', 'second' ) as $unit ) {
794 if ( ! isset( $query[ $unit ] ) ) {
795 $query[ $unit ] = null;
796 }
797 }
798
799 $time_query = $this->build_time_query( $column, $compare, $query['hour'], $query['minute'], $query['second'] );
800 if ( $time_query ) {
801 $where_parts[] = $time_query;
802 }
803 }
804
805 /*
806 * Return an array of 'join' and 'where' for compatibility
807 * with other query classes.
808 */
809 return array(
810 'where' => $where_parts,
811 'join' => array(),
812 );
813 }
814
815 /**
816 * Builds and validates a value string based on the comparison operator.
817 *
818 * @since 3.7.0
819 *
820 * @param string $compare The compare operator to use.
821 * @param string|array $value The value.
822 * @return string|false|int The value to be used in SQL or false on error.
823 */
824 public function build_value( $compare, $value ) {
825 if ( ! isset( $value ) ) {
826 return false;
827 }
828
829 switch ( $compare ) {
830 case 'IN':
831 case 'NOT IN':
832 $value = (array) $value;
833
834 // Remove non-numeric values.
835 $value = array_filter( $value, 'is_numeric' );
836
837 if ( empty( $value ) ) {
838 return false;
839 }
840
841 return '(' . implode( ',', array_map( 'intval', $value ) ) . ')';
842
843 case 'BETWEEN':
844 case 'NOT BETWEEN':
845 if ( ! is_array( $value ) || 2 !== count( $value ) ) {
846 $value = array( $value, $value );
847 } else {
848 $value = array_values( $value );
849 }
850
851 // If either value is non-numeric, bail.
852 foreach ( $value as $v ) {
853 if ( ! is_numeric( $v ) ) {
854 return false;
855 }
856 }
857
858 $value = array_map( 'intval', $value );
859
860 return $value[0] . ' AND ' . $value[1];
861
862 default:
863 if ( ! is_numeric( $value ) ) {
864 return false;
865 }
866
867 return (int) $value;
868 }
869 }
870
871 /**
872 * Builds a MySQL format date/time based on some query parameters.
873 *
874 * You can pass an array of values (year, month, etc.) with missing parameter values being defaulted to
875 * either the maximum or minimum values (controlled by the $default_to parameter). Alternatively you can
876 * pass a string that will be passed to date_create().
877 *
878 * @since 3.7.0
879 *
880 * @param string|array $datetime An array of parameters or a strtotime() string.
881 * @param bool $default_to_max Whether to round up incomplete dates. Supported by values
882 * of $datetime that are arrays, or string values that are a
883 * subset of MySQL date format ('Y', 'Y-m', 'Y-m-d', 'Y-m-d H:i').
884 * Default: false.
885 * @return string|false A MySQL format date/time or false on failure.
886 */
887 public function build_mysql_datetime( $datetime, $default_to_max = false ) {
888 if ( ! is_array( $datetime ) ) {
889
890 /*
891 * Try to parse some common date formats, so we can detect
892 * the level of precision and support the 'inclusive' parameter.
893 */
894 if ( preg_match( '/^(\d{4})$/', $datetime, $matches ) ) {
895 // Y
896 $datetime = array(
897 'year' => (int) $matches[1],
898 );
899
900 } elseif ( preg_match( '/^(\d{4})\-(\d{2})$/', $datetime, $matches ) ) {
901 // Y-m
902 $datetime = array(
903 'year' => (int) $matches[1],
904 'month' => (int) $matches[2],
905 );
906
907 } elseif ( preg_match( '/^(\d{4})\-(\d{2})\-(\d{2})$/', $datetime, $matches ) ) {
908 // Y-m-d
909 $datetime = array(
910 'year' => (int) $matches[1],
911 'month' => (int) $matches[2],
912 'day' => (int) $matches[3],
913 );
914
915 } elseif ( preg_match( '/^(\d{4})\-(\d{2})\-(\d{2}) (\d{2}):(\d{2})$/', $datetime, $matches ) ) {
916 // Y-m-d H:i
917 $datetime = array(
918 'year' => (int) $matches[1],
919 'month' => (int) $matches[2],
920 'day' => (int) $matches[3],
921 'hour' => (int) $matches[4],
922 'minute' => (int) $matches[5],
923 );
924 }
925
926 // If no match is found, we don't support default_to_max.
927 if ( ! is_array( $datetime ) ) {
928 $wp_timezone = wp_timezone();
929
930 // Assume local timezone if not provided.
931 $dt = date_create( $datetime, $wp_timezone );
932
933 if ( false === $dt ) {
934 return gmdate( 'Y-m-d H:i:s', false );
935 }
936
937 return $dt->setTimezone( $wp_timezone )->format( 'Y-m-d H:i:s' );
938 }
939 }
940
941 $datetime = array_map( 'absint', $datetime );
942
943 if ( ! isset( $datetime['year'] ) ) {
944 $datetime['year'] = current_time( 'Y' );
945 }
946
947 if ( ! isset( $datetime['month'] ) ) {
948 $datetime['month'] = ( $default_to_max ) ? 12 : 1;
949 }
950
951 if ( ! isset( $datetime['day'] ) ) {
952 $datetime['day'] = ( $default_to_max ) ? (int) gmdate( 't', mktime( 0, 0, 0, $datetime['month'], 1, $datetime['year'] ) ) : 1;
953 }
954
955 if ( ! isset( $datetime['hour'] ) ) {
956 $datetime['hour'] = ( $default_to_max ) ? 23 : 0;
957 }
958
959 if ( ! isset( $datetime['minute'] ) ) {
960 $datetime['minute'] = ( $default_to_max ) ? 59 : 0;
961 }
962
963 if ( ! isset( $datetime['second'] ) ) {
964 $datetime['second'] = ( $default_to_max ) ? 59 : 0;
965 }
966
967 return sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['minute'], $datetime['second'] );
968 }
969
970 /**
971 * Builds a query string for comparing time values (hour, minute, second).
972 *
973 * If just hour, minute, or second is set than a normal comparison will be done.
974 * However if multiple values are passed, a pseudo-decimal time will be created
975 * in order to be able to accurately compare against.
976 *
977 * @since 3.7.0
978 *
979 * @global wpdb $wpdb WordPress database abstraction object.
980 *
981 * @param string $column The column to query against. Needs to be pre-validated!
982 * @param string $compare The comparison operator. Needs to be pre-validated!
983 * @param int|null $hour Optional. An hour value (0-23).
984 * @param int|null $minute Optional. A minute value (0-59).
985 * @param int|null $second Optional. A second value (0-59).
986 * @return string|false A query part or false on failure.
987 */
988 public function build_time_query( $column, $compare, $hour = null, $minute = null, $second = null ) {
989 global $wpdb;
990
991 // Have to have at least one.
992 if ( ! isset( $hour ) && ! isset( $minute ) && ! isset( $second ) ) {
993 return false;
994 }
995
996 // Complex combined queries aren't supported for multi-value queries.
997 if ( in_array( $compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ), true ) ) {
998 $return = array();
999
1000 $value = $this->build_value( $compare, $hour );
1001 if ( false !== $value ) {
1002 $return[] = "HOUR( $column ) $compare $value";
1003 }
1004
1005 $value = $this->build_value( $compare, $minute );
1006 if ( false !== $value ) {
1007 $return[] = "MINUTE( $column ) $compare $value";
1008 }
1009
1010 $value = $this->build_value( $compare, $second );
1011 if ( false !== $value ) {
1012 $return[] = "SECOND( $column ) $compare $value";
1013 }
1014
1015 return implode( ' AND ', $return );
1016 }
1017
1018 // Cases where just one unit is set.
1019 if ( isset( $hour ) && ! isset( $minute ) && ! isset( $second ) ) {
1020 $value = $this->build_value( $compare, $hour );
1021 if ( false !== $value ) {
1022 return "HOUR( $column ) $compare $value";
1023 }
1024 } elseif ( ! isset( $hour ) && isset( $minute ) && ! isset( $second ) ) {
1025 $value = $this->build_value( $compare, $minute );
1026 if ( false !== $value ) {
1027 return "MINUTE( $column ) $compare $value";
1028 }
1029 } elseif ( ! isset( $hour ) && ! isset( $minute ) && isset( $second ) ) {
1030 $value = $this->build_value( $compare, $second );
1031 if ( false !== $value ) {
1032 return "SECOND( $column ) $compare $value";
1033 }
1034 }
1035
1036 // Single units were already handled. Since hour & second isn't allowed, minute must to be set.
1037 if ( ! isset( $minute ) ) {
1038 return false;
1039 }
1040
1041 $format = '';
1042 $time = '';
1043
1044 // Hour.
1045 if ( null !== $hour ) {
1046 $format .= '%H.';
1047 $time .= sprintf( '%02d', $hour ) . '.';
1048 } else {
1049 $format .= '0.';
1050 $time .= '0.';
1051 }
1052
1053 // Minute.
1054 $format .= '%i';
1055 $time .= sprintf( '%02d', $minute );
1056
1057 if ( isset( $second ) ) {
1058 $format .= '%s';
1059 $time .= sprintf( '%02d', $second );
1060 }
1061
1062 return $wpdb->prepare( "DATE_FORMAT( $column, %s ) $compare %f", $format, $time );
1063 }
1064
1065 /**
1066 * Sanitizes a 'relation' operator.
1067 *
1068 * @since 6.0.3
1069 *
1070 * @param string $relation Raw relation key from the query argument.
1071 * @return string Sanitized relation. Either 'AND' or 'OR'.
1072 */
1073 public function sanitize_relation( $relation ) {
1074 if ( 'OR' === strtoupper( $relation ) ) {
1075 return 'OR';
1076 } else {
1077 return 'AND';
1078 }
1079 }
1080}
1081
Ui Ux Design – Teachers Night Out https://cardgames4educators.com Wed, 16 Oct 2024 22:24:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://cardgames4educators.com/wp-content/uploads/2024/06/cropped-Card-4-Educators-logo-32x32.png Ui Ux Design – Teachers Night Out https://cardgames4educators.com 32 32 Masters In English How English Speaker https://cardgames4educators.com/masters-in-english-how-english-speaker/ https://cardgames4educators.com/masters-in-english-how-english-speaker/#comments Mon, 27 May 2024 08:54:45 +0000 https://themexriver.com/wp/kadu/?p=1

Erat himenaeos neque id sagittis massa. Hac suscipit pulvinar dignissim platea magnis eu. Don tellus a pharetra inceptos efficitur dui pulvinar. Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent pulvinar odio volutpat parturient. Quisque risus finibus suspendisse mus purus magnis facilisi condimentum consectetur dui. Curae elit suspendisse cursus vehicula.

Turpis taciti class non vel pretium quis pulvinar tempor lobortis nunc. Libero phasellus parturient sapien volutpat malesuada ornare. Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae. Porta est tempor ex eget feugiat vulputate ipsum. Justo nec iaculis habitant diam arcu fermentum.

We offer comprehen sive emplo ment services such as assistance wit employer compliance.Our company is your strategic HR partner as instead of HR. john smithson

Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae.

Exploring Learning Landscapes in Academic

Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent.

]]>
https://cardgames4educators.com/masters-in-english-how-english-speaker/feed/ 1