From af146fef8c5f7ec596f8cba23398e50c927b5a6a Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Fri, 16 Jan 2015 15:48:24 +0000 Subject: [PATCH] In `paginate_links()`, don't override custom format arguments when setting up default 'add_args'. Since 4.1 [29780], the default value of the 'add_args' argument in `paginate_links()` has been determined by parsing the current URL. This change had the side effect of overriding custom values of 'format' that changed the pagination query var, with the result that plugins using `paginate_links()` with a custom format generated the incorrect links unless explicitly declaring 'add_args=false' to prevent the default values from overriding. We fix this behavior by parsing URL query vars into the 'add_args' array only after the explicit function params have been parsed, and by skipping the current page's pagination query var when doing this parsing (to avoid the override). Props obenland. Fixes #30831 for trunk. git-svn-id: https://develop.svn.wordpress.org/trunk@31203 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/general-template.php | 29 ++++++--- tests/phpunit/tests/general/paginateLinks.php | 62 +++++++++++++++++++ 2 files changed, 81 insertions(+), 10 deletions(-) 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; + } }