<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[31203] trunk: In `paginate_links()`, don't override custom format arguments when setting up default 'add_args'.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/31203">31203</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/31203","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>boonebgorges</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2015-01-16 15:48:24 +0000 (Fri, 16 Jan 2015)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>In `paginate_links()`, don't override custom format arguments when setting up default 'add_args'.

Since 4.1 <a href="https://core.trac.wordpress.org/changeset/29780">[29780]</a>, 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 <a href="https://core.trac.wordpress.org/ticket/30831">#30831</a> for trunk.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesgeneraltemplatephp">trunk/src/wp-includes/general-template.php</a></li>
<li><a href="#trunktestsphpunittestsgeneralpaginateLinksphp">trunk/tests/phpunit/tests/general/paginateLinks.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesgeneraltemplatephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/general-template.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/general-template.php        2015-01-16 05:37:06 UTC (rev 31202)
+++ trunk/src/wp-includes/general-template.php  2015-01-16 15:48:24 UTC (rev 31203)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2582,20 +2582,18 @@
</span><span class="cx" style="display: block; padding: 0 10px"> function paginate_links( $args = '' ) {
</span><span class="cx" style="display: block; padding: 0 10px">        global $wp_query, $wp_rewrite;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $total        = ( isset( $wp_query->max_num_pages ) ) ? $wp_query->max_num_pages : 1;
-       $current      = ( get_query_var( 'paged' ) ) ? intval( get_query_var( 'paged' ) ) : 1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ // Setting up default values based on the current URL.
</ins><span class="cx" style="display: block; padding: 0 10px">         $pagenum_link = html_entity_decode( get_pagenum_link() );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $query_args   = array();
</del><span class="cx" style="display: block; padding: 0 10px">         $url_parts    = explode( '?', $pagenum_link );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if ( isset( $url_parts[1] ) ) {
-               wp_parse_str( $url_parts[1], $query_args );
-               $query_args = urlencode_deep( $query_args );
-       }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ // 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;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $pagenum_link = remove_query_arg( array_keys( $query_args ), $pagenum_link );
-       $pagenum_link = trailingslashit( $pagenum_link ) . '%_%';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ // Append the format placeholder to the base URL.
+       $pagenum_link = trailingslashit( $url_parts[0] ) . '%_%';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // URL base depends on permalink settings.
</ins><span class="cx" style="display: block; padding: 0 10px">         $format  = $wp_rewrite->using_index_permalinks() && ! strpos( $pagenum_link, 'index.php' ) ? 'index.php/' : '';
</span><span class="cx" style="display: block; padding: 0 10px">        $format .= $wp_rewrite->using_permalinks() ? user_trailingslashit( $wp_rewrite->pagination_base . '/%#%', 'paged' ) : '?paged=%#%';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2611,7 +2609,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                'end_size' => 1,
</span><span class="cx" style="display: block; padding: 0 10px">                'mid_size' => 2,
</span><span class="cx" style="display: block; padding: 0 10px">                'type' => 'plain',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                'add_args' => $query_args, // array of query args to add
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         'add_args' => array(), // array of query args to add
</ins><span class="cx" style="display: block; padding: 0 10px">                 'add_fragment' => '',
</span><span class="cx" style="display: block; padding: 0 10px">                'before_page_number' => '',
</span><span class="cx" style="display: block; padding: 0 10px">                'after_page_number' => ''
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2619,6 +2617,17 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $args = wp_parse_args( $args, $defaults );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // 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 ) );
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         // Who knows what else people pass in $args
</span><span class="cx" style="display: block; padding: 0 10px">        $total = (int) $args['total'];
</span><span class="cx" style="display: block; padding: 0 10px">        if ( $total < 2 ) {
</span></span></pre></div>
<a id="trunktestsphpunittestsgeneralpaginateLinksphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/general/paginateLinks.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/general/paginateLinks.php       2015-01-16 05:37:06 UTC (rev 31202)
+++ trunk/tests/phpunit/tests/general/paginateLinks.php 2015-01-16 15:48:24 UTC (rev 31203)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -229,4 +229,66 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->assertEquals( $expected_href, $href );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * @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;
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre>
</div>
</div>

</body>
</html>