WordPress.org

Make WordPress Core

Changeset 27635


Ignore:
Timestamp:
03/20/2014 02:58:48 AM (4 years ago)
Author:
nacin
Message:

Fix various issues with WP_Adjacent_Post:

  • Performance / number of queries.
  • Incorrect results caused by sticky posts.
  • Back compat for filters, which had used "WHERE" while WP_Query does not; and fixing table references.

props ethitter.
fixes #26937.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/link-template.php

    r27409 r27635  
    12441244
    12451245    /**
    1246      * Allow direct access to adjacent post from the class instance itself
     1246     * Allow direct access to adjacent post from the class instance itself.
    12471247     *
    12481248     * @param string $property Property to get.
     
    12741274     */
    12751275    protected function get_post( $args ) {
    1276         $this->current_post = get_post( $args['post'] );
     1276        $this->current_post   = get_post( $args['post'] );
    12771277        $this->excluded_terms = array_map( 'intval', $args['excluded_terms'] );
    12781278        $this->adjacent       = $args['previous'] ? 'previous' : 'next';
     
    12921292        // Build our arguments for WP_Query.
    12931293        $query_args = array(
    1294             'posts_per_page'   => 1,
    1295             'post_status'      => 'publish',
    1296             'post_type'        => 'post',
    1297             'orderby'          => 'date',
    1298             'order'            => 'previous' === $this->adjacent ? 'DESC' : 'ASC',
    1299             'no_found_rows'    => true,
    1300             'cache_results'    => true,
    1301             'date_query'       => array(),
     1294            'posts_per_page'      => 1,
     1295            'post_status'         => 'publish',
     1296            'post_type'           => 'post',
     1297            'orderby'             => 'date',
     1298            'order'               => 'previous' === $this->adjacent ? 'DESC' : 'ASC',
     1299            'ignore_sticky_posts' => true,
     1300            'date_query'          => array(),
     1301
     1302            // Performance considerations:
     1303            'no_found_rows'          => true,
     1304            'cache_results'          => true,
     1305            'update_post_term_cache' => false,
     1306            'update_post_meta_cache' => false,
     1307            'split_the_query'        => wp_using_ext_object_cache(),
    13021308        );
    13031309
     
    13891395        remove_filter( 'posts_clauses', array( $this, 'filter' ) );
    13901396
    1391         /*
    1392          * The `join` and `where` filters are identical in their parameters,
    1393          * so we can use the same approach for both.
     1397        /**
     1398         * If no legacy filter callbacks are registered, proceed no further.
    13941399         */
    1395         foreach ( array( 'join', 'where' ) as $clause ) {
    1396             if ( has_filter( 'get_' . $this->adjacent . '_post_' . $clause ) ) {
    1397                 $clauses[ $clause ] = $this->filter_join_and_where( $clauses[ $clause ], $clause );
    1398             }
     1400        if ( ! has_filter( 'get_' . $this->adjacent . '_post_join' ) && ! has_filter( 'get_' . $this->adjacent . '_post_where' ) && ! has_filter( 'get_' . $this->adjacent . '_post_sort' ) ) {
     1401            return $clauses;
     1402        }
     1403
     1404        /**
     1405         * Posts table must be aliased as `p` for backwards compatibility with query previously generated by `get_adjacent_post()`.
     1406         */
     1407        $clauses = array_map( array( $this, 'alias_posts_table' ), $clauses );
     1408
     1409        /**
     1410         * Apply the legacy `join` filter.
     1411         */
     1412        if ( has_filter( 'get_' . $this->adjacent . '_post_join' ) ) {
     1413            $clauses['join'] = $this->filter_join( $clauses['join'] );
     1414        }
     1415
     1416        /**
     1417         * Posts table must be aliased as `p` for backwards compatibility with query previously generated by `get_adjacent_post()`.
     1418         * No filter on the table name exists, so we have to leverage the next applied filter, that for the `join` clause.
     1419         * We wait to apply this until after the legacy filter is applied so that the legacy filter doesn't remove the alias.
     1420         */
     1421        $clauses['join'] = 'AS p ' . $clauses['join'];
     1422
     1423        /**
     1424         * Apply the legacy `where` filter.
     1425         */
     1426        if ( has_filter( 'get_' . $this->adjacent . '_post_where' ) ) {
     1427            $clauses['where'] = $this->filter_where( $clauses['where'] );
    13991428        }
    14001429
     
    14121441
    14131442    /**
    1414      * Apply the deprecated `join` or `where` clause filter to the clauses built by WP_Query.
     1443     * Alias posts table as `p` to match query previously built by `get_adjacent_post()`.
    14151444     *
    1416      * @param string $value
    1417      * @param string $clause
     1445     * @global $wpdb
     1446     * @param string  Clause to alias
    14181447     * @return string
    14191448     */
    1420     protected function filter_join_and_where( $value, $clause ) {
     1449    protected function alias_posts_table( $clause ) {
     1450        global $wpdb;
     1451
     1452        return str_replace( $wpdb->posts, 'p', $clause );
     1453    }
     1454
     1455    /**
     1456     * Apply the deprecated `join` clause filter to the clause built by WP_Query.
     1457     *
     1458     * @param string $join
     1459     * @return string
     1460     */
     1461    protected function filter_join( $join ) {
    14211462        /**
    1422          * @todo Minimal hook docs
    14231463         * @deprecated 3.9.0
    14241464         */
    1425         return apply_filters( 'get_' . $this->adjacent . '_post_' . $clause, $value, $this->in_same_term, $this->excluded_terms );
     1465        return apply_filters( 'get_' . $this->adjacent . '_post_join', $join, $this->in_same_term, $this->excluded_terms );
     1466    }
     1467
     1468    /**
     1469     * Apply the deprecated `where` clause filter to the clause built by WP_Query.
     1470     *
     1471     * @param string $join
     1472     * @return string
     1473     */
     1474    protected function filter_where( $where ) {
     1475        $where = trim( $where );
     1476
     1477        // The legacy filter passed the entire clause, including the `WHERE`, while WP_Query's filter does not.
     1478        // We prepend the `WHERE` for the benefit of legacy callbacks that look for it.
     1479        if ( 0 !== stripos( $where, 'where' ) ) {
     1480            $where = 'WHERE 1=1 ' . $where;
     1481        }
     1482
     1483        /**
     1484         * @deprecated 3.9.0
     1485         */
     1486        $where = apply_filters( 'get_' . $this->adjacent . '_post_where', $where, $this->in_same_term, $this->excluded_terms );
     1487
     1488        $where = trim( $where );
     1489
     1490        // The legacy filter passed the entire clause, including the `WHERE`, while WP_Query's filter does not.
     1491        // Removing the `WHERE` is necessary as we've added it above, and the legacy filter could include it in the returned string.
     1492        if ( 0 === stripos( $where, 'where 1=1' ) ) {
     1493            $where = substr( $where, 9 );
     1494        } elseif ( 0 === stripos( $where, 'where' ) ) {
     1495            $where = substr( $where, 5 );
     1496        }
     1497
     1498        $where = trim( $where );
     1499
     1500        // WP_Query expects that the string returned begins with `AND`, as it is prepended with "1=1" when the clauses are joined
     1501        if ( 0 !== stripos( $where, 'and' ) ) {
     1502            $where = 'AND ' . $where;
     1503        }
     1504
     1505        return $where;
    14261506    }
    14271507
  • trunk/tests/phpunit/tests/link.php

    r27285 r27635  
    209209        remove_filter( 'get_next_post_where', array( $this, 'filter_next_post_where' ) );
    210210
     211        // Test "where" filter that writes its own query
     212        add_filter( 'get_previous_post_where', array( $this, 'override_previous_post_where_clause' ) );
     213        $this->go_to( get_permalink( $post_four->ID ) );
     214        $this->assertEquals( $post_two, get_adjacent_post( false, null, true ) );
     215        remove_filter( 'get_previous_post_where', array( $this, 'override_previous_post_where_clause' ) );
     216
    211217        // Test "join" filter by joining the postmeta table and restricting by meta key
    212218        add_filter( 'get_next_post_join', array( $this, 'filter_next_post_join' ) );
     
    249255     * Filter callback for `test_legacy_get_adjacent_post_filters()`
    250256     */
     257    function override_previous_post_where_clause( $where ) {
     258        $where = "WHERE p.post_date < '2012-02-28'";
     259        return $where;
     260    }
     261
     262    /**
     263     * Filter callback for `test_legacy_get_adjacent_post_filters()`
     264     */
    251265    function filter_next_post_join( $join ) {
    252266        global $wpdb;
    253267
    254         $join .= " INNER JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id";
     268        $join .= " INNER JOIN {$wpdb->postmeta} ON p.ID = {$wpdb->postmeta}.post_id";
    255269        return $join;
    256270    }
     
    270284     */
    271285    function filter_next_post_sort( $sort ) {
    272         global $wpdb;
    273 
    274         $sort = str_replace( $wpdb->posts . '.post_date', $wpdb->posts . '.post_title', $sort );
    275         return $sort;
     286        return str_replace( 'p.post_date', 'p.post_title', $sort );
    276287    }
    277288
Note: See TracChangeset for help on using the changeset viewer.