Make WordPress Core

Changeset 37573


Ignore:
Timestamp:
05/26/2016 04:49:10 AM (9 years ago)
Author:
boonebgorges
Message:

Store only term IDs in object term relationships caches.

Previously, objects containing all data about a term were stored in each
object's term cache. Besides being wasteful, this approach caused invalidation
issues, as when a modified term count required a flush for all objects
belonging to the term.

Backward compatibility is maintained for plugins that continue to put object
data directly into the {$taxonomy}_relationships cache bucket.

Fixes #36814.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/taxonomy.php

    r37488 r37573  
    243243    if ( false === $terms ) {
    244244        $terms = wp_get_object_terms( $post_id, $taxonomy );
    245         wp_cache_add( $post_id, $terms, $taxonomy . '_relationships' );
     245        wp_cache_add( $post_id, wp_list_pluck( $terms, 'term_id' ), $taxonomy . '_relationships' );
    246246    }
    247247
  • trunk/src/wp-admin/includes/template.php

    r37545 r37573  
    312312            if ( false === $terms ) {
    313313                $terms = wp_get_object_terms( $post->ID, $taxonomy_name );
    314                 wp_cache_add( $post->ID, $terms, $taxonomy_name . '_relationships' );
     314                wp_cache_add( $post->ID, wp_list_pluck( $terms, 'term_id' ), $taxonomy_name . '_relationships' );
    315315            }
    316316            $term_ids = empty( $terms ) ? array() : wp_list_pluck( $terms, 'term_id' );
  • trunk/src/wp-includes/category-template.php

    r37571 r37573  
    11881188        $terms = wp_get_object_terms( $post->ID, $taxonomy );
    11891189        if ( ! is_wp_error( $terms ) ) {
    1190             $to_cache = array();
    1191             foreach ( $terms as $key => $term ) {
    1192                 $to_cache[ $key ] = $term->data;
    1193             }
    1194             wp_cache_add( $post->ID, $to_cache, $taxonomy . '_relationships' );
    1195         }
    1196     }
    1197 
    1198     if ( ! is_wp_error( $terms ) ) {
    1199         $terms = array_map( 'get_term', $terms );
     1190            $term_ids = wp_list_pluck( $terms, 'term_id' );
     1191            wp_cache_add( $post->ID, $term_ids, $taxonomy . '_relationships' );
     1192        }
    12001193    }
    12011194
  • trunk/src/wp-includes/taxonomy.php

    r37572 r37573  
    32403240 * Retrieves the taxonomy relationship to the term object id.
    32413241 *
     3242 * Upstream functions (like `get_the_terms()` and `is_object_in_term()`) are responsible for populating the
     3243 * object-term relationship cache. The current function only fetches relationship data that is already in the cache.
     3244 *
    32423245 * @since 2.3.0
    32433246 *
    32443247 * @param int    $id       Term object ID.
    32453248 * @param string $taxonomy Taxonomy name.
    3246  * @return bool|mixed Empty array if $terms found, but not `$taxonomy`. False if nothing is in cache
    3247  *                    for `$taxonomy` and `$id`.
     3249 * @return bool|array Array of `WP_Term` objects, if cached False if cache is empty for `$taxonomy` and `$id`.
    32483250 */
    32493251function get_object_term_cache( $id, $taxonomy ) {
    3250     return wp_cache_get( $id, "{$taxonomy}_relationships" );
     3252    $_term_ids = wp_cache_get( $id, "{$taxonomy}_relationships" );
     3253
     3254    // We leave the priming of relationship caches to upstream functions.
     3255    if ( false === $_term_ids ) {
     3256        return false;
     3257    }
     3258
     3259    // Backward compatibility for if a plugin is putting objects into the cache, rather than IDs.
     3260    $term_ids = array();
     3261    foreach ( $_term_ids as $term_id ) {
     3262        if ( is_numeric( $term_id ) ) {
     3263            $term_ids[] = intval( $term_id );
     3264        } elseif ( isset( $term_id->term_id ) ) {
     3265            $term_ids[] = intval( $term_id->term_id );
     3266        }
     3267    }
     3268
     3269    // Fill the term objects.
     3270    _prime_term_caches( $term_ids );
     3271
     3272    $terms = array();
     3273    foreach ( $term_ids as $term_id ) {
     3274        $terms[] = wp_cache_get( $term_id, 'terms' );
     3275    }
     3276
     3277    return array_map( 'get_term', $terms );
    32513278}
    32523279
     
    32983325
    32993326    $object_terms = array();
    3300     foreach ( (array) $terms as $term )
    3301         $object_terms[$term->object_id][$term->taxonomy][] = $term;
     3327    foreach ( (array) $terms as $term ) {
     3328        $object_terms[ $term->object_id ][ $term->taxonomy ][] = $term->term_id;
     3329    }
    33023330
    33033331    foreach ( $ids as $id ) {
     
    35033531        if ( isset($terms_by_id[$id]) )
    35043532            $terms_by_id[$id]->count = count($items);
     3533}
     3534
     3535/**
     3536 * Adds any terms from the given IDs to the cache that do not already exist in cache.
     3537 *
     3538 * @since 4.6.0
     3539 * @access private
     3540 *
     3541 * @global wpdb $wpdb WordPress database abstraction object.
     3542 *
     3543 * @param array $term_ids          Array of term IDs.
     3544 * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
     3545 */
     3546function _prime_term_caches( $term_ids, $update_meta_cache = true ) {
     3547    global $wpdb;
     3548
     3549    $non_cached_ids = _get_non_cached_ids( $term_ids, 'terms' );
     3550    if ( ! empty( $non_cached_ids ) ) {
     3551        $fresh_terms = $wpdb->get_results( sprintf( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE t.term_id IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) );
     3552
     3553        update_term_cache( $fresh_terms, $update_meta_cache );
     3554
     3555        if ( $update_meta_cache ) {
     3556            update_termmeta_cache( $non_cached_ids );
     3557        }
     3558    }
    35053559}
    35063560
     
    42124266    if ( false === $object_terms ) {
    42134267        $object_terms = wp_get_object_terms( $object_id, $taxonomy, array( 'update_term_meta_cache' => false ) );
    4214         wp_cache_set( $object_id, $object_terms, "{$taxonomy}_relationships" );
     4268        wp_cache_set( $object_id, wp_list_pluck( $object_terms, 'term_id' ), "{$taxonomy}_relationships" );
    42154269    }
    42164270
  • trunk/tests/phpunit/tests/term/getTheTerms.php

    r37480 r37573  
    7979     * @ticket 34262
    8080     */
    81     public function test_get_the_terms_should_not_cache_wp_term_objects() {
    82         $p = self::$post_ids[0];
    83         register_taxonomy( 'wptests_tax', 'post' );
    84         $t = self::factory()->term->create( array( 'taxonomy' => 'wptests_tax' ) );
    85         wp_set_object_terms( $p, $t, 'wptests_tax' );
    86 
    87         // Prime the cache.
    88         $terms = get_the_terms( $p, 'wptests_tax' );
    89 
    90         $cached = get_object_term_cache( $p, 'wptests_tax' );
    91 
    92         $this->assertNotEmpty( $cached );
    93         $this->assertSame( $t, (int) $cached[0]->term_id );
    94         $this->assertNotInstanceOf( 'WP_Term', $cached[0] );
    95     }
    96 
    97     /**
    98      * @ticket 34262
    99      */
    10081    public function test_get_the_terms_should_return_wp_term_objects_from_cache() {
    10182        $p = self::$post_ids[0];
     
    171152        $this->assertTrue( is_wp_error( $terms ) );
    172153    }
     154
     155    /**
     156     * @ticket 36814
     157     */
     158    public function test_count_should_not_be_improperly_cached() {
     159        register_taxonomy( 'wptests_tax', 'post' );
     160
     161        $t = self::factory()->term->create( array( 'taxonomy' => 'wptests_tax' ) );
     162
     163        wp_set_object_terms( self::$post_ids[0], $t, 'wptests_tax' );
     164
     165        $terms = get_the_terms( self::$post_ids[0], 'wptests_tax' );
     166        $this->assertSame( 1, $terms[0]->count );
     167
     168        wp_set_object_terms( self::$post_ids[1], $t, 'wptests_tax' );
     169
     170        $terms = get_the_terms( self::$post_ids[0], 'wptests_tax' );
     171        $this->assertSame( 2, $terms[0]->count );
     172    }
     173
     174    /**
     175     * @ticket 36814
     176     */
     177    public function test_uncached_terms_should_be_primed_with_a_single_query() {
     178        global $wpdb;
     179
     180        register_taxonomy( 'wptests_tax', 'post' );
     181
     182        $terms = self::factory()->term->create_many( 3, array( 'taxonomy' => 'wptests_tax' ) );
     183
     184        wp_set_object_terms( self::$post_ids[0], $terms, 'wptests_tax' );
     185
     186        get_the_terms( self::$post_ids[0], 'wptests_tax' );
     187
     188        // Clean cache for two of the terms.
     189        clean_term_cache( array( $terms[0], $terms[1] ), 'wptests_tax', false );
     190
     191        $num_queries = $wpdb->num_queries;
     192        $found = get_the_terms( self::$post_ids[0], 'wptests_tax' );
     193
     194        $this->assertEqualSets( $terms, wp_list_pluck( $found, 'term_id' ) );
     195
     196        $num_queries++;
     197        $this->assertSame( $num_queries, $wpdb->num_queries );
     198
     199    }
    173200}
Note: See TracChangeset for help on using the changeset viewer.