diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 270c252c92..6255324467 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -3891,17 +3891,30 @@ function _update_post_term_count( $terms, $taxonomy ) { $object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) ); } + $post_statuses = array( 'publish' ); + + /** + * Filters the post statuses for updating the term count. + * + * @since 5.7.0 + * + * @param array $post_statuses List of post statuses to include in the count. Default is 'publish'. + * @param WP_Taxonomy $taxonomy Current taxonomy object. + */ + $post_statuses = esc_sql( apply_filters( 'update_post_term_count_statuses', $post_statuses, $taxonomy ) ); + foreach ( (array) $terms as $term ) { $count = 0; // Attachments can be 'inherit' status, we need to base count off the parent's status if so. if ( $check_attachments ) { - $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 ) ); + // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedDynamicPlaceholderGeneration + $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 IN ('" . implode( "', '", $post_statuses ) . "') OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) IN ('" . implode( "', '", $post_statuses ) . "') ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) ); } if ( $object_types ) { // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedDynamicPlaceholderGeneration - $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 ) ); + $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 IN ('" . implode( "', '", $post_statuses ) . "') AND post_type IN ('" . implode( "', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) ); } /** This action is documented in wp-includes/taxonomy.php */ diff --git a/tests/phpunit/tests/term/termCounts.php b/tests/phpunit/tests/term/termCounts.php index c6fa42e4fc..9b4919ec71 100644 --- a/tests/phpunit/tests/term/termCounts.php +++ b/tests/phpunit/tests/term/termCounts.php @@ -224,6 +224,66 @@ class Tests_Term_termCount extends WP_UnitTestCase { ); } + function add_custom_status_to_counted_statuses( $statuses ) { + array_push( $statuses, 'custom' ); + return $statuses; + } + + /** + * Term counts incremented correctly when the `update_post_term_count_statuses` filter is used. + * + * @covers ::wp_update_term_count + * @dataProvider data_term_count_changes_for_update_post_term_count_statuses_filter + * @ticket 38843 + * + * @param string $post_status New post status. + * @param int $change Expected change. + */ + public function test_term_count_changes_for_update_post_term_count_statuses_filter( $post_status, $change ) { + $term_count = get_term( self::$attachment_term )->count; + + add_filter( 'update_post_term_count_statuses', array( $this, 'add_custom_status_to_counted_statuses' ) ); + + $post_id = $this->factory()->post->create( array( 'post_status' => $post_status ) ); + wp_add_object_terms( $post_id, self::$attachment_term, 'wp_test_tax_counts' ); + $attachment_id = self::factory()->attachment->create_object( + array( + 'file' => 'image.jpg', + 'post_parent' => $post_id, + 'post_status' => 'inherit', + ) + ); + wp_add_object_terms( $attachment_id, self::$attachment_term, 'wp_test_tax_counts' ); + + $expected = $term_count + $change; + $this->assertSame( $expected, get_term( self::$attachment_term )->count ); + + remove_filter( 'update_post_term_count_statuses', array( $this, 'add_custom_status_to_counted_statuses' ) ); + } + + /** + * Data provider for test_term_count_changes_for_update_post_term_count_statuses_filter. + * + * @return array[] { + * @type string $post_status New post status. + * @type int $change Expected change. + * } + */ + function data_term_count_changes_for_update_post_term_count_statuses_filter() { + return array( + // 0. Published post + array( 'publish', 2 ), + // 1. Auto draft + array( 'auto-draft', 0 ), + // 2. Draft + array( 'draft', 0 ), + // 3. Private post + array( 'private', 0 ), + // 4. Custom post status + array( 'custom', 2 ), + ); + } + /** * Term counts incremented correctly for posts with attachment. *