diff --git a/src/wp-includes/general-template.php b/src/wp-includes/general-template.php index de0f921dab..51cc66bb23 100644 --- a/src/wp-includes/general-template.php +++ b/src/wp-includes/general-template.php @@ -2582,20 +2582,18 @@ function language_attributes($doctype = 'html') { function paginate_links( $args = '' ) { global $wp_query, $wp_rewrite; - $total = ( isset( $wp_query->max_num_pages ) ) ? $wp_query->max_num_pages : 1; - $current = ( get_query_var( 'paged' ) ) ? intval( get_query_var( 'paged' ) ) : 1; + // Setting up default values based on the current URL. $pagenum_link = html_entity_decode( get_pagenum_link() ); - $query_args = array(); $url_parts = explode( '?', $pagenum_link ); - if ( isset( $url_parts[1] ) ) { - wp_parse_str( $url_parts[1], $query_args ); - $query_args = urlencode_deep( $query_args ); - } + // Get max pages and current page out of the current query, if available. + $total = isset( $wp_query->max_num_pages ) ? $wp_query->max_num_pages : 1; + $current = get_query_var( 'paged' ) ? intval( get_query_var( 'paged' ) ) : 1; - $pagenum_link = remove_query_arg( array_keys( $query_args ), $pagenum_link ); - $pagenum_link = trailingslashit( $pagenum_link ) . '%_%'; + // Append the format placeholder to the base URL. + $pagenum_link = trailingslashit( $url_parts[0] ) . '%_%'; + // URL base depends on permalink settings. $format = $wp_rewrite->using_index_permalinks() && ! strpos( $pagenum_link, 'index.php' ) ? 'index.php/' : ''; $format .= $wp_rewrite->using_permalinks() ? user_trailingslashit( $wp_rewrite->pagination_base . '/%#%', 'paged' ) : '?paged=%#%'; @@ -2611,7 +2609,7 @@ function paginate_links( $args = '' ) { 'end_size' => 1, 'mid_size' => 2, 'type' => 'plain', - 'add_args' => $query_args, // array of query args to add + 'add_args' => array(), // array of query args to add 'add_fragment' => '', 'before_page_number' => '', 'after_page_number' => '' @@ -2619,6 +2617,17 @@ function paginate_links( $args = '' ) { $args = wp_parse_args( $args, $defaults ); + // Merge additional query vars found in the original URL into 'add_args' array. + if ( isset( $url_parts[1] ) ) { + // Find the format argument. + $format_query = parse_url( str_replace( '%_%', $args['format'], $args['base'] ), PHP_URL_QUERY ); + wp_parse_str( $format_query, $format_arg ); + + // Remove the format argument from the array of query arguments, to avoid overwriting custom format. + wp_parse_str( remove_query_arg( array_keys( $format_arg ), $url_parts[1] ), $query_args ); + $args['add_args'] = array_merge( $args['add_args'], urlencode_deep( $query_args ) ); + } + // Who knows what else people pass in $args $total = (int) $args['total']; if ( $total < 2 ) { diff --git a/tests/phpunit/tests/general/paginateLinks.php b/tests/phpunit/tests/general/paginateLinks.php index b2083bbd26..930dcde301 100644 --- a/tests/phpunit/tests/general/paginateLinks.php +++ b/tests/phpunit/tests/general/paginateLinks.php @@ -229,4 +229,66 @@ EXPECTED; $this->assertEquals( $expected_href, $href ); } } + + /** + * @ticket 30831 + */ + function test_paginate_links_with_custom_query_args() { + add_filter( 'get_pagenum_link', array( $this, 'add_query_arg' ) ); + $links = paginate_links( array( + 'current' => 2, + 'total' => 5, + 'end_size' => 1, + 'mid_size' => 1, + 'type' => 'array', + 'add_args' => array( + 'baz' => 'qux', + ), + ) ); + remove_filter( 'get_pagenum_link', array( $this, 'add_query_arg' ) ); + + $document = new DOMDocument(); + $document->preserveWhiteSpace = false; + + $data = array( + 0 => home_url( '/?baz=qux&foo=bar&s=search+term' ), + 1 => home_url( '/?baz=qux&foo=bar&s=search+term' ), + 3 => home_url( '/?paged=3&baz=qux&foo=bar&s=search+term' ), + 5 => home_url( '/?paged=5&baz=qux&foo=bar&s=search+term' ), + 6 => home_url( '/?paged=3&baz=qux&foo=bar&s=search+term' ), + ); + + foreach ( $data as $index => $expected_href ) { + $document->loadHTML( $links[ $index ] ); + $tag = $document->getElementsByTagName( 'a' )->item( 0 ); + $this->assertNotNull( $tag ); + + $href = $tag->attributes->getNamedItem( 'href' )->value; + $this->assertEquals( $expected_href, $href ); + } + } + + /** + * @ticket 30831 + */ + public function test_paginate_links_should_allow_non_default_format_without_add_args() { + // Fake the query params. + $request_uri = $_SERVER['REQUEST_URI']; + $_SERVER['REQUEST_URI'] = add_query_arg( 'foo', 3, home_url() ); + + $links = paginate_links( array( + 'base' => add_query_arg( 'foo', '%#%' ), + 'format' => '', + 'total' => 5, + 'current' => 3, + 'type' => 'array', + ) ); + + $this->assertContains( '?foo=1', $links[1] ); + $this->assertContains( '?foo=2', $links[2] ); + $this->assertContains( '?foo=4', $links[4] ); + $this->assertContains( '?foo=5', $links[5] ); + + $_SERVER['REQUEST_URI'] = $request_uri; + } }