Make WordPress Core


Ignore:
Timestamp:
10/14/2020 12:49:52 AM (4 years ago)
Author:
peterwilsoncc
Message:

Taxonomy: Improve performance of term recounting database queries.

When modifying terms assigned to an object, replace full term recounts with incrementing/decrementing the count as appropriate. This provides a significant performance boost on sites with a high number of term/object relationships and/or posts.

Introduces the functions wp_increment_term_count(), wp_decrement_term_count(), wp_modify_term_count_by() and wp_modify_term_count_by_now() for updating the term count.

Introduces the function _wp_prevent_term_counting() for preventing double counting on posts that are about to transition.

Adds the parameter update_count_by_callback to register_taxonomy() to allow developers to use a custom callback for incrementing or decrementing a term count.

Props boonebgorges, davidbaumwald, hellofromTonya, johnbillion, lcyh78, mattoperry, peterwilsoncc, rebasaurus, whyisjake.
Fixes #40351.

File:
1 edited

Legend:

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

    r49125 r49141  
    40724072    }
    40734073
     4074    // Allow term counts to be handled by transitioning post type.
     4075    _wp_prevent_term_counting( true );
    40744076    if ( is_object_in_taxonomy( $post_type, 'category' ) ) {
    40754077        wp_set_post_categories( $post_ID, $post_category );
     
    41284130        }
    41294131    }
     4132    // Restore term counting.
     4133    _wp_prevent_term_counting( false );
    41304134
    41314135    if ( ! empty( $postarr['meta_input'] ) ) {
     
    44374441            continue;
    44384442        }
     4443        _wp_prevent_term_counting( true );
    44394444        wp_set_post_terms( $post->ID, array( $default_term_id ), $taxonomy );
     4445        _wp_prevent_term_counting( false );
    44404446    }
    44414447
     
    73137319 */
    73147320function _update_term_count_on_transition_post_status( $new_status, $old_status, $post ) {
    7315     // Update counts for the post's terms.
     7321    if ( 'inherit' === $new_status ) {
     7322        $new_status = get_post_status( $post->post_parent );
     7323    }
     7324
     7325    if ( 'inherit' === $old_status ) {
     7326        $old_status = get_post_status( $post->post_parent );
     7327    }
     7328
     7329    $count_new = 'publish' === $new_status;
     7330    $count_old = 'publish' === $old_status;
     7331
     7332    if ( $count_new === $count_old ) {
     7333        // Nothing to do.
     7334        return;
     7335    }
     7336
     7337    /*
     7338     * Update counts for the post's terms.
     7339     *
     7340     * Term counting is deferred while incrementing/decrementing the counts to
     7341     * reduce the number of database queries required. Once the counts are
     7342     * complete the updates are performed if term counting wasn't previously
     7343     * deferred.
     7344     */
     7345    $previous_deferred_setting = wp_defer_term_counting();
     7346    wp_defer_term_counting( true );
    73167347    foreach ( (array) get_object_taxonomies( $post->post_type ) as $taxonomy ) {
    73177348        $tt_ids = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'tt_ids' ) );
    7318         wp_update_term_count( $tt_ids, $taxonomy );
    7319     }
     7349
     7350        if ( empty( $tt_ids ) ) {
     7351            // No terms for this taxonomy on object.
     7352            continue;
     7353        }
     7354
     7355        $object_types = (array) get_taxonomy( $taxonomy )->object_type;
     7356
     7357        foreach ( $object_types as &$object_type ) {
     7358            list( $object_type ) = explode( ':', $object_type );
     7359        }
     7360
     7361        $object_types = array_unique( $object_types );
     7362
     7363        if ( ! in_array( $post->post_type, $object_types, true ) ) {
     7364            $modify_by = 0;
     7365        } elseif ( $count_new && ! $count_old ) {
     7366            $modify_by = 1;
     7367        } elseif ( $count_old && ! $count_new ) {
     7368            $modify_by = -1;
     7369        }
     7370
     7371        if ( 'attachment' === $post->post_type ) {
     7372            wp_modify_term_count_by( $tt_ids, $taxonomy, $modify_by );
     7373            continue;
     7374        }
     7375
     7376        $check_attachments = array_search( 'attachment', $object_types, true );
     7377        if ( false !== $check_attachments ) {
     7378            unset( $object_types[ $check_attachments ] );
     7379            $check_attachments = true;
     7380        }
     7381
     7382        wp_modify_term_count_by( $tt_ids, $taxonomy, $modify_by );
     7383        if ( ! $check_attachments ) {
     7384            continue;
     7385        }
     7386
     7387        /*
     7388         * For non-attachments, check if there are any attachment children
     7389         * with 'inherited' post status -- if so those will need to be counted.
     7390         */
     7391        $attachments = get_children(
     7392            array(
     7393                'post_parent'            => $post->ID,
     7394                'post_status'            => 'inherit',
     7395                'post_type'              => 'attachment',
     7396                'update_post_meta_cache' => false,
     7397                'update_post_term_cache' => true,
     7398            )
     7399        );
     7400
     7401        foreach ( $attachments as $attachment ) {
     7402            _update_term_count_on_transition_post_status( $new_status, $old_status, $attachment );
     7403        }
     7404    }
     7405    wp_defer_term_counting( $previous_deferred_setting );
    73207406}
    73217407
Note: See TracChangeset for help on using the changeset viewer.