Changing CakePHP pagination URLs

CakePHP framework provides a great pagination helper but its default URLs aren’t that great. By default it generates URLs that look like: http://domain/news/page:2. I spent a long time looking for a way to skip “page:” part in URLs and in links generated by the helper, or even just change the string “page” to something else. It showed up that there’s no easy way to configure the paginator that way. So I came up with a workaround that will change your CakePHP pagination URLs to: http://domain/news/2
Assuming that you already created pagination on your site according to CakePHP instructions we will start making a few changes. We begin with the view where we want to modify automatically generated links into the new ones:

$prev_link = str_replace('page:', '', $paginator->prev('« Prev'));
$prev_link = preg_replace('/\/1"/', '"', $prev_link);
$next_link = str_replace('page:', '', $paginator->next('Next »'));
echo $prev_link;
echo $next_link;

This will take out “page:” part from the prev/next links and make them only contain the page number instead. Also, we replace  http://domain/news/1 with only http://domain/news in order to avoid alias URLs and penalties for duplicate content by search engines. Be sure to apply the same method to the rest of your links such as those generated by numbers() method etc., if you are using them.
Now we need to make sure that the Cake makes correct interpretation of the passed argument. In our router file we add something like:

Router::connect('/news/*', array('controller' => 'news', 'action' => 'display'));

This will forward our pagination links to news controller and its display() method. Our page number parameter will be passed as argument to this method. Let’s take a look at the code in news_controller.php:

public function display($option='') {
if (is_numeric($option)) {
$this->passedArgs['page'] = $option;
}
$items = $this->paginate('News');
...
}

As we can see we take the passed argument and assign it to the passedArgs array under the page’ key where all named URL parameters are held. This way the paginator will understand that we are on the page passed by our URL.
That’s it. If you’ve done it correctly you now have nice pagination URLs like:
http://domain/news
http://domain/news/2
http://domain/news/3
instead of:
http://domain/news
http://domain/news/page:1 (duplicate)
http://domain/news/page:2
http://domain/news/page:3