Make WordPress Core

Ticket #38280: 38280.15.diff

File 38280.15.diff, 20.9 KB (added by boonebgorges, 6 years ago)
  • src/wp-includes/default-filters.php

    diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php
    index 5487c8fbe4..10ab57e41d 100644
    a b add_action( 'post_updated', 'wp_save_post_revision', 10, 1 ); 
    343343add_action( 'publish_post', '_publish_post_hook', 5, 1 );
    344344add_action( 'transition_post_status', '_transition_post_status', 5, 3 );
    345345add_action( 'transition_post_status', '_update_term_count_on_transition_post_status', 10, 3 );
     346add_action( 'wp_no_object_term_count_found', 'wp_update_term_count_for_post_type', 10, 2 );
    346347add_action( 'comment_form', 'wp_comment_form_unfiltered_html_nonce' );
    347348add_action( 'admin_init', 'send_frame_options_header', 10, 0 );
    348349add_action( 'welcome_panel', 'wp_welcome_panel' );
  • src/wp-includes/taxonomy.php

    diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php
    index 2df5ac6b41..c6b00a21eb 100644
    a b function wp_update_term_count_now( $terms, $taxonomy ) { 
    31243124        return true;
    31253125}
    31263126
     3127/**
     3128 * Retrieves the term count for a specific object type.
     3129 *
     3130 * @since 5.0.0
     3131 *
     3132 * @param int    $term_id     Term ID.
     3133 * @param string $taxonomy    Taxonomy name.
     3134 * @param string $object_type Object type.
     3135 *
     3136 * @return WP_Error|int WP_Error on failure, object term count otherwise.
     3137 */
     3138function wp_get_term_count_for_object_type( $term_id, $taxonomy, $object_type ) {
     3139        if ( ! taxonomy_exists( $taxonomy ) ) {
     3140                return new WP_Error(
     3141                        'invalid_taxonomy',
     3142                        __( 'Invalid taxonomy.' ),
     3143                        array(
     3144                                'taxonomy' => $taxonomy,
     3145                        )
     3146                );
     3147        }
     3148
     3149        if ( ! is_object_in_taxonomy( $object_type, $taxonomy ) ) {
     3150                return new WP_Error(
     3151                        'invalid_object_type',
     3152                        __( 'Object type is not in taxonomy.' ),
     3153                        array(
     3154                                'object_type' => $object_type,
     3155                                'taxonomy'    => $taxonomy,
     3156                        )
     3157                );
     3158        }
     3159
     3160        $term = get_term( $term_id, $taxonomy );
     3161
     3162        if ( is_wp_error( $term ) ) {
     3163                return $term;
     3164        }
     3165
     3166        $taxonomy_object = get_taxonomy( $taxonomy );
     3167
     3168        // are these right?
     3169        if ( 0 === $term->count ) {
     3170                $count = 0;
     3171        } elseif ( 1 >= count( $taxonomy_object->object_type ) ) {
     3172                $count = $term->count;
     3173        } else {
     3174                $count = wp_get_term_count_for_object_type_from_meta( $term_id, $object_type );
     3175
     3176                // No calculated count found for this object type.
     3177                if ( false === $count ) {
     3178                        /**
     3179                         * Fires when no term count is found for a given object type.
     3180                         *
     3181                         * This action provides an opportunity for third parties to run count routines.
     3182                         * When the object type is a post type, the count routine is run automatically.
     3183                         * See wp_update_term_count_for_post_type().
     3184                         *
     3185                         * @since 5.0.0
     3186                         *
     3187                         * @param WP_Term $term        Term object.
     3188                         * @param string  $object_type Object type name.
     3189                         */
     3190                        do_action( 'wp_no_object_term_count_found', $term, $object_type );
     3191
     3192                        // Try one more fetch after a count has potentially been triggered.
     3193                        $count = (int) wp_get_term_count_for_object_type_from_meta( $term_id, $object_type );
     3194                }
     3195        }
     3196
     3197        /**
     3198         * Filters the object count for a given term.
     3199         *
     3200         * @since 5.0.0
     3201         *
     3202         * @param int     $count       Count of objects of the given `$object_type` belonging to the term.
     3203         * @param WP_Term $term        Term object.
     3204         * @param string  $object_type Object type.
     3205         */
     3206        return apply_filters( 'wp_term_count_for_object_type', $count, $term, $object_type );
     3207}
     3208
     3209/**
     3210 * Triggers a term count refresh when `$object_type` is a post type.
     3211 *
     3212 * Term-object counts are generally recalculated at the time that term-relationships are
     3213 * updated. See eg wp_set_object_terms(). But terms that were last counted before the
     3214 * introduction of term-object counts, this data will initially be missing. This function
     3215 * forces a calculation of those counts when the object is a post type. Object types
     3216 * that are not post types must have their own separate mechanism for triggering
     3217 * these counts.
     3218 *
     3219 * @since 5.0.0
     3220 *
     3221 * @param WP_Term $term        Term object.
     3222 * @param string  $object_type Object type.
     3223 */
     3224function wp_update_term_count_for_post_type( $term, $object_type ) {
     3225        // Non-post-types cannot be handled automatically.
     3226        if ( ! post_type_exists( $object_type ) ) {
     3227                return;
     3228        }
     3229
     3230        // Taxonomies with their own count callbacks cannot be handled automatically.
     3231        $taxonomy = get_taxonomy( $term->taxonomy );
     3232        if ( ! empty( $taxonomy->update_count_callback ) ) {
     3233                return;
     3234        }
     3235
     3236        wp_update_term_count_now( array( $term->term_taxonomy_id ), $term->taxonomy );
     3237}
     3238
     3239/**
     3240 * Get the cached term-object count from termmeta.
     3241 *
     3242 * @param int    $term_id     ID of the term.
     3243 * @param string $object_type Object type.
     3244 * @return bool|int Returns false when no metadata is found, which indicates that a count has not taken place.
     3245 */
     3246function wp_get_term_count_for_object_type_from_meta( $term_id, $object_type ) {
     3247        $term_object_count = get_term_meta( $term_id, '_wp_object_count_' . $object_type, true );
     3248        if ( $term_object_count ) {
     3249                return (int) $term_object_count;
     3250        }
     3251
     3252        $counted_object_types = (array) get_term_meta( $term_id, '_wp_counted_object_types', true );
     3253
     3254        // When the object type is marked counted and no meta key exists, the count is 0.
     3255        if ( in_array( $object_type, $counted_object_types, true ) ) {
     3256                return 0;
     3257        }
     3258
     3259        return false;
     3260}
     3261
    31273262//
    31283263// Cache
    31293264//
    function _prime_term_caches( $term_ids, $update_meta_cache = true ) { 
    36383773 *
    36393774 * @access private
    36403775 * @since 2.3.0
     3776 * @since 5.0.0 Store term counts on a per object type basis in meta.
    36413777 *
    36423778 * @global wpdb $wpdb WordPress database abstraction object.
    36433779 *
    function _update_post_term_count( $terms, $taxonomy ) { 
    36613797        }
    36623798
    36633799        if ( $object_types ) {
    3664                 $object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) );
     3800                $object_types = array_filter( $object_types, 'post_type_exists' );
    36653801        }
    36663802
    3667         foreach ( (array) $terms as $term ) {
     3803        foreach ( (array) $terms as $tt_id ) {
    36683804                $count = 0;
    36693805
     3806                $term = get_term_by( 'term_taxonomy_id', $tt_id );
     3807
     3808                // Remove previous counts to prevent stale data if an object type is removed from a taxonomy.
     3809                $counted_object_types = (array) get_term_meta( $term->term_id, '_wp_counted_object_types', true );
     3810
     3811                foreach ( $counted_object_types as $o_type ) {
     3812                        delete_term_meta( $term->term_id, '_wp_object_count_' . $o_type );
     3813                }
     3814
     3815                delete_term_meta( $term->term_id, '_wp_counted_object_types' );
     3816
     3817                $term_count_meta = array();
     3818
     3819                if ( $object_types ) {
     3820                        foreach ( $object_types as $type ) {
     3821                                $current_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type = %s AND term_taxonomy_id = %d", $type, $tt_id ) );
     3822
     3823                                $count += $current_count;
     3824
     3825                                $term_count_meta[ $type ] = $current_count;
     3826                        }
     3827                }
     3828
    36703829                // Attachments can be 'inherit' status, we need to base count off the parent's status if so.
    36713830                if ( $check_attachments ) {
    3672                         $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) );
     3831                        $attachment_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $tt_id ) );
     3832
     3833                        $count += $attachment_count;
     3834
     3835                        $term_count_meta['attachment'] = $attachment_count;
     3836
     3837                        // Re-add attachment so the meta gets saved below.
     3838                        $object_types[] = 'attachment';
    36733839                }
    36743840
    3675                 if ( $object_types ) {
    3676                         $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode( "', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) );
     3841                // Save individual counts for each object type in term meta.
     3842                if ( 1 < count( $term_count_meta ) ) {
     3843                        foreach ( $object_types as $type ) {
     3844                                if ( ! empty( $term_count_meta[ $type ] ) ) {
     3845                                        update_term_meta( $term->term_id, '_wp_object_count_' . $type, (int) $term_count_meta[ $type ] );
     3846                                }
     3847                        }
     3848
     3849                        update_term_meta( $term->term_id, '_wp_counted_object_types', $object_types );
    36773850                }
    36783851
    36793852                /** This action is documented in wp-includes/taxonomy.php */
    3680                 do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
    3681                 $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
     3853                do_action( 'edit_term_taxonomy', $tt_id, $taxonomy->name );
     3854                $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $tt_id ) );
    36823855
    36833856                /** This action is documented in wp-includes/taxonomy.php */
    3684                 do_action( 'edited_term_taxonomy', $term, $taxonomy->name );
     3857                do_action( 'edited_term_taxonomy', $tt_id, $taxonomy->name );
    36853858        }
    36863859}
    36873860
  • tests/phpunit/tests/term/wpGetObjectTerms.php

    diff --git a/tests/phpunit/tests/term/wpGetObjectTerms.php b/tests/phpunit/tests/term/wpGetObjectTerms.php
    index e7851dcaee..4bf496ffe0 100644
    a b class Tests_Term_WpGetObjectTerms extends WP_UnitTestCase { 
    599599                $p = self::factory()->post->create();
    600600                wp_set_object_terms( $p, $terms, 'wptests_tax' );
    601601
     602                /**
     603                 * `wp_set_object_terms()` populates the cache, but we need it empty to verify
     604                 * behavior of 'update_term_meta_cache'.
     605                 */
     606                foreach ( $terms as $t ) {
     607                        wp_cache_delete( $t, 'term_meta' );
     608                }
     609
    602610                $found = wp_get_object_terms(
    603611                        $p, 'wptests_tax', array(
    604612                                'update_term_meta_cache' => false,
  • new file tests/phpunit/tests/term/wpGetTermCountForObjectType.php

    diff --git a/tests/phpunit/tests/term/wpGetTermCountForObjectType.php b/tests/phpunit/tests/term/wpGetTermCountForObjectType.php
    new file mode 100644
    index 0000000000..1e31110868
    - +  
     1<?php
     2
     3/**
     4 * Class Tests_Term_wpGetTermCountForObjectType
     5 *
     6 * @group taxonomy
     7 * @ticket 38280
     8 */
     9class Tests_Term_wpGetTermCountForObjectType extends WP_UnitTestCase {
     10
     11        /**
     12         * Test when a taxonomy is invalid.
     13         */
     14        public function test_wp_get_term_count_for_object_type_invalid_taxonomy() {
     15                $actual = wp_get_term_count_for_object_type( 0, 'does-not-exist', 'post' );
     16
     17                $this->assertWPError( $actual );
     18                $this->assertSame( 'invalid_taxonomy', $actual->get_error_code() );
     19        }
     20
     21        /**
     22         * Test when an object type is not in a taxonomy.
     23         */
     24        public function test_wp_get_term_count_for_object_type_object_not_in_taxonomy() {
     25                $this->assertWPError( wp_get_term_count_for_object_type( 0, 'category', 'page' ) );
     26        }
     27
     28        /**
     29         * Test when an invalid term is passed.
     30         */
     31        public function test_wp_get_term_count_for_object_type_invalid_term() {
     32                $actual = wp_get_term_count_for_object_type( 0, 'category', 'post' );
     33
     34                $this->assertWPError( $actual );
     35                $this->assertSame( 'invalid_term', $actual->get_error_code() );
     36        }
     37
     38        /**
     39         * Test when a taxonomy belongs to a single object type. No term meta should be
     40         * stored and the count property should be used.
     41         */
     42        public function test_wp_get_term_count_for_object_type_single_object_type() {
     43                $term_id = self::factory()->term->create( array( 'taxonomy' => 'category' ) );
     44                $post_id = self::factory()->post->create(
     45                        array(
     46                                'post_type'     => 'post',
     47                                'post_category' => array(
     48                                        $term_id,
     49                                ),
     50                        )
     51                );
     52
     53                $this->assertFalse( (bool) get_term_meta( $term_id, '_wp_counted_object_types', true ) );
     54                $this->assertEquals( 1, wp_get_term_count_for_object_type( $term_id, 'category', 'post' ) );
     55
     56                $term_object = get_term( $term_id, 'category' );
     57                $this->assertEquals( 1, $term_object->count );
     58
     59                wp_remove_object_terms( $post_id, array( $term_id ), 'category' );
     60
     61                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'category', 'post' ) );
     62
     63                $term_object = get_term( $term_id, 'category' );
     64                $this->assertEquals( 0, $term_object->count );
     65        }
     66
     67        /**
     68         * Test when a taxonomy belongs to more than one object, and at least one object is not a post type.
     69         */
     70        public function test_wp_get_term_count_for_object_type_non_post_type() {
     71                register_taxonomy(
     72                        'wptests_tax',
     73                        array(
     74                                'user',
     75                                'foo'
     76                        )
     77                );
     78
     79                $term_id = self::factory()->term->create(
     80                        array(
     81                                'taxonomy' => 'wptests_tax',
     82                        )
     83                );
     84
     85                $foo_id  = 99999;
     86
     87                wp_set_object_terms( $foo_id, $term_id, 'wptests_tax' );
     88
     89                // 'foo' object doesn't have an update count callback, so the value is always 0.
     90                $count = wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'foo' );
     91                $this->assertSame( 0, $count );
     92        }
     93
     94        /**
     95         * Test when a taxonomy belongs to multiple object types.
     96         */
     97        public function test_wp_get_term_count_for_object_type_multiple_object_types() {
     98                register_post_type( 'wptests_cpt' );
     99                register_taxonomy(
     100                        'wptests_tax',
     101                        array(
     102                                'post',
     103                                'wptests_cpt',
     104                        )
     105                );
     106
     107                $term_id        = self::factory()->term->create( array( 'taxonomy' => 'wptests_tax' ) );
     108                $post_id        = self::factory()->post->create( array( 'post_type' => 'post' ) );
     109                $custom_post_id = self::factory()->post->create( array( 'post_type' => 'wptests_cpt' ) );
     110
     111                // When a term has no relationships, no meta should be stored.
     112                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'post' ) );
     113                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'wptests_cpt' ) );
     114                $this->assertEmpty( get_term_meta( $term_id, '_wp_counted_object_types', true ) );
     115                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_post', true ) );
     116                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_wptests_cpt', true ) );
     117
     118                wp_set_object_terms( $post_id, array( $term_id ), 'wptests_tax' );
     119
     120                // Term has relationships, meta should be stored caching types counted and counts for each type > 0.
     121                $this->assertEquals( 1, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'post' ) );
     122                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'wptests_cpt' ) );
     123                $this->assertEquals( array( 'post', 'wptests_cpt' ), get_term_meta( $term_id, '_wp_counted_object_types', true ) );
     124                $this->assertEquals( 1, get_term_meta( $term_id, '_wp_object_count_post', true ) );
     125                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_wptests_cpt', true ) );
     126
     127                wp_set_object_terms( $custom_post_id, array( $term_id ), 'wptests_tax' );
     128
     129                $this->assertEquals( 1, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'post' ) );
     130                $this->assertEquals( 1, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'wptests_cpt' ) );
     131                $this->assertEquals( array( 'post', 'wptests_cpt' ), get_term_meta( $term_id, '_wp_counted_object_types', true ) );
     132                $this->assertEquals( 1, get_term_meta( $term_id, '_wp_object_count_post', true ) );
     133                $this->assertEquals( 1, get_term_meta( $term_id, '_wp_object_count_wptests_cpt', true ) );
     134
     135                // Total count should be stored in the term's count property.
     136                $term_object = get_term( $term_id, 'wptests_tax' );
     137                $this->assertEquals( 2, $term_object->count );
     138
     139                wp_remove_object_terms( $custom_post_id, array( $term_id ), 'wptests_tax' );
     140
     141                // Object count cache should be removed.
     142                $this->assertEquals( 1, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'post' ) );
     143                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'wptests_cpt' ) );
     144                $this->assertEquals( array( 'post', 'wptests_cpt' ), get_term_meta( $term_id, '_wp_counted_object_types', true ) );
     145                $this->assertEquals( 1, get_term_meta( $term_id, '_wp_object_count_post', true ) );
     146                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_wptests_cpt', true ) );
     147
     148                wp_remove_object_terms( $post_id, array( $term_id ), 'wptests_tax' );
     149
     150                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'post' ) );
     151                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'wptests_cpt' ) );
     152                $this->assertEquals( array( 'post', 'wptests_cpt' ), get_term_meta( $term_id, '_wp_counted_object_types', true ) );
     153                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_post', true ) );
     154                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_wptests_cpt', true ) );
     155        }
     156
     157        /**
     158         * Term count must be generated on the fly (as for "legacy" terms).
     159         */
     160        public function test_count_should_be_generated_for_legacy_terms() {
     161                register_post_type( 'wptests_cpt' );
     162                register_taxonomy(
     163                        'wptests_tax',
     164                        array(
     165                                'post',
     166                                'wptests_cpt',
     167                        )
     168                );
     169
     170                $t = self::factory()->term->create( array( 'taxonomy' => 'wptests_tax' ) );
     171                $p = self::factory()->post->create( array( 'post_type' => 'post' ) );
     172
     173                wp_set_object_terms( $p, array( $t ), 'wptests_tax' );
     174
     175                // Mimic "legacy" terms, which will not have the proper counts.
     176                delete_term_meta( $t, '_wp_object_count_post' );
     177                delete_term_meta( $t, '_wp_counted_object_types' );
     178
     179                $found = wp_get_term_count_for_object_type( $t, 'wptests_tax', 'post' );
     180                $this->assertSame( 1, $found );
     181        }
     182
     183        /**
     184         * Test when a taxonomy belongs to multiple object types, one of which is attachments.
     185         */
     186        public function test_wp_get_term_count_for_object_type_multiple_object_types_attachment() {
     187                register_taxonomy(
     188                        'wptests_tax',
     189                        array(
     190                                'post',
     191                                'attachment',
     192                        )
     193                );
     194
     195                $term_id       = self::factory()->term->create( array( 'taxonomy' => 'wptests_tax' ) );
     196                $post_id       = self::factory()->post->create( array( 'post_type' => 'post' ) );
     197                $attachment_id = self::factory()->attachment->create_upload_object( DIR_TESTDATA . '/images/canola.jpg', $post_id );
     198
     199                // When a term has no relationships, no meta should be stored.
     200                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'post' ) );
     201                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'attachment' ) );
     202                $this->assertEmpty( get_term_meta( $term_id, '_wp_counted_object_types', true ) );
     203                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_post', true ) );
     204                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_attachment', true ) );
     205
     206                wp_set_object_terms( $post_id, array( $term_id ), 'wptests_tax' );
     207
     208                // Term has relationships, meta should be stored caching types counted and counts for each type > 0.
     209                $this->assertEquals( 1, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'post' ) );
     210                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'attachment' ) );
     211                $this->assertEquals( array( 'post', 'attachment' ), get_term_meta( $term_id, '_wp_counted_object_types', true ) );
     212                $this->assertEquals( 1, get_term_meta( $term_id, '_wp_object_count_post', true ) );
     213                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_attachment', true ) );
     214
     215                wp_set_object_terms( $attachment_id, array( $term_id ), 'wptests_tax' );
     216
     217                $this->assertEquals( 1, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'post' ) );
     218                $this->assertEquals( 1, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'attachment' ) );
     219                $this->assertEquals( array( 'post', 'attachment' ), get_term_meta( $term_id, '_wp_counted_object_types', true ) );
     220                $this->assertEquals( 1, get_term_meta( $term_id, '_wp_object_count_post', true ) );
     221                $this->assertEquals( 1, get_term_meta( $term_id, '_wp_object_count_attachment', true ) );
     222
     223                // Total count should be stored in the term's count property.
     224                $term_object = get_term( $term_id, 'wptests_tax' );
     225                $this->assertEquals( 2, $term_object->count );
     226
     227                wp_remove_object_terms( $post_id, array( $term_id ), 'wptests_tax' );
     228
     229                // Object count cache should be removed.
     230                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'post' ) );
     231                $this->assertEquals( 1, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'attachment' ) );
     232                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_post', true ) );
     233                $this->assertEquals( 1, get_term_meta( $term_id, '_wp_object_count_attachment', true ) );
     234                wp_remove_object_terms( $attachment_id, array( $term_id ), 'wptests_tax' );
     235
     236                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'post' ) );
     237                $this->assertEquals( 0, wp_get_term_count_for_object_type( $term_id, 'wptests_tax', 'attachment' ) );
     238                $this->assertEquals( array( 'post', 'attachment' ), get_term_meta( $term_id, '_wp_counted_object_types', true ) );
     239                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_post', true ) );
     240                $this->assertEmpty( get_term_meta( $term_id, '_wp_object_count_attachment', true ) );
     241        }
     242}