Make WordPress Core

Changeset 36357


Ignore:
Timestamp:
01/20/2016 05:27:07 AM (9 years ago)
Author:
dd32
Message:

Comments: 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.

Merges [36277] to the 4.4 branch.
Props boonebgorges, firebird75.
Fixes #35192.

Location:
branches/4.4
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/4.4

  • branches/4.4/src/wp-includes/class-wp-comment-query.php

    r35757 r36357  
    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    /**
     
    817828        $groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
    818829
     830        $this->filtered_where_clause = $where;
     831
    819832        if ( $where ) {
    820833            $where = 'WHERE ' . $where;
     
    868881        );
    869882
    870         $where_clauses = $this->sql_clauses['where'];
    871         unset(
    872             $where_clauses['parent'],
    873             $where_clauses['parent__in'],
    874             $where_clauses['parent__not_in']
    875         );
     883        /*
     884         * The WHERE clause for the descendant query is the same as for the top-level
     885         * query, minus the `parent`, `parent__in`, and `parent__not_in` sub-clauses.
     886         */
     887        $_where = $this->filtered_where_clause;
     888        $exclude_keys = array( 'parent', 'parent__in', 'parent__not_in' );
     889        foreach ( $exclude_keys as $exclude_key ) {
     890            if ( isset( $this->sql_clauses['where'][ $exclude_key ] ) ) {
     891                $clause = $this->sql_clauses['where'][ $exclude_key ];
     892
     893                // Strip the clause as well as any adjacent ANDs.
     894                $pattern = '|(?:AND)?\s*' . $clause . '\s*(?:AND)?|';
     895                $_where_parts = preg_split( $pattern, $_where );
     896
     897                // Remove empties.
     898                $_where_parts = array_filter( array_map( 'trim', $_where_parts ) );
     899
     900                // Reassemble with an AND.
     901                $_where = implode( ' AND ', $_where_parts );
     902            }
     903        }
    876904
    877905        // Fetch an entire level of the descendant tree at a time.
     
    883911            }
    884912
    885             $where = 'WHERE ' . implode( ' AND ', $where_clauses ) . ' AND comment_parent IN (' . implode( ',', array_map( 'intval', $parent_ids ) ) . ')';
     913            $where = 'WHERE ' . $_where . ' AND comment_parent IN (' . implode( ',', array_map( 'intval', $parent_ids ) ) . ')';
    886914            $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" );
    887915
  • branches/4.4/tests/phpunit/tests/comment/query.php

    r35512 r36357  
    21132113
    21142114    /**
     2115     * @ticket 35192
     2116     */
     2117    public function test_comment_clauses_prepend_callback_should_be_respected_when_filling_descendants() {
     2118        $top_level_0 = self::factory()->comment->create( array(
     2119            'comment_post_ID' => $this->post_id,
     2120            'comment_approved' => '1',
     2121        ) );
     2122
     2123        $child1_of_0 = self::factory()->comment->create( array(
     2124            'comment_post_ID' => $this->post_id,
     2125            'comment_approved' => '1',
     2126            'comment_parent' => $top_level_0,
     2127        ) );
     2128
     2129        $child2_of_0 = self::factory()->comment->create( array(
     2130            'comment_post_ID' => $this->post_id,
     2131            'comment_approved' => '1',
     2132            'comment_parent' => $top_level_0,
     2133        ) );
     2134
     2135        $top_level_comments = self::factory()->comment->create_many( 3, array(
     2136            'comment_post_ID' => $this->post_id,
     2137            'comment_approved' => '1',
     2138        ) );
     2139
     2140        $this->to_exclude = array( $child2_of_0, $top_level_comments[1] );
     2141
     2142        add_filter( 'comments_clauses', array( $this, 'prepend_exclusions' ) );
     2143        $q = new WP_Comment_Query( array(
     2144            'post_id' => $this->post_id,
     2145            'hierarchical' => 'flat',
     2146        ) );
     2147        remove_filter( 'comments_clauses', array( $this, 'prepend_exclusions' ) );
     2148
     2149        unset( $this->to_exclude );
     2150
     2151        $this->assertEqualSets( array( $top_level_0, $child1_of_0, $top_level_comments[0], $top_level_comments[2] ), wp_list_pluck( $q->comments, 'comment_ID' ) );
     2152    }
     2153
     2154    public function prepend_exclusions( $clauses ) {
     2155        global $wpdb;
     2156        $clauses['where'] = $wpdb->prepare( 'comment_ID != %d AND comment_ID != %d AND ', $this->to_exclude[0], $this->to_exclude[1] ) . $clauses['where'];
     2157        return $clauses;
     2158    }
     2159
     2160    /**
     2161     * @ticket 35192
     2162     */
     2163    public function test_comment_clauses_append_callback_should_be_respected_when_filling_descendants() {
     2164        $top_level_0 = self::factory()->comment->create( array(
     2165            'comment_post_ID' => $this->post_id,
     2166            'comment_approved' => '1',
     2167        ) );
     2168
     2169        $child1_of_0 = self::factory()->comment->create( array(
     2170            'comment_post_ID' => $this->post_id,
     2171            'comment_approved' => '1',
     2172            'comment_parent' => $top_level_0,
     2173        ) );
     2174
     2175        $child2_of_0 = self::factory()->comment->create( array(
     2176            'comment_post_ID' => $this->post_id,
     2177            'comment_approved' => '1',
     2178            'comment_parent' => $top_level_0,
     2179        ) );
     2180
     2181        $top_level_comments = self::factory()->comment->create_many( 3, array(
     2182            'comment_post_ID' => $this->post_id,
     2183            'comment_approved' => '1',
     2184        ) );
     2185
     2186        $this->to_exclude = array( $child2_of_0, $top_level_comments[1] );
     2187
     2188        add_filter( 'comments_clauses', array( $this, 'append_exclusions' ) );
     2189        $q = new WP_Comment_Query( array(
     2190            'post_id' => $this->post_id,
     2191            'hierarchical' => 'flat',
     2192        ) );
     2193        remove_filter( 'comments_clauses', array( $this, 'append_exclusions' ) );
     2194
     2195        unset( $this->to_exclude );
     2196
     2197        $this->assertEqualSets( array( $top_level_0, $child1_of_0, $top_level_comments[0], $top_level_comments[2] ), wp_list_pluck( $q->comments, 'comment_ID' ) );
     2198    }
     2199
     2200    public function append_exclusions( $clauses ) {
     2201        global $wpdb;
     2202        $clauses['where'] .= $wpdb->prepare( ' AND comment_ID != %d AND comment_ID != %d', $this->to_exclude[0], $this->to_exclude[1] );
     2203        return $clauses;
     2204    }
     2205    /**
    21152206     * @ticket 27571
    21162207     */
Note: See TracChangeset for help on using the changeset viewer.