From 5fb4836f43b2c6e1022e0f9ea3d2a9a798b14785 Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 29 Aug 2025 04:35:20 +0530 Subject: [PATCH 01/14] Terms: Check if the orderby clause is an array and handle --- src/wp-includes/class-wp-term-query.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index 754278cfbaf52..749c2b60a9383 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -445,7 +445,24 @@ public function get_terms() { $_orderby = 'term_id'; } - $orderby = $this->parse_orderby( $_orderby ); + if ( is_array( $_orderby ) ) { + $orderby_array = array(); + + foreach ( $_orderby as $orderby_field => $order ) { + $parsed = $this->parse_orderby( $orderby_field ); + + if ( ! $parsed ) { + continue; + } + + $order = $this->parse_order( $order ); + $orderby_array[] = $parsed . ' ' . $order; + } + + $orderby = implode( ', ', $orderby_array ); + } else { + $orderby = $this->parse_orderby( $_orderby ); + } if ( $orderby ) { $orderby = "ORDER BY $orderby"; From 2b6fc9445a051aa186bd2e9b5a77a7adad826383 Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 29 Aug 2025 04:41:39 +0530 Subject: [PATCH 02/14] Terms: Improve string interpolation and avoid conflicts --- src/wp-includes/class-wp-term-query.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index 749c2b60a9383..d8a463bef01f3 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -449,14 +449,14 @@ public function get_terms() { $orderby_array = array(); foreach ( $_orderby as $orderby_field => $order ) { - $parsed = $this->parse_orderby( $orderby_field ); + $parsed_orderby = $this->parse_orderby( $orderby_field ); - if ( ! $parsed ) { + if ( ! $parsed_orderby ) { continue; } $order = $this->parse_order( $order ); - $orderby_array[] = $parsed . ' ' . $order; + $orderby_array[] = "{$parsed_orderby} {$order}"; } $orderby = implode( ', ', $orderby_array ); From 9050f21b628d91a6c7d02aa1a498bdce12b03cff Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 29 Aug 2025 04:43:53 +0530 Subject: [PATCH 03/14] Fallback to default if all orderby fields are invalid --- src/wp-includes/class-wp-term-query.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index d8a463bef01f3..8ea430d82c9b5 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -460,6 +460,11 @@ public function get_terms() { } $orderby = implode( ', ', $orderby_array ); + + // Fallback to default if all orderby fields are invalid. + if ( empty( $orderby ) ) { + $orderby = $this->parse_orderby( 'name' ); + } } else { $orderby = $this->parse_orderby( $_orderby ); } From 7dfd480eec519fae0786b4915111dd77c6c86b3f Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 29 Aug 2025 04:44:51 +0530 Subject: [PATCH 04/14] Fix whitespace linting --- src/wp-includes/class-wp-term-query.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index 8ea430d82c9b5..65133d1880b20 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -447,21 +447,21 @@ public function get_terms() { if ( is_array( $_orderby ) ) { $orderby_array = array(); - + foreach ( $_orderby as $orderby_field => $order ) { $parsed_orderby = $this->parse_orderby( $orderby_field ); - + if ( ! $parsed_orderby ) { continue; } - - $order = $this->parse_order( $order ); + + $order = $this->parse_order( $order ); $orderby_array[] = "{$parsed_orderby} {$order}"; } - + $orderby = implode( ', ', $orderby_array ); - // Fallback to default if all orderby fields are invalid. + // Fallback to default if all orderby fields are invalid. if ( empty( $orderby ) ) { $orderby = $this->parse_orderby( 'name' ); } From cefb495942233dbd15533c6d89390c653199178e Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 29 Aug 2025 04:48:34 +0530 Subject: [PATCH 05/14] Tems: Fix SQL generation for array orderbys --- src/wp-includes/class-wp-term-query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index 65133d1880b20..0168dd1c239c7 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -768,7 +768,7 @@ public function get_terms() { $this->sql_clauses['select'] = "SELECT $distinct $fields"; $this->sql_clauses['from'] = "FROM $wpdb->terms AS t $join"; - $this->sql_clauses['orderby'] = $orderby ? "$orderby $order" : ''; + $this->sql_clauses['orderby'] = $orderby ? ( is_array( $this->query_vars['orderby'] ) ? $orderby : "$orderby $order" ) : ''; $this->sql_clauses['limits'] = $limits; // Beginning of the string is on a new line to prevent leading whitespace. See https://core.trac.wordpress.org/ticket/56841. From c9bad06e9387f12a79e8a2443ce59bd5464ea965 Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 29 Aug 2025 04:55:51 +0530 Subject: [PATCH 06/14] Add array support enhancement to the doc block --- src/wp-includes/class-wp-term-query.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index 0168dd1c239c7..68ada8d1f3326 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -112,6 +112,7 @@ class WP_Term_Query { * - The value of `$meta_key`. * - The array keys of `$meta_query`. * - 'none' to omit the ORDER BY clause. + * - Array of orderby fields as keys with order ('ASC'/'DESC') as values. * Default 'name'. * @type string $order Whether to order terms in ascending or descending order. * Accepts 'ASC' (ascending) or 'DESC' (descending). From f2d3e955797460d68ff8bddb0c9f4731eb0d50ea Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 29 Aug 2025 04:56:45 +0530 Subject: [PATCH 07/14] Remove unnecessary fallback for empty values --- src/wp-includes/class-wp-term-query.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index 68ada8d1f3326..7682103c53bc8 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -461,11 +461,6 @@ public function get_terms() { } $orderby = implode( ', ', $orderby_array ); - - // Fallback to default if all orderby fields are invalid. - if ( empty( $orderby ) ) { - $orderby = $this->parse_orderby( 'name' ); - } } else { $orderby = $this->parse_orderby( $_orderby ); } From 49d8df647a3f7fe2d7ff16c0d0b0dc041ebd16b0 Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 29 Aug 2025 04:59:01 +0530 Subject: [PATCH 08/14] Update doc block orderby parameter to include array --- src/wp-includes/class-wp-term-query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index 7682103c53bc8..c2f8ec3565c37 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -100,7 +100,7 @@ class WP_Term_Query { * should be limited. * @type int|int[] $object_ids Object ID, or array of object IDs. Results will be * limited to terms associated with these objects. - * @type string $orderby Field(s) to order terms by. Accepts: + * @type string|array $orderby Field(s) to order terms by. Accepts: * - Term fields ('name', 'slug', 'term_group', 'term_id', 'id', * 'description', 'parent', 'term_order'). Unless `$object_ids` * is not empty, 'term_order' is treated the same as 'term_id'. From 020e0308843eb99cdb78dc9c80a89fab5268c1e9 Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 29 Aug 2025 04:59:54 +0530 Subject: [PATCH 09/14] Add changelog to function for added array support --- src/wp-includes/class-wp-term-query.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index c2f8ec3565c37..a2a6e7ac36f06 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -92,6 +92,7 @@ class WP_Term_Query { * @since 5.1.0 Introduced the 'meta_compare_key' parameter. * @since 5.3.0 Introduced the 'meta_type_key' parameter. * @since 6.4.0 Introduced the 'cache_results' parameter. + * @since 6.8.0 Added support for array of orderby fields. * * @param string|array $query { * Optional. Array or query string of term query parameters. Default empty. From 2f93fa289f9baaced090feb9607337e2a28e8a9e Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 29 Aug 2025 05:01:12 +0530 Subject: [PATCH 10/14] Update log version --- src/wp-includes/class-wp-term-query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-term-query.php b/src/wp-includes/class-wp-term-query.php index a2a6e7ac36f06..753f14cfb15a0 100644 --- a/src/wp-includes/class-wp-term-query.php +++ b/src/wp-includes/class-wp-term-query.php @@ -92,7 +92,7 @@ class WP_Term_Query { * @since 5.1.0 Introduced the 'meta_compare_key' parameter. * @since 5.3.0 Introduced the 'meta_type_key' parameter. * @since 6.4.0 Introduced the 'cache_results' parameter. - * @since 6.8.0 Added support for array of orderby fields. + * @since 6.9.0 Added support for array of orderby fields. * * @param string|array $query { * Optional. Array or query string of term query parameters. Default empty. From 6592200004595dd73283361739e598ece390e77e Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Mon, 1 Sep 2025 12:08:18 +0530 Subject: [PATCH 11/14] Test orderby in term query with multiple fields --- tests/phpunit/tests/term/query.php | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/phpunit/tests/term/query.php b/tests/phpunit/tests/term/query.php index d76efa62d8450..737d0d5c7b67c 100644 --- a/tests/phpunit/tests/term/query.php +++ b/tests/phpunit/tests/term/query.php @@ -1185,4 +1185,39 @@ public function test_query_does_not_have_leading_whitespace() { $this->assertSame( ltrim( $q->request ), $q->request, 'The query has leading whitespace' ); } + + /** + * @ticket 63890 + */ + public function test_orderby_array_multiple_fields() { + register_taxonomy( 'wptests_tax_orderby', 'post' ); + + $terms = self::factory()->term->create_many( + 4, + array( + 'taxonomy' => 'wptests_tax_orderby', + ) + ); + + add_term_meta( $terms[0], 'priority', 2 ); + add_term_meta( $terms[1], 'priority', 1 ); + add_term_meta( $terms[2], 'priority', 2 ); + add_term_meta( $terms[3], 'priority', 1 ); + + $q = new WP_Term_Query( + array( + 'taxonomy' => 'wptests_tax_orderby', + 'orderby' => array( + 'meta_value_num' => 'DESC', + 'term_id' => 'ASC', + ), + 'meta_key' => 'priority', + 'hide_empty' => false, + 'fields' => 'ids', + ) + ); + + $expected = array( $terms[0], $terms[2], $terms[1], $terms[3] ); + $this->assertSame( $expected, $q->terms ); + } } From 356edf643d93d7e01532489fd0a9a0d6a8ca588b Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Mon, 1 Sep 2025 12:16:16 +0530 Subject: [PATCH 12/14] Test orderby with name and count --- tests/phpunit/tests/term/query.php | 51 ++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/phpunit/tests/term/query.php b/tests/phpunit/tests/term/query.php index 737d0d5c7b67c..65f412f61657a 100644 --- a/tests/phpunit/tests/term/query.php +++ b/tests/phpunit/tests/term/query.php @@ -1220,4 +1220,55 @@ public function test_orderby_array_multiple_fields() { $expected = array( $terms[0], $terms[2], $terms[1], $terms[3] ); $this->assertSame( $expected, $q->terms ); } + + /** + * @ticket 63890 + */ + public function test_orderby_array_with_name_and_count() { + register_taxonomy( 'wptests_tax_orderby_name', 'post' ); + + $term1 = self::factory()->term->create( + array( + 'taxonomy' => 'wptests_tax_orderby_name', + 'name' => 'Beta Term', + ) + ); + $term2 = self::factory()->term->create( + array( + 'taxonomy' => 'wptests_tax_orderby_name', + 'name' => 'Zeta Term', + ) + ); + $term3 = self::factory()->term->create( + array( + 'taxonomy' => 'wptests_tax_orderby_name', + 'name' => 'Alpha Term', + ) + ); + + $post1 = self::factory()->post->create(); + $post2 = self::factory()->post->create(); + $post3 = self::factory()->post->create(); + $post4 = self::factory()->post->create(); + + wp_set_object_terms( $post1, array( $term1 ), 'wptests_tax_orderby_name' ); + wp_set_object_terms( $post2, array( $term1 ), 'wptests_tax_orderby_name' ); + wp_set_object_terms( $post3, array( $term2 ), 'wptests_tax_orderby_name' ); + wp_set_object_terms( $post4, array( $term3 ), 'wptests_tax_orderby_name' ); + + $q = new WP_Term_Query( + array( + 'taxonomy' => 'wptests_tax_orderby_name', + 'orderby' => array( + 'count' => 'DESC', + 'name' => 'ASC', + ), + 'hide_empty' => false, + 'fields' => 'ids', + ) + ); + + $expected = array( $term1, $term3, $term2 ); + $this->assertSame( $expected, $q->terms ); + } } From 9778e43eedb8df5164c2cd4a7a63de2710a9b7af Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Mon, 1 Sep 2025 12:18:19 +0530 Subject: [PATCH 13/14] Test orderby array backward compatibility --- tests/phpunit/tests/term/query.php | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/phpunit/tests/term/query.php b/tests/phpunit/tests/term/query.php index 65f412f61657a..4d5fbe91a368b 100644 --- a/tests/phpunit/tests/term/query.php +++ b/tests/phpunit/tests/term/query.php @@ -1271,4 +1271,41 @@ public function test_orderby_array_with_name_and_count() { $expected = array( $term1, $term3, $term2 ); $this->assertSame( $expected, $q->terms ); } + + /** + * @ticket 63890 + */ + public function test_orderby_array_backward_compatibility() { + register_taxonomy( 'wptests_tax_compat', 'post' ); + + $terms = self::factory()->term->create_many( + 3, + array( + 'taxonomy' => 'wptests_tax_compat', + ) + ); + + $q1 = new WP_Term_Query( + array( + 'taxonomy' => 'wptests_tax_compat', + 'orderby' => 'term_id', + 'order' => 'ASC', + 'hide_empty' => false, + 'fields' => 'ids', + ) + ); + + $this->assertSame( $terms, $q1->terms ); + + $q2 = new WP_Term_Query( + array( + 'taxonomy' => 'wptests_tax_compat', + 'orderby' => array( 'term_id' => 'ASC' ), + 'hide_empty' => false, + 'fields' => 'ids', + ) + ); + + $this->assertSame( $terms, $q2->terms ); + } } From bd1c1ac0c2ccdfdc3be0c3be583208c8595de162 Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Mon, 1 Sep 2025 12:23:45 +0530 Subject: [PATCH 14/14] Test orderby array all invalid fields fallback --- tests/phpunit/tests/term/query.php | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/phpunit/tests/term/query.php b/tests/phpunit/tests/term/query.php index 4d5fbe91a368b..4945afb025114 100644 --- a/tests/phpunit/tests/term/query.php +++ b/tests/phpunit/tests/term/query.php @@ -1308,4 +1308,33 @@ public function test_orderby_array_backward_compatibility() { $this->assertSame( $terms, $q2->terms ); } + + /** + * @ticket 63890 + */ + public function test_orderby_array_all_invalid_fields_fallback() { + register_taxonomy( 'wptests_tax_fallback', 'post' ); + + $terms = self::factory()->term->create_many( + 2, + array( + 'taxonomy' => 'wptests_tax_fallback', + ) + ); + + $q = new WP_Term_Query( + array( + 'taxonomy' => 'wptests_tax_fallback', + 'orderby' => array( + 'invalid_field1' => 'ASC', + 'invalid_field2' => 'DESC', + ), + 'hide_empty' => false, + 'fields' => 'ids', + ) + ); + + $this->assertNotEmpty( $q->terms ); + $this->assertCount( 2, $q->terms ); + } }