Jump to content

[SOLVED] Pagination links render but do not work.

Recommended Posts

Hey everyone,

I'm pretty experienced with pagination and haven't seen this before. I have my pages pulled using $pages->find, which is working fine however using renderPager() generates pagination where the links do not work. Here are some details.

  • All templates needing pagination have pagination enabled in the admin.
  • URL Segments are not enabled.
  • Clicking on the "Next" or numbered links merely reloads the current page.
  • The link href values are properly being output with the urls being /page2, /page3, /page4, etc.
  • Manually entering the paginated urls has the same effect of reloading the current page with no new content.
  • Pages are being returned from the ->find function properly and with the proper limit.

A few other details:

  • ProcessWire v3.0.98
  • Multi-language is enabled, 2 languages implemented.
  • Pagination does not work on either language
  • Have very few modules installed (few enough to list), none of which I could see interfering:
    • ProFields, ProDrafts, ListerPro, DB Backups, Cronjob DB Backup, Upgrades, Upgrade Checker, Force Password Change, Markup Sitemap XML

I'm stumped. For the sake of being overly-thorough, here's the code:

  $articleTemplates = [

  $searchParams = [
    'template=' . implode('|', $articleTemplates),
    'limit=' . $pages->get('template=template_news')->list_count

  $articles = $pages->find(implode(',', $searchParams));
  echo $articles->renderPager();


Share this post

Link to post
Share on other sites

So I figured out the source of the issue. I wrote some code that detects a user's preferred language either from their browser language setting, or from a cookie that is created when they have visited and chose a language last time.

If a preferred language detected and the current page URL does not match it, it will redirect to the same page but in the proper language.

My problem is finding a way to get the URL that includes the pagination to compare. Right now my idea is to use $input->pageNum to build the URL myself... is there a way to get the URL including the page number?

Lesson learned...

Share this post

Link to post
Share on other sites
1 hour ago, usualCommission said:

is there a way to get the URL including the page number?

I'm not 100% I understand your question. Maybe you can try combination of $input->pageNum and $pager->getURL()? E.g.:


Note the caveat in the $pager->getURL() method at the above link.

Could this topic be of interest?



Edited by kongondo

Share this post

Link to post
Share on other sites

Yeah, I'm not explaining my situation well enough and it's becoming a little more complex.

I'm working on abstracting localization to a class where one of the methods is used to redirect the user to their preferred language. That preferred language is either the language preference they have set in their browser, or a language cookie that was set last time they visited and selected a language via a select dropdown in the nav. That said, since the method is run on page load it will not have any access to specific pagination instances because they don't exist yet.

I read the link above and didn't see a solution that covers all of the bases and the module reference in a link to another post is no longer maintained, so I am going to write a custom implementation.

Here's my solution:

  • Language detection will be tied to a unique session variable.
  • On page load, the script checks for that session variable, if it exists- it exits because the language has been checked/redirected if necessary on ingress already.
  • If no language session variable exists, then compare the destination URL against the URL of that page for their preferred language.
  • If the URLs do not match then build a new URL
  • The destination URL is checked for page numbering using $input->pageNum(), if  > 1 then create a URL string for that. Any GET variables are extracted and rebuilt into a string- this preserves any possible incoming variables like UTM trackers.
  • Get localized URL for user's preferred language, re-add page number, re-add any GET variables that existed.
  • Set unique language session variable, then properly redirect to the localized page using the build URL.

I kind of wish that there was a built in method that could wrap most of this up and preserve URL details while redirecting to a given translated page, but this should work and also only redirect once.

I may be over-complicating this but it's what I've got. I really appreciate your help!

Share this post

Link to post
Share on other sites

Something like this would be the easiest way, I can think of, to do what you are doing. Redirect to a another language, including urlSegments, Pagenumber and optional QueryStrings;

if($user->language->isDefault) {
	$user->language = $languages->get("de");
	$session->redirect($input->url($withQueryString = true));


  • Like 2

Share this post

Link to post
Share on other sites

That sets the user language properly but getting the $input->url(true) still gets the non-localized version of the URL so it doesn't redirect to the translated page. It loops and fails the redirect.

Also the language move has been a little rough because using the code below seems to lead to a possible solution but is where I was hitting the paging/GET issues.

$languages->setLanguage(-lang str here-); // Also sets the language as a $user->language assignment does
$page->localHttpUrl($user->language); // Returns the proper localized URL, but does not include pagination or GET vars

I've seen many posts in the forums about redirection to a language and all of them use $page->localUrl($user->langauge) and none consider GET vars. Multi-language documentation says that the $page->localUrl() will automatically adjust to pagination but I haven't seen it. Would still have to manually build GET vars.


Share this post

Link to post
Share on other sites

How about getting the url-segments/page-num/get-vars suffix and then appending that to $page->localUrl?

$url_suffix = str_replace($page->url, '', $input->url(true));
$redirect_url = $page->localUrl() . $url_suffix;


  • Thanks 1

Share this post

Link to post
Share on other sites

Added that to a comparison and that did the trick! Here's the method after adding your trick:

private function doInitLocalization() {
  $page = wire('page');
  $user = wire('user');
  $input = wire('input');

  // Get/set user language from either browser or cookie
  $user->language = $this->getLangFromCookie() ?: $this->getValidBrowserPrefLang();

  $urlSuffix = str_replace($page->url, '', $input->url(true));
  $userUrl = $page->localUrl($user->language) . $urlSuffix;

  if ($_SERVER['REQUEST_URI'] !== $userUrl) {
    header("Location: {$userUrl}");

getLangFromCookie() checks if the user has visited previously and selected a language from a dropdown.
getValidBrowserPrefLang() gets the language pref sent by the browser, if it exists as a language in the CMS, returns the value.

By setting the language for the user this checks against what the browser request asked for/server is delivering vs. what the CMS knows it should be delivering. If they differ, then redirect.

This is executed in _init.php so any point of ingress is checked for url vs. preference.

Thanks @kongondo for introducing me to $input->url and the good idea for direction.
Thanks @Soma for concluding my head->desk marathon. Your solution is the simple one I couldn't see.


Share this post

Link to post
Share on other sites

When you change the $user->language, all following API returns stuff in that language also, the $page->url or $input->url. No need to do str_eplace on something already the same.

So if $this.>getLangFromCookie does return the language object then you can change it to this.

private function doInitLocalization() {
  $user = wire('user');
  $input = wire('input');

  // Get/set user language from either browser or cookie
  $language = $this->getLangFromCookie() ?: $this->getValidBrowserPrefLang();
  if($language !== $user->language) {
    $user->language = $language;


  • Like 1

Share this post

Link to post
Share on other sites

Good to know.

$this->getLangFromCookie() returns a string and is shared by other methods in the same/other classes. I could probably refactor it to work directly with the language object, but I'll have to come back to that sometime. Appreciate that info.

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By ottogal
      Hello all,
      using PW 3.0.148 with the regular site profile for a blog, I got an an empty pagination output when I had a Toggle field in the selector.
      The Toggle Fieldtype was introduced with https://processwire.com/blog/posts/pw-3.0.139/ .
      The selector resulting in empty pagination:
      $posts = $pages->find("parent=blog, sort=-date, limit=10, toggle_field=0"); It worked well, when I replaced the Toggle field with a Checkbox field:
      $posts = $pages->find("parent=blog, sort=-date, limit=10, checkbox_field=0"); So the prerequisites for the pagination to work are given.
      The settings for the Toggle field were:
      Formatted value: Integer Label Type: Yes/No Input Type: Toggle buttons Default selected option: No Thanks for any hints!
    • By jacmaes
      I have a series of videos, and the following search form (translated into English here) that allows to filter these videos on the frontend:

      I've built a few of these search forms, but only with text fields, selects and radio buttons. Here I'm using an array with checkboxes ("Level" field above), and it's causing me grief when I try to paginate these results. I've done a lot of searching in the forum and spent too many hours to try to get it to work. Here's how I'm building the selector:
      <?php if(count($input->get)): // Level is an array. Code adapted from Ryan's snippet here: // https://processwire.com/talk/topic/3472-enable-pagination-for-search-results/?tab=comments#comment-38042 if($input->get->level) { $level = array(); foreach($input->get->level as $id) $level[] = (int) $id; // sanitize to INTs $level = implode('|', $level); // convert to 123|456|789 string, ready for selector } else { $level = ''; } $data = array( 'training_type' => array('=', (int) $input->get->training_type), 'duration' => array('=', (int) $input->get->duration), 'level' => array('=', $level), 'limit' => array('=', (int) $input->get->limit) ); $selector = ''; // iterate through the $data we made above to create a selector string foreach($data as $field => $a) { list($operator, $value) = $a; if(empty($value)) continue; // send value to the whitelist so that it can be used in pagination $input->whitelist($field, $value); // append to our selector string $selector .= "$field$operator$value, "; } $videos = $page->children("$selector"); When I hit search, I get the expected results. So far so good. The GET parameters are the following with the options selected in the screenshot above:
      videos/?level[]=1476&level[]=1477&training_type=1473&duration=1485&limit=10 $selector echoes the following as the "level" field is an array with a pipe character:
      level=1476|1477, training_type=1473, duration=1485, limit=10 Now, when paginating these results, the following page (page 2) shows these GET parameters:
      videos/page2/?level=1476|1477&training_type=1473&duration=1486&limit=10 And I think that's where the problem lies. The "level" field is "lost" and I'm getting more results than expected on subsequent pages. If I manually add "page2" to the initial results in the URL, just to test, everything works fine:
      videos/page2/?level[]=1476&level[]=1477&training_type=1473&duration=1486&limit=10 But how can I achieve this in code? Do I need to revert to "level[]=1475&level[]=1477" instead of "level=1476|1477" for the pagination to work correctly, and can you PHP gods illuminate me?
      Any help would be really appreciated, really.
    • By christophengelmayer
      Hi everyone,
      I'm working on a CLI script that renders paginated pages.
      Therefore I iterate trough paginated pages and set the page number and render the result.
      My problem is, after calling the render function for the first time, the output doesn't change even if I change the page number.
      I'm using a template that renders a pagination of its children:
      <?php echo $page->children("limit=3")->render(); ?> I can view the paginated results in the Browser:
      /page-rendering-pagination/ /page-rendering-pagination/page2 /page-rendering-pagination/page3 ... When trying to render the different pages using the API I always get the first result, even if I change the page Number.
      <?php namespace ProcessWire; include('./index.php'); wire('input')->setPageNum(1); $p = wire('pages')->get('/page-rendering-pagination'); var_dump($p->render()); // renders first three items wire('input')->setPageNum(2); var_dump($p->render()); // also renders the first three items Am I missing something? Is there some kind of caching mechanism that I'm not aware of?
      Thanks for your help.
    • By dragan
      Quick question: Is it possible to use PW's pagination for other things than PageArrays? i.e. query custom database tables and paginate the results? Has anyone ever tried it?
    • By brdje
      I've created a product database which all use the template product.php and are published on the website.
      I'm trying to create an overview table with pagination of all the products, but using $pages->get does not return an object, only the object title.
      $products = $pages->get("template=product, limit=10"); This returns 10 strings in the frontend but not the object. When looping over the result set to get product fields, i get the following error:
      Notice: Trying to get property 'title' of non-object
      Because the product database is fairly large, i've added a pagination using the same query and this does return all the pages, but i can't click on the links that the paginator renders.
      $results = $pages->find("template=product, limit=10"); if($results->getTotal() > 10) { echo $results->renderPager(array( "nextItemLabel" => "Volgende", "previousItemLabel" => "Vorige", "currentItemClass" => 'active' )); }
      I've added the option in the template to allow page numbers. When i navigate to the link manually, i still end up seeing the 10 first products.
      I've tried changing several settings around, but i'm a bit stuck on how to resolve these issues. Do you have any advice what I need to adjust?
      Thanks in advance for your feedback.
  • Create New...