<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[31179] trunk: Support array values in `WP_Date_Query::validate_date_values()`.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/31179">31179</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/31179","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>boonebgorges</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2015-01-14 16:50:09 +0000 (Wed, 14 Jan 2015)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Support array values in `WP_Date_Query::validate_date_values()`.

Introduced in <a href="https://core.trac.wordpress.org/changeset/29925">[29925]</a>, `validate_date_values()` throws `_doing_it_wrong()`
notices when values passed as part of a `WP_Date_Query` do not reflect actual
dates. However, the validation did not account properly for the case where an
array of multiple values is passed, as when doing IN or BETWEEN queries.

Props dlh.
Fixes <a href="https://core.trac.wordpress.org/ticket/31001">#31001</a> for trunk.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesdatephp">trunk/src/wp-includes/date.php</a></li>
<li><a href="#trunktestsphpunittestsdatequeryphp">trunk/tests/phpunit/tests/date/query.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesdatephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/date.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/date.php    2015-01-14 05:32:19 UTC (rev 31178)
+++ trunk/src/wp-includes/date.php      2015-01-14 16:50:09 UTC (rev 31179)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -304,8 +304,17 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Days per year.
</span><span class="cx" style="display: block; padding: 0 10px">                if ( array_key_exists( 'year', $date_query ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // If a year exists in the date query, we can use it to get the days.
-                       $max_days_of_year = date( 'z', mktime( 0, 0, 0, 12, 31, $date_query['year'] ) ) + 1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 /*
+                        * If a year exists in the date query, we can use it to get the days.
+                        * If multiple years are provided (as in a BETWEEN), use the first one.
+                        */
+                       if ( is_array( $date_query['year'] ) ) {
+                               $_year = reset( $date_query['year'] );
+                       } else {
+                               $_year = $date_query['year'];
+                       }
+
+                       $max_days_of_year = date( 'z', mktime( 0, 0, 0, 12, 31, $_year ) ) + 1;
</ins><span class="cx" style="display: block; padding: 0 10px">                 } else {
</span><span class="cx" style="display: block; padding: 0 10px">                        // otherwise we use the max of 366 (leap-year)
</span><span class="cx" style="display: block; padding: 0 10px">                        $max_days_of_year = 366;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -335,10 +344,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Weeks per year.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( array_key_exists( 'year', $date_query ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( isset( $_year ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         // If we have a specific year, use it to calculate number of weeks.
</span><span class="cx" style="display: block; padding: 0 10px">                        $date = new DateTime();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $date->setISODate( $date_query['year'], 53 );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $date->setISODate( $_year, 53 );
</ins><span class="cx" style="display: block; padding: 0 10px">                         $week_count = $date->format( "W" ) === "53" ? 53 : 52;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                } else {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -381,22 +390,25 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                continue;
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $is_between = $date_query[ $key ] >= $check['min'] && $date_query[ $key ] <= $check['max'];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Throw a notice for each failing value.
+                       $is_between = true;
+                       foreach ( (array) $date_query[ $key ] as $_value ) {
+                               $is_between = $_value >= $check['min'] && $_value <= $check['max'];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        if ( ! $is_between ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         if ( ! $is_between ) {
+                                       $error = sprintf(
+                                               /* translators: Date query invalid date message: 1: invalid value, 2: type of value, 3: minimum valid value, 4: maximum valid value */
+                                               __( 'Invalid value %1$s for %2$s. Expected value should be between %3$s and %4$s.' ),
+                                               '<code>' . esc_html( $_value ) . '</code>',
+                                               '<code>' . esc_html( $key ) . '</code>',
+                                               '<code>' . esc_html( $check['min'] ) . '</code>',
+                                               '<code>' . esc_html( $check['max'] ) . '</code>'
+                                       );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $error = sprintf(
-                                       /* translators: Date query invalid date message: 1: invalid value, 2: type of value, 3: minimum valid value, 4: maximum valid value */
-                                       __( 'Invalid value %1$s for %2$s. Expected value should be between %3$s and %4$s.' ),
-                                       '<code>' . esc_html( $date_query[ $key ] ) . '</code>',
-                                       '<code>' . esc_html( $key ) . '</code>',
-                                       '<code>' . esc_html( $check['min'] ) . '</code>',
-                                       '<code>' . esc_html( $check['max'] ) . '</code>'
-                               );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 _doing_it_wrong( __CLASS__, $error, '4.1.0' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                _doing_it_wrong( __CLASS__, $error, '4.1.0' );
-
-                               $valid = false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 $valid = false;
+                               }
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunktestsphpunittestsdatequeryphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/date/query.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/date/query.php  2015-01-14 05:32:19 UTC (rev 31178)
+++ trunk/tests/phpunit/tests/date/query.php    2015-01-14 16:50:09 UTC (rev 31179)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -960,6 +960,68 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * @ticket 31001
+        */
+       public function test_validate_date_values_should_process_array_value_for_year() {
+               $p1 = $this->factory->post->create( array( 'post_date' => '2015-01-12' ) );
+               $p2 = $this->factory->post->create( array( 'post_date' => '2013-01-12' ) );
+
+               $q = new WP_Query( array(
+                       'date_query' => array(
+                               array(
+                                       'compare' => 'BETWEEN',
+                                       'year' => array( 2012, 2014 ),
+                               ),
+                       ),
+                       'fields' => 'ids',
+               ) );
+
+               $this->assertEquals( array( $p2 ), $q->posts );
+       }
+
+       /**
+        * @ticket 31001
+        */
+       public function test_validate_date_values_should_process_array_value_for_day() {
+               $p1 = $this->factory->post->create( array( 'post_date' => '2015-01-12' ) );
+               $p2 = $this->factory->post->create( array( 'post_date' => '2015-01-10' ) );
+
+               $q = new WP_Query( array(
+                       'date_query' => array(
+                               array(
+                                       'compare' => 'BETWEEN',
+                                       'day' => array( 9, 11 ),
+                               ),
+                       ),
+                       'fields' => 'ids',
+               ) );
+
+               $this->assertEquals( array( $p2 ), $q->posts );
+       }
+
+       /**
+        * @ticket 31001
+        * @expectedIncorrectUsage WP_Date_Query
+        */
+       public function test_validate_date_values_should_process_array_value_for_day_when_values_are_invalid() {
+               $p1 = $this->factory->post->create( array( 'post_date' => '2015-01-12' ) );
+               $p2 = $this->factory->post->create( array( 'post_date' => '2015-01-10' ) );
+
+               $q = new WP_Query( array(
+                       'date_query' => array(
+                               array(
+                                       'compare' => 'BETWEEN',
+                                       'day' => array( 9, 32 ),
+                               ),
+                       ),
+                       'fields' => 'ids',
+               ) );
+
+               // MySQL ignores the invalid clause.
+               $this->assertEquals( array( $p1, $p2 ), $q->posts );
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         /** Helpers **********************************************************/
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        public function date_query_valid_columns_callback( $columns ) {
</span></span></pre>
</div>
</div>

</body>
</html>