Since my earlier CakePHP post seemed to help some folks out, I’m back with another Pro-Tip that improves Cake’s handling of paged results. Its built-in pagination functions are nearly ideal except for one glaring problem: the query string is not preserved between pages. This adds unnecessary difficulty when implementing such basic functionality as search results, which often rely on the query string (See: Google).
You may have already picked up the common advice to add the following code to your views:
$paginator->options(array('url' => $this->passedArgs));
Normally the passedArgs here are simply the parameters for the current action, which are part of the current page’s URL. In most cases you want to preserve these, so the code above will do that for you. However, the query string is not preserved, so we need to add a bit of extra code. Luckily the “url” option maps to an array that is processed by the core Router url function. If one of these array keys is “?” then its value (either a string or an array) will be transformed into a query string for the resulting URL. We simply want to include the current query string as it already exists, so we can use a built-in PHP function to do that, then merge it with passedArgs in our final code:
$paginator->options(array('url' => array_merge($this->passedArgs, array('?' => ltrim(strstr($_SERVER['QUERY_STRING'], '&'), '&')))));
The reason we have to incorporate ltrim and strstr is because CakePHP already processes every page request with a “behind the scenes” query string that contains an initial “url” variable. We don’t need this for our purposes, so we discard it and take the rest of the query string.
Truthfully I feel like this functionality should be nicely integrated into Cake by default, instead of requiring the use of this fix. Perhaps another $paginator option is needed in the view that allows one of three values for URL preservation: the current action only (which is presently the default), the full URL minus the query string, and the full URL including the query string (which I believe should be the default). But until then, I hope this tweak can help you out.