Skip to content

Commit 3888339

Browse files
committed
Taxonomy: Ensure _pad_term_counts() handles post types safely.This commit updates _pad_term_counts() to use $wpdb->prepare() for all database queries, improving security and consistency. Additionally, it introduces a filter using post_type_exists() to ensure that only registered post types are queried, aligning the behavior with _update_post_term_count().Includes comprehensive unit tests to verify the logic and prevent regressions.Fixes #65055.See #11542.
1 parent 4d3b0b9 commit 3888339

File tree

2 files changed

+82
-3
lines changed

2 files changed

+82
-3
lines changed

src/wp-includes/taxonomy.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4065,8 +4065,20 @@ function _pad_term_counts( &$terms, $taxonomy ) {
40654065

40664066
// Get the object and term IDs and stick them in a lookup table.
40674067
$tax_obj = get_taxonomy( $taxonomy );
4068-
$object_types = esc_sql( $tax_obj->object_type );
4069-
$results = $wpdb->get_results( "SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode( ',', array_keys( $term_ids ) ) . ") AND post_type IN ('" . implode( "', '", $object_types ) . "') AND post_status = 'publish'" );
4068+
$object_types = (array) $tax_obj->object_type;
4069+
4070+
//Filter invalid post types for consistency with _update_post_term_count().
4071+
$object_types = array_filter( $object_types, 'post_type_exists' );
4072+
if ( empty( $object_types ) ) {
4073+
return;
4074+
}
4075+
4076+
$results = $wpdb->get_results(
4077+
$wpdb->prepare(
4078+
"SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode( ',', array_fill( 0, count( $term_ids ), '%d' ) ) . ') AND post_type IN (' . implode( ',', array_fill( 0, count( $object_types ), '%s' ) ) . ") AND post_status = 'publish'",
4079+
array_merge( array_keys( $term_ids ), $object_types )
4080+
)
4081+
);
40704082

40714083
foreach ( $results as $row ) {
40724084
$id = $term_ids[ $row->term_taxonomy_id ];

tests/phpunit/tests/taxonomy.php

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
1616
self::$editor_id = $factory->user->create( array( 'role' => 'editor' ) );
1717
}
1818

19-
public function test_get_post_taxonomies() {
19+
/************* ✨ Windsurf Command ⭐ *************/
20+
/**
21+
* Tests that get_object_taxonomies returns all taxonomies associated with the 'post' object type.
22+
* @since 2.5.0
23+
*/
24+
/******* 47033ee7-498b-4bba-8cf1-3758976c8603 *******/ public function test_get_post_taxonomies() {
2025
$this->assertSame( array( 'category', 'post_tag', 'post_format' ), get_object_taxonomies( 'post' ) );
2126
}
2227

@@ -1124,4 +1129,66 @@ public function test_default_term_for_post_in_multiple_taxonomies() {
11241129
$this->assertContains( $tax1, $taxonomies );
11251130
$this->assertContains( $tax2, $taxonomies );
11261131
}
1132+
1133+
/**
1134+
* @ticket 65055
1135+
* Filter invalid post types before SQL query
1136+
*/
1137+
public function test_pad_term_counts_with_invalid_post_types() {
1138+
register_taxonomy( 'invalid_tax', array( 'non_existent_type' ), array( 'hierarchical' => true ) );
1139+
1140+
$parent = self::factory()->term->create( array( 'taxonomy' => 'invalid_tax' ) );
1141+
self::factory()->term->create(
1142+
array(
1143+
'taxonomy' => 'invalid_tax', // 確保跟父節點是同一個 Taxonomy
1144+
'parent' => $parent,
1145+
)
1146+
);
1147+
1148+
_get_term_hierarchy( 'invalid_tax' );
1149+
1150+
$terms = get_terms(
1151+
array(
1152+
'taxonomy' => 'invalid_tax',
1153+
'hide_empty' => false,
1154+
)
1155+
);
1156+
1157+
_pad_term_counts( $terms, 'invalid_tax' );
1158+
1159+
$this->assertEquals( 0, $terms[0]->count );
1160+
}
1161+
1162+
/**
1163+
* @ticket 65055
1164+
*/
1165+
public function test_pad_term_counts_with_standard_post_types() {
1166+
register_post_type( 'book' );
1167+
register_taxonomy( 'genre', array( 'book' ), array( 'hierarchical' => true ) ); // 確保階層屬性開啟
1168+
1169+
$parent = self::factory()->term->create( array( 'taxonomy' => 'genre' ) );
1170+
$child = self::factory()->term->create(
1171+
array(
1172+
'taxonomy' => 'genre',
1173+
'parent' => $parent,
1174+
)
1175+
);
1176+
1177+
_get_term_hierarchy( 'genre' );
1178+
1179+
$post_id = self::factory()->post->create( array( 'post_type' => 'book' ) );
1180+
wp_set_object_terms( $post_id, $child, 'genre' );
1181+
1182+
$terms = get_terms(
1183+
array(
1184+
'taxonomy' => 'genre',
1185+
'hide_empty' => false,
1186+
)
1187+
);
1188+
1189+
_pad_term_counts( $terms, 'genre' );
1190+
1191+
$parent_term = wp_list_filter( $terms, array( 'term_id' => $parent ) );
1192+
$this->assertEquals( 1, current( $parent_term )->count, 'Parent terms should include post counts from their child terms' );
1193+
}
11271194
}

0 commit comments

Comments
 (0)