Skip to content

Commit 5117f0b

Browse files
committed
Applied patch WordPress#8591
1 parent fd2693d commit 5117f0b

2 files changed

Lines changed: 160 additions & 0 deletions

File tree

src/wp-includes/general-template.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4664,6 +4664,20 @@ function paginate_links( $args = '' ) {
46644664
$format = $wp_rewrite->using_index_permalinks() && ! strpos( $pagenum_link, 'index.php' ) ? 'index.php/' : '';
46654665
$format .= $wp_rewrite->using_permalinks() ? user_trailingslashit( $wp_rewrite->pagination_base . '/%#%', 'paged' ) : '?paged=%#%';
46664666

4667+
/*
4668+
* Modify defaults for sites without trailing slashed permalinks.
4669+
*
4670+
* Ensures sites not using trailing slashes get links in the form
4671+
* `/page/2` rather than `/page/2/`. On these sites, linking to the
4672+
* URL with a trailing slash will results in a 301 redirect from the
4673+
* incorrect URL to the correctly formattted one. This presents an
4674+
* unnecessary performance hit.
4675+
*/
4676+
if ( $wp_rewrite->using_permalinks() && ! $wp_rewrite->use_trailing_slashes ) {
4677+
$pagenum_link = str_replace( '/%_%', '%_%', $pagenum_link );
4678+
$format = '/' . ltrim( $format, '/' );
4679+
}
4680+
46674681
$defaults = array(
46684682
'base' => $pagenum_link, // http://example.com/all_posts.php%_% : %_% is replaced by format (below).
46694683
'format' => $format, // ?page=%#% : %#% is replaced by the page number.

tests/phpunit/tests/general/paginateLinks.php

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,40 @@ class Tests_General_PaginateLinks extends WP_UnitTestCase {
99

1010
private $i18n_count = 0;
1111

12+
/**
13+
* Post IDs created for shared fixtures.
14+
*
15+
* @var int[]
16+
*/
17+
public static $post_ids = array();
18+
19+
/**
20+
* Category ID created for shared fixtures.
21+
*
22+
* @var int
23+
*/
24+
public static $category_id = 0;
25+
26+
/**
27+
* Set up shared fixtures.
28+
*
29+
* @param WP_UnitTest_Factory $factory Factory instance.
30+
*/
31+
public static function wpSetUpBeforeClass( $factory ) {
32+
self::$category_id = $factory->term->create(
33+
array(
34+
'taxonomy' => 'category',
35+
'name' => 'Categorized',
36+
array( 'slug' => 'categorized' ),
37+
)
38+
);
39+
40+
self::$post_ids = $factory->post->create_many( 10 );
41+
foreach ( self::$post_ids as $post_id ) {
42+
wp_set_post_categories( $post_id, array( self::$category_id ) );
43+
}
44+
}
45+
1246
public function set_up() {
1347
parent::set_up();
1448

@@ -383,4 +417,116 @@ public function test_custom_base_query_arg_should_be_stripped_from_current_url_b
383417
$page_2_url = home_url() . '?foo=2';
384418
$this->assertContains( "<a class=\"page-numbers\" href=\"$page_2_url\">2</a>", $links );
385419
}
420+
421+
/**
422+
* Ensures pagination links include trailing slashes when the permalink structure includes them.
423+
*
424+
* @ticket 61393
425+
*/
426+
public function test_permalinks_with_trailing_slash_produce_links_with_trailing_slashes() {
427+
update_option( 'posts_per_page', 2 );
428+
$this->set_permalink_structure( '/%postname%/' );
429+
430+
$this->go_to( '/category/categorized/page/2/' );
431+
432+
// For some reason current isn't picked up.
433+
$links = paginate_links( array( 'current' => 2 ) );
434+
435+
$base_url = untrailingslashit( home_url( '/category/categorized/' ) );
436+
$this->assertStringContainsString( "href=\"{$base_url}/\"", $links, 'The links should link to page one with a trailing slash.' );
437+
$this->assertStringNotContainsString( "href=\"{$base_url}\"", $links, 'The links should not link to page one without a trailing slash.' );
438+
439+
$base_url_regex = preg_quote( $base_url, '/' );
440+
$this->assertMatchesRegularExpression( "/href=\"{$base_url_regex}\/page\/[0-9]\/\"/", $links, 'Pagination links with trailing slashes should be included.' );
441+
$this->assertDoesNotMatchRegularExpression( "/href=\"{$base_url_regex}\/page\/[0-9]\"/", $links, 'Pagination links without trailing slashes should not be included.' );
442+
}
443+
444+
/**
445+
* Ensures pagination links do not include trailing slashes when the permalink structure doesn't includes them.
446+
*
447+
* @ticket 61393
448+
*/
449+
public function test_permalinks_without_trailing_slash_produce_links_without_trailing_slashes() {
450+
update_option( 'posts_per_page', 2 );
451+
$this->set_permalink_structure( '/%postname%' );
452+
453+
$this->go_to( '/category/categorized/page/2' );
454+
455+
// For some reason current isn't picked up.
456+
$links = paginate_links( array( 'current' => 2 ) );
457+
458+
$base_url = untrailingslashit( home_url( '/category/categorized/' ) );
459+
$this->assertStringNotContainsString( "href=\"{$base_url}/\"", $links, 'The links should link to page one without a trailing slash.' );
460+
$this->assertStringContainsString( "href=\"{$base_url}\"", $links, 'The links should not link to page one with a trailing slash.' );
461+
462+
$base_url_regex = preg_quote( $base_url, '/' );
463+
$this->assertDoesNotMatchRegularExpression( "/href=\"$base_url_regex}\/page\/[0-9]\/\"/", $links, 'Pagination links with trailing slashes should not be included.' );
464+
$this->assertMatchesRegularExpression( "/href=\"{$base_url_regex}\/page\/[0-9]\"/", $links, 'Pagination links without trailing slashes should be included.' );
465+
}
466+
467+
/**
468+
* Ensures the pagination links do not modify query strings (permalinks with trailing slash).
469+
*
470+
* @ticket 61393
471+
* @ticket 63123
472+
*
473+
* @dataProvider data_query_strings
474+
*
475+
* @param string $query_string Query string.
476+
* @param string $unexpected Unexpected query string.
477+
*/
478+
public function test_permalinks_with_trailing_slash_do_not_modify_query_strings( $query_string, $unexpected ) {
479+
update_option( 'posts_per_page', 2 );
480+
$this->set_permalink_structure( '/%postname%/' );
481+
482+
$this->go_to( "/page/2/?{$query_string}" );
483+
484+
// For some reason current isn't picked up.
485+
$links = paginate_links( array( 'current' => 2 ) );
486+
487+
$this->assertStringContainsString( "/page/3/?{$query_string}\"", $links, 'The query string should appear in the links.' );
488+
$this->assertStringNotContainsString( "/page/3/?{$unexpected}\"", $links, 'The query string should not be modified.' );
489+
}
490+
491+
/**
492+
* Ensures the pagination links do not modify query strings (permalinks without trailing slash).
493+
*
494+
* @ticket 61393
495+
* @ticket 63123
496+
*
497+
* @dataProvider data_query_strings
498+
*
499+
* @param string $query_string Query string.
500+
* @param string $unexpected Unexpected query string.
501+
*/
502+
public function test_permalinks_without_trailing_slash_do_not_modify_query_strings( $query_string, $unexpected ) {
503+
update_option( 'posts_per_page', 2 );
504+
$this->set_permalink_structure( '/%postname%' );
505+
506+
$this->go_to( "/page/2?{$query_string}" );
507+
508+
// For some reason current isn't picked up.
509+
$links = paginate_links( array( 'current' => 2 ) );
510+
511+
$this->assertStringContainsString( "/page/3?{$query_string}\"", $links, 'The query string should appear in the links.' );
512+
$this->assertStringNotContainsString( "/page/3?{$unexpected}\"", $links, 'The query string should not be modified.' );
513+
}
514+
515+
/**
516+
* Data provider for
517+
* - test_permalinks_without_trailing_slash_do_not_modify_query_strings
518+
* - test_permalinks_with_trailing_slash_do_not_modify_query_strings
519+
*
520+
* @return array[] Data provider.
521+
*/
522+
public function data_query_strings() {
523+
return array(
524+
array( 'foo=bar', 'foo=bar/' ),
525+
array( 'foo=bar', 'foo=bar%2F' ),
526+
array( 'foo=bar%2F', 'foo=bar' ),
527+
528+
array( 's=post', 's=post/' ),
529+
array( 's=post', 's=post%2F' ),
530+
);
531+
}
386532
}

0 commit comments

Comments
 (0)