WordPress.org

Make WordPress Core

Ticket #18694: 18694.3.patch

File 18694.3.patch, 15.7 KB (added by Viper007Bond, 7 years ago)
  • wp-includes/comment.php

     
    200200        var $meta_query = false;
    201201
    202202        /**
     203         * Date query container
     204         *
     205         * @since 3.6.0
     206         * @access public
     207         * @var object WP_Date_Query
     208         */
     209        var $date_query = false;
     210
     211        /**
    203212         * Execute the query
    204213         *
    205214         * @since 3.1.0
     
    234243                        'meta_key' => '',
    235244                        'meta_value' => '',
    236245                        'meta_query' => '',
     246                        'date_query' => null, // See WP_Date_Query
    237247                );
    238248
    239249                $groupby = '';
     
    361371                        $groupby = "{$wpdb->comments}.comment_ID";
    362372                }
    363373
     374                if ( ! empty( $date_query ) && is_array( $date_query ) ) {
     375                        $date_query_object = new WP_Date_Query( $date_query, 'comment_date' );
     376                        $where .= $date_query_object->get_sql();
     377                }
     378
    364379                $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits', 'groupby' );
    365380                $clauses = apply_filters_ref_array( 'comments_clauses', array( compact( $pieces ), &$this ) );
    366381                foreach ( $pieces as $piece )
  • wp-includes/query.php

     
    867867        var $meta_query = false;
    868868
    869869        /**
     870         * Date query container
     871         *
     872         * @since 3.6.0
     873         * @access public
     874         * @var object WP_Date_Query
     875         */
     876        var $date_query = false;
     877
     878        /**
    870879         * Holds the data for a single object that is queried.
    871880         *
    872881         * Holds the contents of a post, page, category, attachment.
     
    20612070                                $where .= " AND SECOND($wpdb->posts.post_date)=" . substr($q['m'], 12, 2);
    20622071                }
    20632072
     2073                // Handle individual date parameters
     2074                $date_parameters = array();
     2075
    20642076                if ( '' !== $q['hour'] )
    2065                         $where .= " AND HOUR($wpdb->posts.post_date)='" . $q['hour'] . "'";
     2077                        $date_parameters['hour'] = $q['hour'];
    20662078
    20672079                if ( '' !== $q['minute'] )
    2068                         $where .= " AND MINUTE($wpdb->posts.post_date)='" . $q['minute'] . "'";
     2080                        $date_parameters['minute'] = $q['minute'];
    20692081
    20702082                if ( '' !== $q['second'] )
    2071                         $where .= " AND SECOND($wpdb->posts.post_date)='" . $q['second'] . "'";
     2083                        $date_parameters['second'] = $q['second'];
    20722084
    20732085                if ( $q['year'] )
    2074                         $where .= " AND YEAR($wpdb->posts.post_date)='" . $q['year'] . "'";
     2086                        $date_parameters['year'] = $q['year'];
    20752087
    20762088                if ( $q['monthnum'] )
    2077                         $where .= " AND MONTH($wpdb->posts.post_date)='" . $q['monthnum'] . "'";
     2089                        $date_parameters['month'] = $q['monthnum'];
    20782090
    20792091                if ( $q['day'] )
    2080                         $where .= " AND DAYOFMONTH($wpdb->posts.post_date)='" . $q['day'] . "'";
     2092                        $date_parameters['day'] = $q['day'];
    20812093
     2094                if ( $q['w'] )
     2095                        $date_parameters['week'] = $q['w'];
     2096
     2097                if ( ! empty( $date_parameters ) ) {
     2098                        $date_query = new WP_Date_Query( array( $date_parameters ) );
     2099                        $where .= $date_query->get_sql();
     2100                }
     2101                unset( $date_parameters );
     2102
     2103                // Handle complex date queries
     2104                if ( ! empty( $q['date_query'] ) ) {
     2105                        $this->date_query = new WP_Date_Query( $q['date_query'] );
     2106                        $where .= $this->date_query->get_sql();
     2107                }
     2108
    20822109                // If we've got a post_type AND its not "any" post_type.
    20832110                if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) {
    20842111                        foreach ( (array)$q['post_type'] as $_post_type ) {
     
    21472174                        $where .= " AND $wpdb->posts.post_name = '" . $q['attachment'] . "'";
    21482175                }
    21492176
    2150                 if ( $q['w'] )
    2151                         $where .= ' AND ' . _wp_mysql_week( "`$wpdb->posts`.`post_date`" ) . " = '" . $q['w'] . "'";
    21522177
    21532178                if ( intval($q['comments_popup']) )
    21542179                        $q['p'] = absint($q['comments_popup']);
     
    35533578}
    35543579
    35553580/**
     3581 * WP_Date_Query will generate a MySQL WHERE clause for the specified date-based parameters.
     3582 *
     3583 * Initialize the class by passing an array of arrays of parameters. Example:
     3584 *
     3585 * $date_query = new WP_Date_Query( array(
     3586 *              'column' => 'optional, column to query against, default is post_date',
     3587 *              'compare' => 'optional, see WP_Date_Query::get_compare()',
     3588 *              'relation' => 'optional, OR or AND, how the sub-arrays should be compared, default is AND',
     3589 *              array(
     3590 *                      'column' => 'see above',
     3591 *                      'compare' => 'see above',
     3592 *                      'after' => 'string or array, see WP_Date_Query::build_mysql_datetime()',
     3593 *                      'before' => 'string or array, see WP_Date_Query::build_mysql_datetime()',
     3594 *                      'inclusive' => 'boolean, for after/before, whether exact value should be matched or not',
     3595 *                      'year' => '4 digit int',
     3596 *                      'month' => 'int, 1-12',
     3597 *                      'week' => 'int, 0-53',
     3598 *                      'day' => 'int, 1-31',
     3599 *                      'hour' => 'int, 0-23',
     3600 *                      'minute' => 'int, 0-60',
     3601 *                      'second' => 'int, 0-60',
     3602 *              ),
     3603 *              array(
     3604 *                      ...
     3605 *              ),
     3606 *              ...
     3607 * ) );
     3608 *
     3609 * Then call the get_sql() method to get the MySQL WHERE string:
     3610 *
     3611 * $where .= $date_query->get_sql();
     3612 *
     3613 * @since 3.6.0
     3614 */
     3615class WP_Date_Query {
     3616        /**
     3617         * List of date queries.
     3618         *
     3619         * @since 3.6.0
     3620         * @access public
     3621         * @var array
     3622         */
     3623        public $queries = array();
     3624
     3625        /**
     3626         * The relation between the queries. Can be either 'AND' or 'OR' and can be changed via the query arguments.
     3627         *
     3628         * @since 3.6.0
     3629         * @access public
     3630         * @var string
     3631         */
     3632        public $relation = 'AND';
     3633
     3634        /**
     3635         * The column to query against. Can be changed via the query arguments.
     3636         *
     3637         * @since 3.6.0
     3638         * @access public
     3639         * @var string
     3640         */
     3641        public $column = 'post_date';
     3642
     3643        /**
     3644         * The value comparison operator. Can be changed via the query arguments.
     3645         *
     3646         * @since 3.6.0
     3647         * @access public
     3648         * @var array
     3649         */
     3650        public $compare = '=';
     3651
     3652        /**
     3653         * Constructor
     3654         *
     3655         * @param array $date_query A date query parameter array, see class descriptor for further details.
     3656         * @param array (optional) $default_column What column name to query against. Defaults to "post_date".
     3657         */
     3658        function __construct( $date_query, $default_column = 'post_date' ) {
     3659                if ( empty( $date_query ) || ! is_array( $date_query ) )
     3660                        return;
     3661
     3662                if ( isset( $date_query['relation'] ) && strtoupper( $date_query['relation'] ) == 'OR' ) {
     3663                        $this->relation = 'OR';
     3664                } else {
     3665                        $this->relation = 'AND';
     3666                }
     3667
     3668                if ( ! empty( $date_query['column'] ) )
     3669                        $this->column = esc_sql( $date_query['column'] );
     3670                else
     3671                        $this->column = esc_sql( $default_column );
     3672
     3673                $this->compare = $this->get_compare( $date_query );
     3674
     3675                // If an array of arrays wasn't passed, fix it
     3676                if ( ! isset( $date_query[0] ) )
     3677                        $date_query = array( $date_query );
     3678
     3679                $this->queries = array();
     3680                foreach ( $date_query as $key => $query ) {
     3681                        if ( ! is_array( $query ) )
     3682                                continue;
     3683
     3684                        $this->queries[$key] = $query;
     3685                }
     3686        }
     3687
     3688        /**
     3689         * Determines and validates what comparison operator to use.
     3690         *
     3691         * @since 3.6.0
     3692         * @access public
     3693         *
     3694         * @param array $query A date query or a date subquery
     3695         * @return string The comparison operator
     3696         */
     3697        public function get_compare( $query ) {
     3698                if ( ! empty( $query['compare'] ) && in_array( $query['compare'], array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) )
     3699                        return strtoupper( $query['compare'] );
     3700
     3701                return $this->compare;
     3702        }
     3703
     3704        /**
     3705         * Turns an array of date query parameters into a MySQL string.
     3706         *
     3707         * @since 3.6.0
     3708         * @access public
     3709         *
     3710         * @return string MySQL WHERE parameters
     3711         */
     3712        public function get_sql() {
     3713                global $wpdb;
     3714
     3715                // The parts of the final query
     3716                $where = array();
     3717
     3718                foreach ( $this->queries as $key => $query ) {
     3719
     3720                        // The sub-parts of a $where part
     3721                        $where_parts = array();
     3722
     3723                        $column = ( ! empty( $query['column'] ) ) ? esc_sql( $query['column'] ) : $this->column;
     3724
     3725                        $compare = $this->get_compare( $query );
     3726
     3727                        $lt = '<';
     3728                        $gt = '>';
     3729                        if ( ! empty( $query['inclusive'] ) ) {
     3730                                $lt .= '=';
     3731                                $gt .= '=';
     3732                        }
     3733
     3734                        // Range queries
     3735                        if ( ! empty( $query['after'] ) )
     3736                                $where_parts[] = $wpdb->prepare( "$column $gt %s", $this->build_mysql_datetime( $query['after'], true ) );
     3737
     3738                        if ( ! empty( $query['before'] ) )
     3739                                $where_parts[] = $wpdb->prepare( "$column $lt %s", $this->build_mysql_datetime( $query['before'], false ) );
     3740
     3741                        // Specific value queries
     3742
     3743                        if ( isset( $query['year'] ) && $value = $this->build_value( $compare, $query['year'] ) )
     3744                                $where_parts[] = "YEAR( $column ) $compare $value";
     3745
     3746                        if ( isset( $query['month'] ) && $value = $this->build_value( $compare, $query['month'] ) )
     3747                                $where_parts[] = "MONTH( $column ) $compare $value";
     3748
     3749                        // Legacy
     3750                        if ( isset( $query['monthnum'] ) && $value = $this->build_value( $compare, $query['monthnum'] ) )
     3751                                $where_parts[] = "MONTH( $column ) $compare $value";
     3752
     3753                        if ( isset( $query['week'] ) && false !== ( $value = $this->build_value( $compare, $query['week'] ) ) )
     3754                                $where_parts[] = _wp_mysql_week( $column ) . " $compare $value";
     3755
     3756                        // Legacy
     3757                        if ( isset( $query['w'] ) && false !== ( $value = $this->build_value( $compare, $query['w'] ) ) )
     3758                                $where_parts[] = _wp_mysql_week( $column ) . " $compare $value";
     3759
     3760                        if ( isset( $query['dayofyear'] ) && $value = $this->build_value( $compare, $query['dayofyear'] ) )
     3761                                $where_parts[] = "DAYOFYEAR( $column ) $compare $value";
     3762
     3763                        if ( isset( $query['day'] ) && $value = $this->build_value( $compare, $query['day'] ) )
     3764                                $where_parts[] = "DAYOFMONTH( $column ) $compare $value";
     3765
     3766                        if ( isset( $query['dayofweek'] ) && $value = $this->build_value( $compare, $query['dayofweek'] ) )
     3767                                $where_parts[] = "DAYOFWEEK( $column ) $compare $value";
     3768
     3769                        if ( isset( $query['hour'] ) || isset( $query['minute'] ) || isset( $query['second'] ) ) {
     3770                                // Avoid notices
     3771                                foreach ( array( 'hour', 'minute', 'second' ) as $unit ) {
     3772                                        if ( ! isset( $query[$unit] ) ) {
     3773                                                $query[$unit] = null;
     3774                                        }
     3775                                }
     3776
     3777                                if ( $time_query = $this->build_time_query( $column, $compare, $query['hour'], $query['minute'], $query['second'] ) ) {
     3778                                        $where_parts[] = $time_query;
     3779                                }
     3780                        }
     3781
     3782                        // Combine the parts of this subquery into a single string
     3783                        if ( ! empty( $where_parts ) )
     3784                                $where[$key] = '( ' . implode( ' AND ', $where_parts ) . ' )';
     3785                }
     3786
     3787                // Combine the subquery strings into a single string
     3788                if ( ! empty( $where ) )
     3789                        $where = ' AND ( ' . implode( " {$this->relation} ", $where ) . ' )';
     3790                else
     3791                        $where = '';
     3792
     3793                return apply_filters( 'get_date_sql', $where, $this );
     3794        }
     3795
     3796        /**
     3797         * Builds and validates a value string based on the comparison operator.
     3798         *
     3799         * @since 3.6.0
     3800         * @access public
     3801         *
     3802         * @param string $compare The compare operator to use
     3803         * @param string|array $value The value
     3804         * @return string|int|false The value to be used in SQL or false on error.
     3805         */
     3806        public function build_value( $compare, $value ) {
     3807                if ( ! isset( $value ) )
     3808                        return false;
     3809
     3810                switch ( $compare ) {
     3811                        case 'IN':
     3812                        case 'NOT IN':
     3813                                return '(' . implode( ',', array_map( 'intval', (array) $value ) ) . ')';
     3814
     3815                        case 'BETWEEN':
     3816                        case 'NOT BETWEEN':
     3817                                if ( ! is_array( $value ) || 2 != count( $value ) || ! isset( $value[0] ) || ! isset( $value[1] ) )
     3818                                        $value = array( $value, $value );
     3819
     3820                                $value = array_map( 'intval', $value );
     3821
     3822                                return $value[0] . ' AND ' . $value[1];
     3823
     3824                        default;
     3825                                return (int) $value;
     3826                }
     3827        }
     3828
     3829        /**
     3830         * Builds a MySQL format date/time based on some query parameters.
     3831         *
     3832         * You can pass an array of values (year, month, etc.) with missing parameter values being defaulted to
     3833         * either the maximum or minimum values (controlled by the $default_to parameter). Alternatively you can
     3834         * pass a string that that will be run through strtotime().
     3835         *
     3836         * @since 3.6.0
     3837         * @access public
     3838         *
     3839         * @param string|array $datetime An array of parameters or a strotime() string
     3840         * @param string $default_to Controls what values default to if they are missing from $datetime. Pass "min" or "max".
     3841         * @return string|false A MySQL format date/time or false on failure
     3842         */
     3843        public function build_mysql_datetime( $datetime, $default_to_max = false ) {
     3844                $now = current_time( 'timestamp' );
     3845
     3846                if ( is_array( $datetime ) ) {
     3847                        $datetime = array_map( 'absint', $datetime );
     3848
     3849                        if ( ! isset( $datetime['year'] ) )
     3850                                $datetime['year'] = gmdate( 'Y', $now );
     3851
     3852                        if ( ! isset( $datetime['month'] ) )
     3853                                $datetime['month'] = ( $default_to_max ) ? 12 : 1;
     3854
     3855                        if ( ! isset( $datetime['day'] ) )
     3856                                $datetime['day'] = ( $default_to_max ) ? (int) date( 't', mktime( 0, 0, 0, $datetime['month'], 1, $datetime['year'] ) ) : 1;
     3857
     3858                        if ( ! isset( $datetime['hour'] ) )
     3859                                $datetime['hour'] = ( $default_to_max ) ? 23 : 0;
     3860
     3861                        if ( ! isset( $datetime['minute'] ) )
     3862                                $datetime['minute'] = ( $default_to_max ) ? 59 : 0;
     3863
     3864                        if ( ! isset( $datetime['second'] ) )
     3865                                $datetime['second'] = ( $default_to_max ) ? 59 : 0;
     3866
     3867                        return sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['minute'], $datetime['second'] );
     3868                } else {
     3869                        // Timezone issues here possibly
     3870                        return gmdate( 'Y-m-d H:i:s', strtotime( $datetime, $now ) );
     3871                }
     3872
     3873                return false;
     3874        }
     3875
     3876        /**
     3877         * Builds a query string for comparing time values (hour, minute, second).
     3878         *
     3879         * If just hour, minute, or second is set than a normal comparison will be done.
     3880         * However if multiple values are passed, a pseudo-decimal time will be created
     3881         * in order to be able to accurately compare against.
     3882         *
     3883         * @since 3.6.0
     3884         * @access public
     3885         *
     3886         * @param string $column The column to query against. Needs to be pre-validated!
     3887         * @param string $compare The comparison operator. Needs to be pre-validated!
     3888         * @param int|null $hour Optional. An hour value (0-23).
     3889         * @param int|null $minute Optional. A minute value (0-59).
     3890         * @param int|null $second Optional. A second value (0-59).
     3891         * @return string|false A query part or false on failure.
     3892         */
     3893        public function build_time_query( $column, $compare, $hour = null, $minute = null, $second = null ) {
     3894                global $wpdb;
     3895
     3896                // Have to have at least one
     3897                if ( ! isset( $hour ) && ! isset( $minute ) && ! isset( $second ) )
     3898                        return false;
     3899
     3900                // Complex combined queries aren't supported for multi-value queries
     3901                if ( in_array( $compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) {
     3902                        $return = array();
     3903
     3904                        if ( isset( $hour ) && false !== ( $value = $this->build_value( $compare, $hour ) ) )
     3905                                $return[] = "HOUR( $column ) $compare $value";
     3906
     3907                        if ( isset( $minute ) && false !== ( $value = $this->build_value( $compare, $minute ) ) )
     3908                                $return[] = "MINUTE( $column ) $compare $value";
     3909
     3910                        if ( isset( $second ) && false !== ( $value = $this->build_value( $compare, $second ) ) )
     3911                                $return[] = "SECOND( $column ) $compare $value";
     3912
     3913                        return implode( ' AND ', $return );
     3914                }
     3915
     3916                // Cases where just one unit is set
     3917                if ( isset( $hour ) && ! isset( $minute ) && ! isset( $second ) && false !== ( $value = $this->build_value( $compare, $hour ) ) ) {
     3918                        return "HOUR( $column ) $compare $value";
     3919                } elseif ( ! isset( $hour ) && isset( $minute ) && ! isset( $second ) && false !== ( $value = $this->build_value( $compare, $minute ) ) ) {
     3920                        return "MINUTE( $column ) $compare $value";
     3921                } elseif ( ! isset( $hour ) && ! isset( $minute ) && isset( $second ) && false !== ( $value = $this->build_value( $compare, $second ) ) ) {
     3922                        return "SECOND( $column ) $compare $value";
     3923                }
     3924
     3925                // Single units were already handled. Since hour & second isn't allowed, minute must to be set.
     3926                if ( ! isset( $minute ) )
     3927                        return false;
     3928
     3929                $format = $time = '';
     3930
     3931                // Hour
     3932                if ( $hour ) {
     3933                        $format .= '%H.';
     3934                        $time   .= sprintf( '%02d', $hour ) . '.';
     3935                } else {
     3936                        $format .= '0.';
     3937                        $time   .= '0.';
     3938                }
     3939
     3940                // Minute
     3941                $format .= '%i';
     3942                $time   .= sprintf( '%02d', $minute );
     3943
     3944                if ( isset( $second ) ) {
     3945                        $format .= '%s';
     3946                        $time   .= sprintf( '%02d', $second );
     3947                }
     3948
     3949                return $wpdb->prepare( "DATE_FORMAT( $column, %s ) $compare %f", $format, $time );
     3950        }
     3951}
     3952
     3953/**
    35563954 * Redirect old slugs to the correct permalink.
    35573955 *
    35583956 * Attempts to find the current slug from the past slugs.