From 4bcc0a5d816562cfe4e12616b1ca5043cbbaa56b Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 29 Aug 2024 14:55:42 +0200 Subject: [PATCH 01/27] Tax Query: Allow querying for all posts with any term of a given taxonomy --- src/wp-includes/class-wp-query.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index bc673191a8a16..c9a73285dffb7 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1165,16 +1165,16 @@ public function parse_tax_query( &$q ) { } foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy => $t ) { + if ( 'post_tag' === $taxonomy ) { continue; // Handled further down in the $q['tag'] block. } - if ( $t->query_var && ! empty( $q[ $t->query_var ] ) ) { + if ( $t->query_var && ( ! empty( $q[ $t->query_var ] || '' === $q[ $t->query_var ] ) ) ) { $tax_query_defaults = array( 'taxonomy' => $taxonomy, 'field' => 'slug', ); - if ( ! empty( $t->rewrite['hierarchical'] ) ) { $q[ $t->query_var ] = wp_basename( $q[ $t->query_var ] ); } @@ -1195,13 +1195,24 @@ public function parse_tax_query( &$q ) { ) ); } - } else { + } elseif ( '' !== $term ) { $tax_query[] = array_merge( $tax_query_defaults, array( 'terms' => preg_split( '/[,]+/', $term ), ) ); + } else { + // FIXME: Figure out why 'category' is automatically + // added as a query arg and what to do about it. + if ( 'category' !== $taxonomy ) { + $tax_query[] = array_merge( + $tax_query_defaults, + array( + 'operator' => 'EXISTS', + ) + ); + } } } } From 6c90faf1176a471da5a1659041abd85f7bee255e Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 29 Aug 2024 16:21:05 +0200 Subject: [PATCH 02/27] Restore whitespace --- src/wp-includes/class-wp-query.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index c9a73285dffb7..9e2b50e3755d2 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1175,6 +1175,7 @@ public function parse_tax_query( &$q ) { 'taxonomy' => $taxonomy, 'field' => 'slug', ); + if ( ! empty( $t->rewrite['hierarchical'] ) ) { $q[ $t->query_var ] = wp_basename( $q[ $t->query_var ] ); } From 15a7daf7b5af683c37ab1d22504c1f2729dd175a Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 29 Aug 2024 16:21:40 +0200 Subject: [PATCH 03/27] ...and remove spurious whitespace --- src/wp-includes/class-wp-query.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 9e2b50e3755d2..a3fc73fa253c9 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1165,7 +1165,6 @@ public function parse_tax_query( &$q ) { } foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy => $t ) { - if ( 'post_tag' === $taxonomy ) { continue; // Handled further down in the $q['tag'] block. } From 28e62508936466a96652f92dfeaf839bfebac6f2 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 5 Sep 2024 13:28:14 +0200 Subject: [PATCH 04/27] Tighten guard --- src/wp-includes/class-wp-query.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index a3fc73fa253c9..b0abc5735bbf5 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1169,7 +1169,7 @@ public function parse_tax_query( &$q ) { continue; // Handled further down in the $q['tag'] block. } - if ( $t->query_var && ( ! empty( $q[ $t->query_var ] || '' === $q[ $t->query_var ] ) ) ) { + if ( $t->query_var && isset( $q[ $t->query_var ] ) ) { $tax_query_defaults = array( 'taxonomy' => $taxonomy, 'field' => 'slug', @@ -1195,14 +1195,14 @@ public function parse_tax_query( &$q ) { ) ); } - } elseif ( '' !== $term ) { + } elseif ( ! empty( $term ) ) { $tax_query[] = array_merge( $tax_query_defaults, array( 'terms' => preg_split( '/[,]+/', $term ), ) ); - } else { + } elseif ( '' === $term ) { // FIXME: Figure out why 'category' is automatically // added as a query arg and what to do about it. if ( 'category' !== $taxonomy ) { From 55bc397f625a239f06774df3f4170ddb494284d4 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 5 Sep 2024 13:30:52 +0200 Subject: [PATCH 05/27] else should do here --- src/wp-includes/class-wp-query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index b0abc5735bbf5..4e8728142946f 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1202,7 +1202,7 @@ public function parse_tax_query( &$q ) { 'terms' => preg_split( '/[,]+/', $term ), ) ); - } elseif ( '' === $term ) { + } else { // FIXME: Figure out why 'category' is automatically // added as a query arg and what to do about it. if ( 'category' !== $taxonomy ) { From 9a04ce629439b9e0c906f95683ffbf9385db7ca9 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 9 Sep 2024 17:04:28 +0200 Subject: [PATCH 06/27] Make basic redirect work --- src/wp-includes/class-wp-taxonomy.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index 254ea6a15c98b..5f12efd5c7dd2 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -512,6 +512,10 @@ public function add_rewrite_rules() { add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); + + // TODO: If rewrite tag exists, append taxonomy name to regex. + add_rewrite_tag( '%taxonomy%', "(?:$this->name)", $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); + add_permastruct( 'taxonomy', '%taxonomy%', $this->rewrite ); } } From 7bf597995cca58dfd7240ee9837e367fc85611b7 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 10 Sep 2024 10:08:55 +0200 Subject: [PATCH 07/27] A bit hacky --- src/wp-includes/class-wp-taxonomy.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index 5f12efd5c7dd2..d8644df6455fc 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -513,9 +513,8 @@ public function add_rewrite_rules() { add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); - // TODO: If rewrite tag exists, append taxonomy name to regex. - add_rewrite_tag( '%taxonomy%', "(?:$this->name)", $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); - add_permastruct( 'taxonomy', '%taxonomy%', $this->rewrite ); + add_rewrite_tag( "%$this->name-taxonomy%", "(?:$this->name)", $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); + add_permastruct( "$this->name-taxonomy", "%$this->name-taxonomy%", $this->rewrite ); } } From 1c42f8b7dfda7dd6d9bdbf412887b297ccb5aa99 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 10 Sep 2024 12:29:18 +0200 Subject: [PATCH 08/27] Better? --- src/wp-includes/class-wp-taxonomy.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index d8644df6455fc..df31f17768cf4 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -511,10 +511,7 @@ public function add_rewrite_rules() { } add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); - add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); - - add_rewrite_tag( "%$this->name-taxonomy%", "(?:$this->name)", $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); - add_permastruct( "$this->name-taxonomy", "%$this->name-taxonomy%", $this->rewrite ); + add_permastruct( $this->name, "{$this->rewrite['slug']}(?:/%$this->name%)?", $this->rewrite ); } } From f17bf173872beab0ebd89bc9d10a9d39dbcb1338 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 10 Sep 2024 16:01:05 +0200 Subject: [PATCH 09/27] Revert "Better?" This reverts commit 6150936fdcd553ca92260b9305b33a16d0747760. --- src/wp-includes/class-wp-taxonomy.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index df31f17768cf4..d8644df6455fc 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -511,7 +511,10 @@ public function add_rewrite_rules() { } add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); - add_permastruct( $this->name, "{$this->rewrite['slug']}(?:/%$this->name%)?", $this->rewrite ); + add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); + + add_rewrite_tag( "%$this->name-taxonomy%", "(?:$this->name)", $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); + add_permastruct( "$this->name-taxonomy", "%$this->name-taxonomy%", $this->rewrite ); } } From 03edd4338782c18f2375a7a5f24bc16fcec85698 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 10 Sep 2024 16:25:41 +0200 Subject: [PATCH 10/27] Re-use query --- src/wp-includes/class-wp-taxonomy.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index d8644df6455fc..f6556edd9e88f 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -510,10 +510,12 @@ public function add_rewrite_rules() { $tag = '([^/]+)'; } - add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); + $query = $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term="; + + add_rewrite_tag( "%$this->name%", $tag, $query ); add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); - add_rewrite_tag( "%$this->name-taxonomy%", "(?:$this->name)", $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); + add_rewrite_tag( "%$this->name-taxonomy%", "(?:$this->name)", $query ); add_permastruct( "$this->name-taxonomy", "%$this->name-taxonomy%", $this->rewrite ); } } From 4d8f697f391a3e62d98c2d6b3fc46b67cad831ee Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 10 Sep 2024 16:26:37 +0200 Subject: [PATCH 11/27] Proper teardown --- src/wp-includes/class-wp-taxonomy.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index f6556edd9e88f..41628634e0e1c 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -538,6 +538,9 @@ public function remove_rewrite_rules() { // Remove rewrite tags and permastructs. if ( false !== $this->rewrite ) { + remove_rewrite_tag( "%$this->name-taxonomy%" ); + remove_permastruct( "$this->name-taxonomy" ); + remove_rewrite_tag( "%$this->name%" ); remove_permastruct( $this->name ); } From 8ddd012569489790cc9198260cd72d5e0088ad0d Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 12:07:38 +0200 Subject: [PATCH 12/27] Update test --- tests/phpunit/tests/taxonomy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/taxonomy.php b/tests/phpunit/tests/taxonomy.php index 2a4ee3b560d08..9d7c3a8726c8b 100644 --- a/tests/phpunit/tests/taxonomy.php +++ b/tests/phpunit/tests/taxonomy.php @@ -917,7 +917,7 @@ public function test_unregister_taxonomy_removes_rewrite_rules() { $this->assertTrue( unregister_taxonomy( 'foo' ) ); $this->assertNotContains( '%foo%', $wp_rewrite->rewritecode ); $this->assertNotContains( 'bar=', $wp_rewrite->queryreplace ); - $this->assertCount( --$count_before, $wp_rewrite->rewritereplace ); // Array was reduced by one value. + $this->assertCount( $count_before - 2, $wp_rewrite->rewritereplace ); // Array was reduced by two values. } /** From 5792517284dcd5275f77efb26d298b9beaf3ad22 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 12:25:17 +0200 Subject: [PATCH 13/27] Re-differentiate queries --- src/wp-includes/class-wp-taxonomy.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index 41628634e0e1c..c0c6884d46fce 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -510,12 +510,12 @@ public function add_rewrite_rules() { $tag = '([^/]+)'; } - $query = $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term="; - - add_rewrite_tag( "%$this->name%", $tag, $query ); + add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); - add_rewrite_tag( "%$this->name-taxonomy%", "(?:$this->name)", $query ); + // For the root taxonomy archive, the query string is simply the query var, with no value set, + // or, if no query var is defined, `taxonomy=$this->name`. + add_rewrite_tag( "%$this->name-taxonomy%", "(?:$this->name)", $this->query_var ? $this->query_var : "taxonomy=$this->name" ); add_permastruct( "$this->name-taxonomy", "%$this->name-taxonomy%", $this->rewrite ); } } From 2f94522670e6d577374bc7850beaa7e1cedea2f6 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 12:36:43 +0200 Subject: [PATCH 14/27] Change name of rewrite tag and permastruct --- src/wp-includes/class-wp-taxonomy.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index c0c6884d46fce..9d4c03fc083b6 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -515,8 +515,8 @@ public function add_rewrite_rules() { // For the root taxonomy archive, the query string is simply the query var, with no value set, // or, if no query var is defined, `taxonomy=$this->name`. - add_rewrite_tag( "%$this->name-taxonomy%", "(?:$this->name)", $this->query_var ? $this->query_var : "taxonomy=$this->name" ); - add_permastruct( "$this->name-taxonomy", "%$this->name-taxonomy%", $this->rewrite ); + add_rewrite_tag( "%taxonomy-$this->name%", "(?:$this->name)", $this->query_var ? $this->query_var : "taxonomy=$this->name" ); + add_permastruct( "taxonomy-$this->name", "%taxonomy-$this->name%", $this->rewrite ); } } @@ -538,8 +538,8 @@ public function remove_rewrite_rules() { // Remove rewrite tags and permastructs. if ( false !== $this->rewrite ) { - remove_rewrite_tag( "%$this->name-taxonomy%" ); - remove_permastruct( "$this->name-taxonomy" ); + remove_rewrite_tag( "%taxonomy-$this->name%" ); + remove_permastruct( "taxonomy-$this->name" ); remove_rewrite_tag( "%$this->name%" ); remove_permastruct( $this->name ); From 92e47b41e726fbe5fd2e6869ec46dda96a0bac0b Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 13:05:38 +0200 Subject: [PATCH 15/27] Add back dangling equals sign --- src/wp-includes/class-wp-taxonomy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index 9d4c03fc083b6..1e7719e930263 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -515,7 +515,7 @@ public function add_rewrite_rules() { // For the root taxonomy archive, the query string is simply the query var, with no value set, // or, if no query var is defined, `taxonomy=$this->name`. - add_rewrite_tag( "%taxonomy-$this->name%", "(?:$this->name)", $this->query_var ? $this->query_var : "taxonomy=$this->name" ); + add_rewrite_tag( "%taxonomy-$this->name%", "$this->name", $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name" ); add_permastruct( "taxonomy-$this->name", "%taxonomy-$this->name%", $this->rewrite ); } } From 3ba05844fb4a14adab19cc4eeb7bf49857b3aaa3 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 13:07:42 +0200 Subject: [PATCH 16/27] Use only taxonomy= format for root tax archives --- src/wp-includes/class-wp-taxonomy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index 1e7719e930263..9e65e0921e5f8 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -515,7 +515,7 @@ public function add_rewrite_rules() { // For the root taxonomy archive, the query string is simply the query var, with no value set, // or, if no query var is defined, `taxonomy=$this->name`. - add_rewrite_tag( "%taxonomy-$this->name%", "$this->name", $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name" ); + add_rewrite_tag( "%taxonomy-$this->name%", "$this->name", "taxonomy=$this->name" ); add_permastruct( "taxonomy-$this->name", "%taxonomy-$this->name%", $this->rewrite ); } } From ea1d6ccbaee1cb5aaec929dd7542039035991d01 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 13:14:15 +0200 Subject: [PATCH 17/27] Remove now-obsolete comment --- src/wp-includes/class-wp-taxonomy.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index 9e65e0921e5f8..f79faa309bdc7 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -513,8 +513,6 @@ public function add_rewrite_rules() { add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); - // For the root taxonomy archive, the query string is simply the query var, with no value set, - // or, if no query var is defined, `taxonomy=$this->name`. add_rewrite_tag( "%taxonomy-$this->name%", "$this->name", "taxonomy=$this->name" ); add_permastruct( "taxonomy-$this->name", "%taxonomy-$this->name%", $this->rewrite ); } From 81c02727759062d474438fb03ee0945036190836 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 13:20:06 +0200 Subject: [PATCH 18/27] Match taxonomy name --- src/wp-includes/class-wp-taxonomy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index f79faa309bdc7..fd68a973ae811 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -513,7 +513,7 @@ public function add_rewrite_rules() { add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); - add_rewrite_tag( "%taxonomy-$this->name%", "$this->name", "taxonomy=$this->name" ); + add_rewrite_tag( "%taxonomy-$this->name%", "($this->name)", 'taxonomy=' ); add_permastruct( "taxonomy-$this->name", "%taxonomy-$this->name%", $this->rewrite ); } } From aa8675f1cc08ab688076e65f8fc9bc6224eda7de Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 13:44:53 +0200 Subject: [PATCH 19/27] Change order of precedence --- src/wp-includes/class-wp-taxonomy.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index fd68a973ae811..bd649d6edb722 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -510,11 +510,11 @@ public function add_rewrite_rules() { $tag = '([^/]+)'; } - add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); - add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); - add_rewrite_tag( "%taxonomy-$this->name%", "($this->name)", 'taxonomy=' ); add_permastruct( "taxonomy-$this->name", "%taxonomy-$this->name%", $this->rewrite ); + + add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); + add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); } } @@ -536,11 +536,11 @@ public function remove_rewrite_rules() { // Remove rewrite tags and permastructs. if ( false !== $this->rewrite ) { - remove_rewrite_tag( "%taxonomy-$this->name%" ); - remove_permastruct( "taxonomy-$this->name" ); - remove_rewrite_tag( "%$this->name%" ); remove_permastruct( $this->name ); + + remove_rewrite_tag( "%taxonomy-$this->name%" ); + remove_permastruct( "taxonomy-$this->name" ); } } From 36ae684ed6c2405b889806cc3b97fe56bbbc698f Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 13:45:56 +0200 Subject: [PATCH 20/27] Start adding some basic test coverage --- tests/phpunit/tests/canonical.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/phpunit/tests/canonical.php b/tests/phpunit/tests/canonical.php index 886b09312910e..1a3a85a3730c0 100644 --- a/tests/phpunit/tests/canonical.php +++ b/tests/phpunit/tests/canonical.php @@ -87,6 +87,13 @@ public function data_canonical() { array( '?cat=%d', array( 'url' => '/category/parent/' ), 15256 ), array( '?cat=%d', array( 'url' => '/category/parent/child-1/' ), 15256 ), array( '?cat=%d', array( 'url' => '/category/parent/child-1/child-2/' ) ), // No children. + array( + '/category/', + array( + 'url' => '/category/', + 'qv' => array( 'taxonomy' => 'category' ), + ), + ), array( '/category/uncategorized/', array( @@ -94,6 +101,16 @@ public function data_canonical() { 'qv' => array( 'category_name' => 'uncategorized' ), ), ), + array( + '/category/page/2/', + array( + 'url' => '/category/page/2/', + 'qv' => array( + 'taxonomy' => 'category', + 'paged' => 2, + ), + ), + ), array( '/category/uncategorized/page/2/', array( @@ -104,6 +121,16 @@ public function data_canonical() { ), ), ), + array( + '/category/?paged=2', + array( + 'url' => '/category/page/2/', + 'qv' => array( + 'taxonomy' => 'category', + 'paged' => 2, + ), + ), + ), array( '/category/uncategorized/?paged=2', array( From 9b68771edaf64b06a2968a64a02eb112ac4f4d06 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 13:55:20 +0200 Subject: [PATCH 21/27] Make work with query_vars --- src/wp-includes/class-wp-taxonomy.php | 7 ++++++- tests/phpunit/tests/canonical.php | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index bd649d6edb722..147d22489363f 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -510,7 +510,12 @@ public function add_rewrite_rules() { $tag = '([^/]+)'; } - add_rewrite_tag( "%taxonomy-$this->name%", "($this->name)", 'taxonomy=' ); + if ( $this->query_var ) { + add_rewrite_tag( "%taxonomy-$this->name%", "$this->name()", "{$this->query_var}=" ); + } else { + add_rewrite_tag( "%taxonomy-$this->name%", "($this->name)", 'taxonomy=' ); + } + add_permastruct( "taxonomy-$this->name", "%taxonomy-$this->name%", $this->rewrite ); add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); diff --git a/tests/phpunit/tests/canonical.php b/tests/phpunit/tests/canonical.php index 1a3a85a3730c0..2727a98e6e2d4 100644 --- a/tests/phpunit/tests/canonical.php +++ b/tests/phpunit/tests/canonical.php @@ -91,7 +91,7 @@ public function data_canonical() { '/category/', array( 'url' => '/category/', - 'qv' => array( 'taxonomy' => 'category' ), + 'qv' => array( 'category_name' => '' ), ), ), array( @@ -106,8 +106,8 @@ public function data_canonical() { array( 'url' => '/category/page/2/', 'qv' => array( - 'taxonomy' => 'category', - 'paged' => 2, + 'category_name' => '', + 'paged' => 2, ), ), ), @@ -126,8 +126,8 @@ public function data_canonical() { array( 'url' => '/category/page/2/', 'qv' => array( - 'taxonomy' => 'category', - 'paged' => 2, + 'category_name' => '', + 'paged' => 2, ), ), ), From 12f5208d0fd3f290d169b617efb176f67519e026 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 14:01:18 +0200 Subject: [PATCH 22/27] Simplify --- src/wp-includes/class-wp-taxonomy.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index 147d22489363f..7063bea95c18c 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -510,15 +510,12 @@ public function add_rewrite_rules() { $tag = '([^/]+)'; } - if ( $this->query_var ) { - add_rewrite_tag( "%taxonomy-$this->name%", "$this->name()", "{$this->query_var}=" ); - } else { - add_rewrite_tag( "%taxonomy-$this->name%", "($this->name)", 'taxonomy=' ); - } + $query = $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term="; + add_rewrite_tag( "%taxonomy-$this->name%", "$this->name()", $query ); add_permastruct( "taxonomy-$this->name", "%taxonomy-$this->name%", $this->rewrite ); - add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); + add_rewrite_tag( "%$this->name%", $tag, $query ); add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); } } From 772437fa16f8e97ac9477f0fc1a8ce6cea4a3b78 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 16:40:04 +0200 Subject: [PATCH 23/27] Add ticket references --- tests/phpunit/tests/canonical.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/phpunit/tests/canonical.php b/tests/phpunit/tests/canonical.php index 2727a98e6e2d4..04d0b2ac88b65 100644 --- a/tests/phpunit/tests/canonical.php +++ b/tests/phpunit/tests/canonical.php @@ -93,6 +93,7 @@ public function data_canonical() { 'url' => '/category/', 'qv' => array( 'category_name' => '' ), ), + 61957, ), array( '/category/uncategorized/', @@ -110,6 +111,7 @@ public function data_canonical() { 'paged' => 2, ), ), + 61957, ), array( '/category/uncategorized/page/2/', @@ -130,6 +132,7 @@ public function data_canonical() { 'paged' => 2, ), ), + 61957, ), array( '/category/uncategorized/?paged=2', From 91ddfda99fa23fc2d8ee676118ff2be279f9a0eb Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 11 Sep 2024 16:50:31 +0200 Subject: [PATCH 24/27] Add more test coverage --- tests/phpunit/tests/canonical.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/phpunit/tests/canonical.php b/tests/phpunit/tests/canonical.php index 04d0b2ac88b65..ac5b35c9adea5 100644 --- a/tests/phpunit/tests/canonical.php +++ b/tests/phpunit/tests/canonical.php @@ -157,6 +157,17 @@ public function data_canonical() { ), // Categories & intersections with other vars. + array( + '/category/?tag=post-formats', + array( + 'url' => '/category/?tag=post-formats', + 'qv' => array( + 'category_name' => '', + 'tag' => 'post-formats', + ), + ), + 61957, + ), array( '/category/uncategorized/?tag=post-formats', array( @@ -176,6 +187,7 @@ public function data_canonical() { ), // Taxonomies with extra query vars. + array( '/category/page/1/?test=one%20two', '/category/?test=one%20two', 61957 ), // Extra query vars should stay encoded. array( '/category/cat-a/page/1/?test=one%20two', '/category/cat-a/?test=one%20two', 18086 ), // Extra query vars should stay encoded. // Categories with dates. From 20e46d082370e8107d00ca960501ae8f7028fef0 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 9 Dec 2024 15:38:13 +0100 Subject: [PATCH 25/27] Rephrase for legibility --- src/wp-includes/class-wp-query.php | 72 +++++++++++++++--------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 4e8728142946f..4c646dbc2a22a 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1169,50 +1169,52 @@ public function parse_tax_query( &$q ) { continue; // Handled further down in the $q['tag'] block. } - if ( $t->query_var && isset( $q[ $t->query_var ] ) ) { - $tax_query_defaults = array( - 'taxonomy' => $taxonomy, - 'field' => 'slug', - ); + if ( ! $t->query_var || ! isset( $q[ $t->query_var ] ) ) { + continue; + } - if ( ! empty( $t->rewrite['hierarchical'] ) ) { - $q[ $t->query_var ] = wp_basename( $q[ $t->query_var ] ); - } + $tax_query_defaults = array( + 'taxonomy' => $taxonomy, + 'field' => 'slug', + ); - $term = $q[ $t->query_var ]; + if ( ! empty( $t->rewrite['hierarchical'] ) ) { + $q[ $t->query_var ] = wp_basename( $q[ $t->query_var ] ); + } - if ( is_array( $term ) ) { - $term = implode( ',', $term ); - } + $term = $q[ $t->query_var ]; - if ( str_contains( $term, '+' ) ) { - $terms = preg_split( '/[+]+/', $term ); - foreach ( $terms as $term ) { - $tax_query[] = array_merge( - $tax_query_defaults, - array( - 'terms' => array( $term ), - ) - ); - } - } elseif ( ! empty( $term ) ) { + if ( is_array( $term ) ) { + $term = implode( ',', $term ); + } + + if ( str_contains( $term, '+' ) ) { + $terms = preg_split( '/[+]+/', $term ); + foreach ( $terms as $term ) { $tax_query[] = array_merge( $tax_query_defaults, array( - 'terms' => preg_split( '/[,]+/', $term ), + 'terms' => array( $term ), + ) + ); + } + } elseif ( ! empty( $term ) ) { + $tax_query[] = array_merge( + $tax_query_defaults, + array( + 'terms' => preg_split( '/[,]+/', $term ), + ) + ); + } else { + // FIXME: Figure out why 'category' is automatically + // added as a query arg and what to do about it. + if ( 'category' !== $taxonomy ) { + $tax_query[] = array_merge( + $tax_query_defaults, + array( + 'operator' => 'EXISTS', ) ); - } else { - // FIXME: Figure out why 'category' is automatically - // added as a query arg and what to do about it. - if ( 'category' !== $taxonomy ) { - $tax_query[] = array_merge( - $tax_query_defaults, - array( - 'operator' => 'EXISTS', - ) - ); - } } } } From 73b67127fe7411e50f6b85cdb340f363747d38cf Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 9 Dec 2024 16:11:19 +0100 Subject: [PATCH 26/27] Handle default category query correctly --- src/wp-includes/class-wp-query.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 4c646dbc2a22a..738be677f5e89 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1173,6 +1173,12 @@ public function parse_tax_query( &$q ) { continue; } + if ( 'category' === $taxonomy && empty( $q[ $t->query_var ] ) ) { + // Unlike custom taxonomies, the category field is automatically added to every query. + // Thus, we need to skip it if it is empty. + continue; + } + $tax_query_defaults = array( 'taxonomy' => $taxonomy, 'field' => 'slug', @@ -1206,16 +1212,12 @@ public function parse_tax_query( &$q ) { ) ); } else { - // FIXME: Figure out why 'category' is automatically - // added as a query arg and what to do about it. - if ( 'category' !== $taxonomy ) { - $tax_query[] = array_merge( - $tax_query_defaults, - array( - 'operator' => 'EXISTS', - ) - ); - } + $tax_query[] = array_merge( + $tax_query_defaults, + array( + 'operator' => 'EXISTS', + ) + ); } } From e767570907992459cb78a12f852de7f564633bbf Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 9 Dec 2024 17:57:49 +0100 Subject: [PATCH 27/27] Add register_taxonomy flag --- src/wp-includes/class-wp-query.php | 6 +++--- src/wp-includes/class-wp-taxonomy.php | 10 ++++++++++ src/wp-includes/taxonomy.php | 3 +++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 738be677f5e89..0c8a5a3f1537b 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1173,9 +1173,9 @@ public function parse_tax_query( &$q ) { continue; } - if ( 'category' === $taxonomy && empty( $q[ $t->query_var ] ) ) { - // Unlike custom taxonomies, the category field is automatically added to every query. - // Thus, we need to skip it if it is empty. + if ( empty( $q[ $t->query_var ] ) && ! $t->root_taxonomy_archive ) { + // We only allow the term to be empty if the taxonomy is set up to + // show its root archive. continue; } diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php index 7063bea95c18c..758a790b1865d 100644 --- a/src/wp-includes/class-wp-taxonomy.php +++ b/src/wp-includes/class-wp-taxonomy.php @@ -245,6 +245,15 @@ final class WP_Taxonomy { */ public $default_term; + /** + * Whether to show a page for the root taxonomy route, displaying all + * posts that have any term from the taxonomy assigned. + * + * @since 6.8.0 + * @var bool + */ + public $root_taxonomy_archive = false; + /** * Whether terms in this taxonomy should be sorted in the order they are provided to `wp_set_object_terms()`. * @@ -359,6 +368,7 @@ public function set_props( $object_type, $args ) { 'rest_namespace' => false, 'rest_controller_class' => false, 'default_term' => null, + 'root_taxonomy_archive' => false, 'sort' => null, 'args' => null, '_builtin' => false, diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index bebf55ec79bfa..8292ded7c6e54 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -426,6 +426,7 @@ function is_taxonomy_hierarchical( $taxonomy ) { * @since 5.4.0 Added the registered taxonomy object as a return value. * @since 5.5.0 Introduced `default_term` argument. * @since 5.9.0 Introduced `rest_namespace` argument. + * @since 6.8.0 Introduced `root_taxonomy_archive` argument. * * @global WP_Taxonomy[] $wp_taxonomies Registered taxonomies. * @@ -506,6 +507,8 @@ function is_taxonomy_hierarchical( $taxonomy ) { * @type string $slug Slug for default term. Default empty. * @type string $description Description for default term. Default empty. * } + * @type bool $root_taxonomy_archive Whether to show a page at the root taxonomy route, displaying all + * posts that have any term from the taxonomy assigned. Default false. * @type bool $sort Whether terms in this taxonomy should be sorted in the order they are * provided to `wp_set_object_terms()`. Default null which equates to false. * @type array $args Array of arguments to automatically use inside `wp_get_object_terms()`