Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/wp-includes/class-wp-rewrite.php
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,11 @@ public function generate_rewrite_rules( $permalink_structure, $ep_mask = EP_NONE

$num_tokens = count( $tokens[0] );

$quoted_rewritecode = array();
foreach ( $this->rewritecode as $code ) {
$quoted_rewritecode[] = preg_quote( $code, '#' );
}

$index = $this->index; // Probably 'index.php'.
$feedindex = $index;
$trackbackindex = $index;
Expand Down Expand Up @@ -960,7 +965,7 @@ public function generate_rewrite_rules( $permalink_structure, $ep_mask = EP_NONE
$struct = ltrim( $struct, '/' );

// Replace tags with regexes.
$match = str_replace( $this->rewritecode, $this->rewritereplace, $struct );
$match = str_replace( $quoted_rewritecode, $this->rewritereplace, preg_quote( $struct, '#' ) );

// Make a list of tags, and store how many there are in $num_toks.
$num_toks = preg_match_all( '/%.+?%/', $struct, $toks );
Expand Down Expand Up @@ -1102,8 +1107,12 @@ public function generate_rewrite_rules( $permalink_structure, $ep_mask = EP_NONE
// Trim slashes from the end of the regex for this dir.
$match = rtrim( $match, '/' );

// Get rid of brackets.
$submatchbase = str_replace( array( '(', ')' ), '', $match );
// Remove capture groups from rewrite tag regexes for attachment rules.
$submatchbase = str_replace(
$quoted_rewritecode,
str_replace( array( '(', ')' ), '', $this->rewritereplace ),
preg_quote( rtrim( $struct, '/' ), '#' )
);

// Add a rule for at attachments, which take the form of <permalink>/some-text.
$sub1 = $submatchbase . '/([^/]+)/';
Expand Down
64 changes: 64 additions & 0 deletions tests/phpunit/tests/rewrite.php
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,70 @@ public function test_parse_request_with_post_slug_that_clashes_with_a_trashed_pa
$this->assertFalse( is_404() );
}

/**
* @ticket 49510
*/
public function test_taxonomy_bases_with_regex_metacharacters() {
update_option( 'category_base', 'cat+base' );
update_option( 'tag_base', 'tag+base' );
create_initial_taxonomies();
delete_option( 'rewrite_rules' );

$category_id = self::factory()->term->create(
array(
'name' => 'Category A',
'taxonomy' => 'category',
)
);
$tag_id = self::factory()->term->create(
array(
'name' => 'Tag A',
'taxonomy' => 'post_tag',
)
);

$this->go_to( get_term_link( $category_id, 'category' ) );
$category_name = get_query_var( 'category_name' );

$this->go_to( get_term_link( $tag_id, 'post_tag' ) );

$this->assertSame(
array( 'category-a', 'tag-a' ),
array( $category_name, get_query_var( 'tag' ) )
);
}

/**
* @ticket 49510
*/
public function test_taxonomy_base_regex_metacharacter_is_literal() {
update_option( 'category_base', 'cat.base' );
create_initial_taxonomies();
delete_option( 'rewrite_rules' );

self::factory()->term->create(
array(
'name' => 'Category A',
'taxonomy' => 'category',
)
);

$this->go_to( '/catXbase/category-a/' );

$this->assertSame( '', get_query_var( 'category_name' ) );
}

/**
* @ticket 49510
*/
public function test_permalink_regex_metacharacters_are_literal_in_attachment_rules() {
global $wp_rewrite;

$rules = $wp_rewrite->generate_rewrite_rules( '/archive(2026)/%postname%/', EP_PERMALINK );

$this->assertSame( 'index.php?attachment=$matches[1]', $rules['archive\(2026\)/[^/]+/attachment/([^/]+)/?$'] );
}

/**
* @ticket 29107
*/
Expand Down
13 changes: 13 additions & 0 deletions tests/phpunit/tests/rewrite/rewriteTags.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,19 @@ public function test_add_rewrite_tag_updates_existing() {
$this->assertNotContains( 'pagename=', $wp_rewrite->queryreplace );
}

/**
* @ticket 49510
*/
public function test_generate_rewrite_rules_with_regex_metacharacter_in_tag() {
global $wp_rewrite;

add_rewrite_tag( '%foo.bar%', '([^/]+)', 'foo=' );

$rules = $wp_rewrite->generate_rewrite_rules( '/base/%foo.bar%' );

$this->assertSame( 'index.php?foo=$1', $rules['base/([^/]+)/?$'] );
}

public function test_remove_rewrite_tag() {
global $wp_rewrite;

Expand Down
Loading