Make WordPress Core

Changeset 36277 for trunk


Ignore:
Timestamp:
01/13/2016 04:00:36 AM (11 years ago)
Author:
boonebgorges
Message:

Use the post-filter WHERE clause when querying for comment descendants.

The descendant query in WP_Comment_Query::fill_descendants() uses the clauses
of the main get_comment_ids() query as a basis, discarding the parent,
parent__in, and parent__not_in clauses. As implemented in WP 4.4 [34546],
the WHERE clause was assembled in such a way that any modifications applied
using the comments_clauses filter were not inherited by fill_descendants().
This resulted in descendant queries that did not always properly filter
results, and sometimes contained syntax errors.

The current changeset fixes the problem by using the post-filter WHERE clause
as the basis for the fill_descendants() query. This change requires a new
approach for eliminating the unneeded parent-related clauses: instead of
eliminating values in an associative array, we must use regular expressions.

Props boonebgorges, firebird75.
Fixes #35192.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-comment-query.php

    r36224 r36277  
    5959                'limits'  => '',
    6060        );
     61
     62        /**
     63         * SQL WHERE clause.
     64         *
     65         * Stored after the 'comments_clauses' filter is run on the compiled WHERE sub-clauses.
     66         *
     67         * @since 4.4.2
     68         * @access protected
     69         * @var string
     70         */
     71        protected $filtered_where_clause;
    6172
    6273        /**
    … …  
    824835                $groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
    825836
     837                $this->filtered_where_clause = $where;
     838
    826839                if ( $where ) {
    827840                        $where = 'WHERE ' . $where;
    … …  
    875888                );
    876889
    877                 $where_clauses = $this->sql_clauses['where'];
    878                 unset(
    879                         $where_clauses['parent'],
    880                         $where_clauses['parent__in'],
    881                         $where_clauses['parent__not_in']
    882                 );
     890                /*
     891                 * The WHERE clause for the descendant query is the same as for the top-level
     892                 * query, minus the `parent`, `parent__in`, and `parent__not_in` sub-clauses.
     893                 */
     894                $_where = $this->filtered_where_clause;
     895                $exclude_keys = array( 'parent', 'parent__in', 'parent__not_in' );
     896                foreach ( $exclude_keys as $exclude_key ) {
     897                        if ( isset( $this->sql_clauses['where'][ $exclude_key ] ) ) {
     898                                $clause = $this->sql_clauses['where'][ $exclude_key ];
     899
     900                                // Strip the clause as well as any adjacent ANDs.
     901                                $pattern = '|(?:AND)?\s*' . $clause . '\s*(?:AND)?|';
     902                                $_where_parts = preg_split( $pattern, $_where );
     903
     904                                // Remove empties.
     905                                $_where_parts = array_filter( array_map( 'trim', $_where_parts ) );
     906
     907                                // Reassemble with an AND.
     908                                $_where = implode( ' AND ', $_where_parts );
     909                        }
     910                }
    883911
    884912                // Fetch an entire level of the descendant tree at a time.
    … …  
    890918                        }
    891919
    892                         $where = 'WHERE ' . implode( ' AND ', $where_clauses ) . ' AND comment_parent IN (' . implode( ',', array_map( 'intval', $parent_ids ) ) . ')';
     920                        $where = 'WHERE ' . $_where . ' AND comment_parent IN (' . implode( ',', array_map( 'intval', $parent_ids ) ) . ')';
    893921                        $comment_ids = $wpdb->get_col( "{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['groupby']} ORDER BY comment_date_gmt ASC, comment_ID ASC" );
    894922
  • trunk/tests/phpunit/tests/comment/query.php

    r36224 r36277  
    21302130
    21312131        /**
     2132         * @ticket 35192
     2133         */
     2134        public function test_comment_clauses_prepend_callback_should_be_respected_when_filling_descendants() {
     2135                $top_level_0 = self::factory()->comment->create( array(
     2136                        'comment_post_ID' => $this->post_id,
     2137                        'comment_approved' => '1',
     2138                ) );
     2139
     2140                $child1_of_0 = self::factory()->comment->create( array(
     2141                        'comment_post_ID' => $this->post_id,
     2142                        'comment_approved' => '1',
     2143                        'comment_parent' => $top_level_0,
     2144                ) );
     2145
     2146                $child2_of_0 = self::factory()->comment->create( array(
     2147                        'comment_post_ID' => $this->post_id,
     2148                        'comment_approved' => '1',
     2149                        'comment_parent' => $top_level_0,
     2150                ) );
     2151
     2152                $top_level_comments = self::factory()->comment->create_many( 3, array(
     2153                        'comment_post_ID' => $this->post_id,
     2154                        'comment_approved' => '1',
     2155                ) );
     2156
     2157                $this->to_exclude = array( $child2_of_0, $top_level_comments[1] );
     2158
     2159                add_filter( 'comments_clauses', array( $this, 'prepend_exclusions' ) );
     2160                $q = new WP_Comment_Query( array(
     2161                        'post_id' => $this->post_id,
     2162                        'hierarchical' => 'flat',
     2163                ) );
     2164                remove_filter( 'comments_clauses', array( $this, 'prepend_exclusions' ) );
     2165
     2166                unset( $this->to_exclude );
     2167
     2168                $this->assertEqualSets( array( $top_level_0, $child1_of_0, $top_level_comments[0], $top_level_comments[2] ), wp_list_pluck( $q->comments, 'comment_ID' ) );
     2169        }
     2170
     2171        public function prepend_exclusions( $clauses ) {
     2172                global $wpdb;
     2173                $clauses['where'] = $wpdb->prepare( 'comment_ID != %d AND comment_ID != %d AND ', $this->to_exclude[0], $this->to_exclude[1] ) . $clauses['where'];
     2174                return $clauses;
     2175        }
     2176
     2177        /**
     2178         * @ticket 35192
     2179         */
     2180        public function test_comment_clauses_append_callback_should_be_respected_when_filling_descendants() {
     2181                $top_level_0 = self::factory()->comment->create( array(
     2182                        'comment_post_ID' => $this->post_id,
     2183                        'comment_approved' => '1',
     2184                ) );
     2185
     2186                $child1_of_0 = self::factory()->comment->create( array(
     2187                        'comment_post_ID' => $this->post_id,
     2188                        'comment_approved' => '1',
     2189                        'comment_parent' => $top_level_0,
     2190                ) );
     2191
     2192                $child2_of_0 = self::factory()->comment->create( array(
     2193                        'comment_post_ID' => $this->post_id,
     2194                        'comment_approved' => '1',
     2195                        'comment_parent' => $top_level_0,
     2196                ) );
     2197
     2198                $top_level_comments = self::factory()->comment->create_many( 3, array(
     2199                        'comment_post_ID' => $this->post_id,
     2200                        'comment_approved' => '1',
     2201                ) );
     2202
     2203                $this->to_exclude = array( $child2_of_0, $top_level_comments[1] );
     2204
     2205                add_filter( 'comments_clauses', array( $this, 'append_exclusions' ) );
     2206                $q = new WP_Comment_Query( array(
     2207                        'post_id' => $this->post_id,
     2208                        'hierarchical' => 'flat',
     2209                ) );
     2210                remove_filter( 'comments_clauses', array( $this, 'append_exclusions' ) );
     2211
     2212                unset( $this->to_exclude );
     2213
     2214                $this->assertEqualSets( array( $top_level_0, $child1_of_0, $top_level_comments[0], $top_level_comments[2] ), wp_list_pluck( $q->comments, 'comment_ID' ) );
     2215        }
     2216
     2217        public function append_exclusions( $clauses ) {
     2218                global $wpdb;
     2219                $clauses['where'] .= $wpdb->prepare( ' AND comment_ID != %d AND comment_ID != %d', $this->to_exclude[0], $this->to_exclude[1] );
     2220                return $clauses;
     2221        }
     2222        /**
    21322223         * @ticket 27571
    21332224         */
Note: See TracChangeset for help on using the changeset viewer.