WordPress.org

Make WordPress Core

Ticket #38280: 38280.18.diff

File 38280.18.diff, 20.4 KB (added by boonebgorges, 23 months 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..3146bea49f 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_term_object_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 3f9b960538..40bb988c78 100644
    a b function wp_update_term_count_now( $terms, $taxonomy ) { 
    31243124        return true;
    31253125}
    31263126
     3127/**
     3128 * Retrieves the number of objects of a specific type for a term.
     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, term's object count for specified type otherwise.
     3137 */
     3138function wp_get_term_object_count( $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        if ( 0 === $term->count ) {
     3169                // If the global count for a term is 0, no need for an object-specific count.
     3170                $count = 0;
     3171        } else {
     3172                $count = wp_get_term_object_count_from_meta( $term_id, $object_type );
     3173
     3174                // No calculated count found for this object type.
     3175                if ( false === $count ) {
     3176                        /**
     3177                         * Fires when no object count is found for a given object type.
     3178                         *
     3179                         * This action provides an opportunity for third parties to run count routines.
     3180                         * When the object type is a post type, the count routine is run automatically.
     3181                         * See wp_update_term_count_for_post_type().
     3182                         *
     3183                         * @since 5.0.0
     3184                         *
     3185                         * @param WP_Term $term        Term object.
     3186                         * @param string  $object_type Object type name.
     3187                         */
     3188                        do_action( 'wp_no_term_object_count_found', $term, $object_type );
     3189
     3190                        // Try one more fetch after a count has potentially been triggered.
     3191                        $count = (int) wp_get_term_object_count_from_meta( $term_id, $object_type );
     3192                }
     3193        }
     3194
     3195        /**
     3196         * Filters the object count for a given term.
     3197         *
     3198         * @since 5.0.0
     3199         *
     3200         * @param int     $count       Count of objects of the given `$object_type` belonging to the term.
     3201         * @param WP_Term $term        Term object.
     3202         * @param string  $object_type Object type.
     3203         */
     3204        return apply_filters( 'wp_term_object_count', $count, $term, $object_type );
     3205}
     3206
     3207/**
     3208 * Triggers a term count refresh when `$object_type` is a post type.
     3209 *
     3210 * Term-object counts are generally recalculated at the time that term-relationships are
     3211 * updated. See eg wp_set_object_terms(). But for terms that were last counted before the
     3212 * introduction of term-object counts, this data will initially be missing. This function
     3213 * forces a calculation of those counts when the object is a post type. Object types
     3214 * that are not post types must provide their own separate mechanism for triggering
     3215 * these counts.
     3216 *
     3217 * @since 5.0.0
     3218 *
     3219 * @param WP_Term $term        Term object.
     3220 * @param string  $object_type Object type.
     3221 */
     3222function wp_update_term_count_for_post_type( $term, $object_type ) {
     3223        // Non-post-types cannot be handled automatically.
     3224        if ( ! post_type_exists( $object_type ) ) {
     3225                return;
     3226        }
     3227
     3228        // Taxonomies with their own count callbacks cannot be handled automatically.
     3229        $taxonomy = get_taxonomy( $term->taxonomy );
     3230        if ( ! empty( $taxonomy->update_count_callback ) ) {
     3231                return;
     3232        }
     3233
     3234        wp_update_term_count_now( array( $term->term_taxonomy_id ), $term->taxonomy );
     3235}
     3236
     3237/**
     3238 * Get the cached term-object count from termmeta.
     3239 *
     3240 * @param int    $term_id     ID of the term.
     3241 * @param string $object_type Object type.
     3242 * @return bool|int Returns false when no metadata is found, which indicates that a count has not taken place.
     3243 */
     3244function wp_get_term_object_count_from_meta( $term_id, $object_type ) {
     3245        $term_object_count = get_term_meta( $term_id, '_wp_object_count_' . $object_type, true );
     3246        if ( $term_object_count ) {
     3247                return (int) $term_object_count;
     3248        }
     3249
     3250        $counted_object_types = (array) get_term_meta( $term_id, '_wp_counted_object_types', true );
     3251
     3252        // When the object type is marked counted and no meta key exists, the count is 0.
     3253        if ( in_array( $object_type, $counted_object_types, true ) ) {
     3254                return 0;
     3255        }
     3256
     3257        return false;
     3258}
     3259
    31273260//
    31283261// Cache
    31293262//
    function _prime_term_caches( $term_ids, $update_meta_cache = true ) { 
    36383771 *
    36393772 * @access private
    36403773 * @since 2.3.0
     3774 * @since 5.0.0 Store term counts on a per object type basis in meta.
    36413775 *
    36423776 * @global wpdb $wpdb WordPress database abstraction object.
    36433777 *
    function _update_post_term_count( $terms, $taxonomy ) { 
    36613795        }
    36623796
    36633797        if ( $object_types ) {
    3664                 $object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) );
     3798                $object_types = array_filter( $object_types, 'post_type_exists' );
    36653799        }
    36663800
    3667         foreach ( (array) $terms as $term ) {
     3801        foreach ( (array) $terms as $tt_id ) {
    36683802                $count = 0;
    36693803
     3804                $term = get_term_by( 'term_taxonomy_id', $tt_id );
     3805
     3806                // Remove previous counts to prevent stale data if an object type is removed from a taxonomy.
     3807                $counted_object_types = (array) get_term_meta( $term->term_id, '_wp_counted_object_types', true );
     3808
     3809                foreach ( $counted_object_types as $o_type ) {
     3810                        delete_term_meta( $term->term_id, '_wp_object_count_' . $o_type );
     3811                }
     3812
     3813                delete_term_meta( $term->term_id, '_wp_counted_object_types' );
     3814
     3815                $term_count_meta = array();
     3816
     3817                if ( $object_types ) {
     3818                        foreach ( $object_types as $type ) {
     3819                                $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 ) );
     3820
     3821                                $count += $current_count;
     3822
     3823                                $term_count_meta[ $type ] = $current_count;
     3824                        }
     3825                }
     3826
    36703827                // Attachments can be 'inherit' status, we need to base count off the parent's status if so.
    36713828                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 ) );
     3829                        $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 ) );
     3830
     3831                        $count += $attachment_count;
     3832
     3833                        $term_count_meta['attachment'] = $attachment_count;
     3834
     3835                        // Re-add attachment so the meta gets saved below.
     3836                        $object_types[] = 'attachment';
    36733837                }
    36743838
    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 ) );
     3839                // Save individual counts for each object type in term meta.
     3840                foreach ( $object_types as $type ) {
     3841                        if ( ! empty( $term_count_meta[ $type ] ) ) {
     3842                                update_term_meta( $term->term_id, '_wp_object_count_' . $type, (int) $term_count_meta[ $type ] );
     3843                        }
    36773844                }
    36783845
     3846                update_term_meta( $term->term_id, '_wp_counted_object_types', $object_types );
     3847
    36793848                /** 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 ) );
     3849                do_action( 'edit_term_taxonomy', $tt_id, $taxonomy->name );
     3850                $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $tt_id ) );
    36823851
    36833852                /** This action is documented in wp-includes/taxonomy.php */
    3684                 do_action( 'edited_term_taxonomy', $term, $taxonomy->name );
     3853                do_action( 'edited_term_taxonomy', $tt_id, $taxonomy->name );
    36853854        }
    36863855}
    36873856
  • 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/wpGetTermObjectCount.php

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