WordPress.org

Make WordPress Core

Ticket #18694: 18694.test.patch

File 18694.test.patch, 11.6 KB (added by Viper007Bond, 3 years ago)

Preliminary patch for testing purposes, still a work in progress (see comments)

  • wp-includes/query.php

     
    20752075                if ( $q['day'] ) 
    20762076                        $where .= " AND DAYOFMONTH($wpdb->posts.post_date)='" . $q['day'] . "'"; 
    20772077 
     2078                // Temporary 
     2079                if ( ! empty( $q['date_query'] ) ) { 
     2080                        $date_query = new WP_Date_Query( $q['date_query'] ); 
     2081                        $where .= $date_query->get_sql(); 
     2082                } 
     2083 
    20782084                // If we've got a post_type AND its not "any" post_type. 
    20792085                if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) { 
    20802086                        foreach ( (array)$q['post_type'] as $_post_type ) { 
     
    35543560} 
    35553561 
    35563562/** 
     3563 * Container class for a date query 
     3564 * 
     3565 * @since 3.4.0 
     3566 */ 
     3567class WP_Date_Query { 
     3568        /** 
     3569        * List of date queries. A single query is an associative array: 
     3570        * 
     3571        * TODO: DOCUMENT AVAILABLE VARS 
     3572        * 
     3573        * @since 3.4.0 
     3574        * @access public 
     3575        * @var array 
     3576        */ 
     3577        public $queries = array(); 
     3578 
     3579        /** 
     3580         * The relation between the queries. Can be one of 'AND' or 'OR'. 
     3581         * 
     3582         * @since 3.4.0 
     3583         * @access public 
     3584         * @var string 
     3585         */ 
     3586        public $relation; 
     3587 
     3588        /** 
     3589         * The column to query against. Can be changed via the query arguments. 
     3590         * 
     3591         * @since 3.4.0 
     3592         * @access public 
     3593         * @var string 
     3594         */ 
     3595        public $column = 'post_date'; 
     3596 
     3597        /** 
     3598         * The value comparison operator. Can be changed via the query arguments. 
     3599         * 
     3600         * @since 3.4.0 
     3601         * @access public 
     3602         * @var array 
     3603         */ 
     3604        public $compare = '='; 
     3605 
     3606        /** 
     3607         * Constructor 
     3608         * 
     3609         * @param array (optional) $date_query A date query parameter array 
     3610         */ 
     3611        function __construct( $date_query = false ) { 
     3612                if ( empty( $date_query ) || ! is_array( $date_query ) ) 
     3613                        return false; 
     3614 
     3615                if ( isset( $date_query['relation'] ) && strtoupper( $date_query['relation'] ) == 'OR' ) { 
     3616                        $this->relation = 'OR'; 
     3617                } else { 
     3618                        $this->relation = 'AND'; 
     3619                } 
     3620 
     3621                $this->column  = $this->get_column( $date_query ); 
     3622                $this->compare = $this->get_compare( $date_query ); 
     3623 
     3624                $this->queries = array(); 
     3625                foreach ( $date_query as $key => $query ) { 
     3626                        if ( ! is_array( $query ) ) 
     3627                                continue; 
     3628 
     3629                        $this->queries[$key] = $query; 
     3630                } 
     3631        } 
     3632 
     3633        /** 
     3634         * Determines and validates what database column to query against. 
     3635         * 
     3636         * @since 3.4.0 
     3637         * @access public 
     3638         * 
     3639         * @param array $query A date query or a date subquery 
     3640         * @return string The column to query against 
     3641         */ 
     3642        public function get_column( $query ) { 
     3643                if ( isset( $query['column'] ) && in_array( $query['column'], array( 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt' ) ) ) 
     3644                        return strtolower( $query['column'] ); 
     3645 
     3646                return $this->column; 
     3647        } 
     3648 
     3649        /** 
     3650         * Determines and validates what comparison operator to use. 
     3651         * 
     3652         * @since 3.4.0 
     3653         * @access public 
     3654         * 
     3655         * @param array $query A date query or a date subquery 
     3656         * @return string The comparison operator 
     3657         */ 
     3658        public function get_compare( $query ) { 
     3659                if ( ! empty( $query['compare'] ) && in_array( $query['compare'], array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) 
     3660                        return strtoupper( $query['compare'] ); 
     3661 
     3662                return $this->compare; 
     3663        } 
     3664 
     3665        /** 
     3666         * Turns an array of date query parameters into a MySQL string. 
     3667         * 
     3668         * @since 3.4.0 
     3669         * @access public 
     3670         * 
     3671         * @return string MySQL WHERE parameters 
     3672         */ 
     3673        public function get_sql() { 
     3674                global $wpdb; 
     3675 
     3676                // The parts of the final query 
     3677                $where = array(); 
     3678 
     3679                $valid_args = array( 
     3680                        'column', 
     3681                        'compare', 
     3682                        'inclusive', 
     3683                        'after', 
     3684                        'before', 
     3685                        'hour', 
     3686                        'minute', 
     3687                        'second', 
     3688                        'dayofweek', 
     3689                ); 
     3690 
     3691                foreach ( $this->queries as $key => $query ) { 
     3692                        // Makes life easier while avoiding notices 
     3693                        foreach ( $valid_args as $valid_arg ) { 
     3694                                if ( ! isset( $query[$valid_arg] ) ) { 
     3695                                        $query[$valid_arg] = null; 
     3696                                } 
     3697                        } 
     3698 
     3699                        // The parts of a $where part (Queryception!) 
     3700                        $where_parts = array(); 
     3701 
     3702                        // Figure out what column to use in this subquery, defaulting to the overall column 
     3703                        $column = $wpdb->posts . '.' . $this->get_column( $query ); 
     3704 
     3705                        // Range queries 
     3706                        if ( ! empty( $query['after'] ) || ! empty( $query['before'] ) ) { 
     3707                                $lt = ( $query['inclusive'] ) ? '<=' : '<'; 
     3708                                $gt = ( $query['inclusive'] ) ? '>=' : '>'; 
     3709 
     3710                                if ( $query['after'] ) 
     3711                                        $where_parts[] = $wpdb->prepare( "$column $gt %s", $this->build_mysql_datetime( $query['after'] ) ); 
     3712                                 
     3713                                if ( $query['before'] ) 
     3714                                        $where_parts[] = $wpdb->prepare( "$column $lt %s", $this->build_mysql_datetime( $query['before'] ) ); 
     3715                        } 
     3716 
     3717                        // Specific value queries 
     3718                        else { 
     3719                                $compare = $this->get_compare( $query ); 
     3720 
     3721                                if ( isset( $query['year'] ) && $value = $this->build_value( $compare, $query['year'] ) ) 
     3722                                        $where_parts[] = "YEAR( $column ) $compare $value"; 
     3723 
     3724                                if ( isset( $query['month'] ) && $value = $this->build_value( $compare, $query['month'] ) ) 
     3725                                        $where_parts[] = "MONTH( $column ) $compare $value"; 
     3726 
     3727                                // Legacy 
     3728                                if ( isset( $query['monthnum'] ) && $value = $this->build_value( $compare, $query['monthnum'] ) ) 
     3729                                        $where_parts[] = "MONTH( $column ) $compare $value"; 
     3730 
     3731                                if ( isset( $query['week'] ) && $value = $this->build_value( $compare, $query['week'] ) ) 
     3732                                        $where_parts[] = "WEEK( $column ) $compare $value"; 
     3733 
     3734                                // Legacy 
     3735                                if ( isset( $query['w'] ) && $value = $this->build_value( $compare, $query['w'] ) ) 
     3736                                        $where_parts[] = "WEEK( $column ) $compare $value"; 
     3737 
     3738                                if ( isset( $query['dayofyear'] ) && $value = $this->build_value( $compare, $query['dayofyear'] ) ) 
     3739                                        $where_parts[] = "DAYOFYEAR( $column ) $compare $value"; 
     3740 
     3741                                if ( isset( $query['day'] ) && $value = $this->build_value( $compare, $query['day'] ) ) 
     3742                                        $where_parts[] = "DAYOFMONTH( $column ) $compare $value"; 
     3743 
     3744                                if ( isset( $query['dayofweek'] ) && $value = $this->build_value( $compare, $query['dayofweek'] ) ) 
     3745                                        $where_parts[] = "DAYOFWEEK( $column ) $compare $value"; 
     3746 
     3747                                if ( isset( $query['hour'] ) || isset( $query['minute'] ) || isset( $query['second'] ) ) { 
     3748                                        if ( $time_query = $this->build_time_query( $column, $compare, $query['hour'], $query['minute'], $query['second'] ) ) { 
     3749                                                $where_parts[] = $time_query; 
     3750                                        } 
     3751                                } 
     3752                        } 
     3753 
     3754                        // Combine the parts of this subquery into a single string 
     3755                        if ( ! empty( $where_parts ) ) 
     3756                                $where[$key] = '( ' . implode( ' AND ', $where_parts ) . ' )'; 
     3757                } 
     3758 
     3759                // Combine the subquery strings into a single string 
     3760                if ( ! empty( $where ) ) 
     3761                        $where = ' AND ( ' . implode( " {$this->relation} ", $where ) . ' )'; 
     3762                else 
     3763                        $where = ''; 
     3764 
     3765                return apply_filters( 'get_date_sql', $where, $this->queries ); 
     3766        } 
     3767 
     3768        /** 
     3769         * Builds and validates a value string based on the comparison operator. 
     3770         * 
     3771         * @since 3.4.0 
     3772         * @access public 
     3773         * 
     3774         * @param string $compare The compare operator to use 
     3775         * @param string|array $value The value 
     3776         * @return string|int The value to be used in SQL 
     3777         */ 
     3778        public function build_value( $compare, $value ) { 
     3779                if ( ! isset( $value ) ) 
     3780                        return false; 
     3781 
     3782                switch ( $compare ) { 
     3783                        case 'IN': 
     3784                        case 'NOT IN': 
     3785                                return '(' . implode( ',', array_map( 'intval', (array) $value ) ) . ')'; 
     3786 
     3787                        case 'BETWEEN': 
     3788                        case 'NOT BETWEEN': 
     3789                                if ( ! is_array( $value ) || 2 != count( $value ) || ! isset( $value[0] ) || ! isset( $value[1] ) ) 
     3790                                        $value = array( $value, $value ); 
     3791 
     3792                                $value = array_map( 'intval', $value ); 
     3793 
     3794                                return $value[0] . ' AND ' . $value[1]; 
     3795 
     3796                        default; 
     3797                                return (int) $value; 
     3798                } 
     3799        } 
     3800 
     3801        /** 
     3802         * Builds a MySQL format date/time based on some query parameters. 
     3803         * 
     3804         * You can pass an array of values (year, month, etc.) with missing parameter values being defaulted to 0 
     3805         * or you can pass a string that will be run through strtotime(). 
     3806         * 
     3807         * @since 3.4.0 
     3808         * @access public 
     3809         * 
     3810         * @param string|array $datetime An array of parameters or a strotime() string 
     3811         * @return string|false A MySQL format date/time or false on failure 
     3812         */ 
     3813        public function build_mysql_datetime( $datetime ) { 
     3814                $now = current_time( 'timestamp' ); 
     3815 
     3816                if ( is_array( $datetime ) ) { 
     3817                        if ( ! isset( $datetime['year'] ) ) 
     3818                                $datetime['year'] = gmdate( 'Y', $now ); 
     3819 
     3820                        if ( ! isset( $datetime['month'] ) ) 
     3821                                $datetime['month'] = 1; 
     3822 
     3823                        if ( ! isset( $datetime['day'] ) ) 
     3824                                $datetime['day'] = 1; 
     3825 
     3826                        if ( ! isset( $datetime['hour'] ) ) 
     3827                                $datetime['hour'] = 0; 
     3828 
     3829                        if ( ! isset( $datetime['minute'] ) ) 
     3830                                $datetime['minute'] = 0; 
     3831 
     3832                        if ( ! isset( $datetime['second'] ) ) 
     3833                                $datetime['second'] = 0; 
     3834 
     3835                        $datetime = array_map( 'intval', $datetime ); 
     3836 
     3837                        return sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['minute'], $datetime['second'] ); 
     3838                } else { 
     3839                        // Timezone issues here possibly 
     3840                        return gmdate( 'Y-m-d H:i:s', strtotime( $datetime, $now ) ); 
     3841                } 
     3842 
     3843                return false; 
     3844        } 
     3845 
     3846        /** 
     3847         * Builds a query string for comparing time values (hour, minute, second). 
     3848         * 
     3849         * If just hour, minute, or second is set than a normal comparison will be done. 
     3850         * However if multiple values are passed, a pseudo-decimal time will be created 
     3851         * in order to be able to accurately compare against. 
     3852         * 
     3853         * @since 3.4.0 
     3854         * @access public 
     3855         * 
     3856         * @param string $column The column to query against. Needs to be pre-validated! 
     3857         * @param string $compare The comparison operator. Needs to be pre-validated! 
     3858         * @param int|null $hour Optional. An hour value (0-23). 
     3859         * @param int|null $minute Optional. A minute value (0-59). 
     3860         * @param int|null $second Optional. A second value (0-59). 
     3861         * @return string|false A query part or false on failure. 
     3862         */ 
     3863        public function build_time_query( $column, $compare, $hour = null, $minute = null, $second = null ) { 
     3864                global $wpdb; 
     3865 
     3866                // Have to have at least one 
     3867                if ( ! isset( $hour ) && ! isset( $minute ) && ! isset( $second ) ) 
     3868                        return false; 
     3869 
     3870                // Complex combined queries aren't supported for multi-value queries 
     3871                if ( in_array( $compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) { 
     3872                        $return = array(); 
     3873 
     3874                        if ( isset( $hour ) && $value = $this->build_value( $compare, $hour ) ) 
     3875                                $return[] = "HOUR( $column ) $compare $value"; 
     3876 
     3877                        if ( isset( $minute ) && $value = $this->build_value( $compare, $minute ) ) 
     3878                                $return[] = "MINUTE( $column ) $compare $value"; 
     3879 
     3880                        if ( isset( $second ) && $value = $this->build_value( $compare, $second ) ) 
     3881                                $return[] = "SECOND( $column ) $compare $value"; 
     3882 
     3883                        return implode( ' AND ', $return ); 
     3884                } 
     3885 
     3886                // Cases where just one unit is set 
     3887                if ( isset( $hour ) && ! isset( $minute ) && ! isset( $second ) && $value = $this->build_value( $compare, $hour ) ) { 
     3888                        return "HOUR( $column ) $compare $value"; 
     3889                } elseif ( ! isset( $hour ) && isset( $minute ) && ! isset( $second ) && $value = $this->build_value( $compare, $minute ) ) { 
     3890                        return "MINUTE( $column ) $compare $value"; 
     3891                } elseif ( ! isset( $hour ) && ! isset( $minute ) && isset( $second ) && $value = $this->build_value( $compare, $second ) ) { 
     3892                        return "SECOND( $column ) $compare $value"; 
     3893                } 
     3894 
     3895                // Single units were already handled. Since hour & second isn't allowed, minute must to be set. 
     3896                if ( ! isset( $minute ) ) 
     3897                        return false; 
     3898 
     3899                $format = $time = ''; 
     3900 
     3901                // Hour 
     3902                if ( $hour ) { 
     3903                        $format .= '%H.'; 
     3904                        $time   .= sprintf( '%02d', $hour ) . '.'; 
     3905                } else { 
     3906                        $format .= '0.'; 
     3907                        $time   .= '0.'; 
     3908                } 
     3909 
     3910                // Minute 
     3911                $format .= '%i'; 
     3912                $time   .= sprintf( '%02d', $minute ); 
     3913 
     3914                if ( isset( $second ) ) { 
     3915                        $format .= '%s'; 
     3916                        $time   .= sprintf( '%02d', $second ); 
     3917                } 
     3918 
     3919                return $wpdb->prepare( "DATE_FORMAT( $column, %s ) $compare %f", $format, $time ); 
     3920        } 
     3921} 
     3922 
     3923/** 
    35573924 * Set up global post data. 
    35583925 * 
    35593926 * @since 1.5.0 
     
    35963963 
    35973964        return true; 
    35983965} 
    3599 ?> 
     3966 
     3967?> 
     3968 No newline at end of file