Jump to content

Enable pagination for search results?


antknight
 Share

Recommended Posts

Hello, I am just using the basic search template and was wondering how to enable pagination for the search results, it is simple enough to do for other pages just can't get it working for search.

<?php

/**
 * Search template
 *
 */

$out = '';

if($q = $sanitizer->selectorValue($input->get->q)) {

	// Send our sanitized query 'q' variable to the whitelist where it will be
	// picked up and echoed in the search box by the head.inc file.
	$input->whitelist('q', $q); 

	// Search the title, body and sidebar fields for our query text.
	// Limit the results to 50 pages. 
	// Exclude results that use the 'admin' template. 
	$matches = $pages->find("title|body|sidebar~=$q, limit=50"); 

	$count = count($matches); 

	if($count) {
		$out .= "<h2>Found $count pages matching your query:</h2>" . 
			"<ul class='nav'>";

		foreach($matches as $m) {
			$out .= "<li><p><a href='{$m->url}'>{$m->title}</a><br />{$m->summary}</p></li>";
		}

		$out .= "</ul>";

	} else {
		$out .= "<h2>Sorry, no results were found.</h2>";
	}
} else {
	$out .= "<h2>Please enter a search term in the search box (upper right corner)</h2>";
}

// Note that we stored our output in $out before printing it because we wanted to execute
// the search before including the header template. This is because the header template 
// displays the current search query in the search box (via the $input->whitelist) and 
// we wanted to make sure we had that setup before including the header template. 

include("./head.inc"); 

echo $out; 

include("./foot.inc"); 
Link to comment
Share on other sites

Thanks for the tips, you will be pleased to know I managed to figure it out! :

<?php

/**
 * Search template
 *
 */

$out = '';

if($q = $sanitizer->selectorValue($input->get->q)) {

	// Send our sanitized query 'q' variable to the whitelist where it will be
	// picked up and echoed in the search box by the head.inc file.
	$input->whitelist('q', $q); 

	// Search the title, body and sidebar fields for our query text.
	// Limit the results to 50 pages. 
	// Exclude results that use the 'admin' template. 
	$matches = $pages->find("title|body|sidebar~=$q, limit=50");
        $pagination = $matches->renderPager(array(
         'numPageLinks' => "5",
         'nextItemLabel' => "Next",
         'previousItemLabel' => "Prev",
         'listMarkup' => "<ul class='MarkupPagerNav'>{out}</ul>",
         'itemMarkup' => "<li class='{class}'>{out}</li>",
         'linkMarkup' => "<a href='{url}'><span>{out}</span></a>"));

	$count = count($matches); 

	if($count) {
		$out .= "<h2>Found $count pages matching your query:</h2>" . 
			"<ul class='nav'>";

		foreach($matches as $m) {
			$out .= "<li><p><a href='{$m->url}'>{$m->title}</a><br />{$m->summary}</p></li>";
		}

		$out .= "</ul>";

	} else {
		$out .= "<h2>Sorry, no results were found.</h2>";
	}
} else {
	$out .= "<h2>Please enter a search term in the search box (upper right corner)</h2>";
}

// Note that we stored our output in $out before printing it because we wanted to execute
// the search before including the header template. This is because the header template 
// displays the current search query in the search box (via the $input->whitelist) and 
// we wanted to make sure we had that setup before including the header template. 

include("./head.inc"); 

echo $out; 
echo $pagination;

include("./foot.inc");
  • Like 1
Link to comment
Share on other sites

  • 1 month later...

Hello guys, need a little help here.

I'm also trying to set pager for search results but the whole query string seems to be stripped out in links that pager renders.

// page url
http://domain.com/search/?vendor[]=1087&vendor[]=1212&light_source_amount=&product_family=&safety_class=&voltage=&height_min=&height_max=&length_min=&length_max=&width_min=&width_max=&depth_min=&depth_max=&hanging_height_min=&hanging_height_max=&diameter_min=&diameter_max=

// pager urls
http://domain.com/search/?page=2
http://domain.com/search/?page=3
http://domain.com/search/?page=4

Can it be because the query string is so freaking long?

Link to comment
Share on other sites

Aah, ok.. now it's looking better. Thanks!

Still not there yet.. Now pager url looks like this:

http://domain.com/search/?vendor=1087|1212&light_source_amount=&product_family=&safety_class=&voltage=&height_min=&height_max=&length_min=&length_max=&width_min=&width_max=&depth_min=&depth_max=&hanging_height_min=&hanging_height_max=&diameter_min=&diameter_max=&page=2

Notice pipes as vendor delimiters. OK, then I click to page 2 but nothing happens. Same results and pager page 1 is active. Only difference is that now pager urls have changed to use plus sign as delimiter:

http://domain.com/search/?vendor=1087+1212&light_source_amount=&product_family=&safety_class=&voltage=&height_min=&height_max=&length_min=&length_max=&width_min=&width_max=&depth_min=&depth_max=&hanging_height_min=&hanging_height_max=&diameter_min=&diameter_max=&page=2

Selector for results remains same all the time:

 id>1, limit=20, template=product, vendor=1087|1212 
Link to comment
Share on other sites

The biggest issue that I can see here is that you don't have page numbers enabled for your template. ProcessWire putting in the "page=2" is a signal of that. So before you do anything else, go and enable page numbers by editing your 'search' template–you'll see the option to enable page numbers on the URLs tab.

When it comes to dealing with your 'vendor' field, I recommend whitelisting it to a string in whatever format you want to extract it. For instance, maybe you want to use commas as a separator rather than pipes. You can whitelist it like this: 

$input->whitelist('vendor', implode(',', $vendors)); // if vendors is an array
$input->whitelist('vendor', str_replace('|', ',', $vendors)); // if vendors is a PageArray

Though you could certainly stick with "|" pipes if you preferred. But what I don't want to see you do is bundle that right from $input->get->vendor into a selector without validating it first. So switching to another separator makes that intention a little more clear. For instance, your form processor might capture and sanitize the vendor variable like this:

if($input->get->vendor) {
  if(is_array($input->get->vendor)) {
    // array from form submission
    $dirty = $input->get->vendor; 
  } else {
    // convert from your CSV string to array
    $dirty = explode(',', $input->get->vendor); 
  }
  $vendor = array();
  foreach($dirty as $id) $vendor[] = (int) $id; // sanitize to INTs
  $vendor = implode('|', $vendor); // convert to 123|456|789 string, ready for selector
} else {
  $vendor = '';
}

 
  • Like 1
Link to comment
Share on other sites

Thank you very plenty Ryan!

You're absolutely right - I made such a rookie mistake and didn't have page numbers enabled from template setup. Once I did it paging started working like excepted. Sorry about that.

Right now I have function that makes selector string for PW from post or get data and I have this excactly problem with PW page field values that it can be either array or string, with values separated by plus sing or empty space. If I just whitelist data like you suggest, I wouldn't have to do all checking and exploding at all. If I got this right..

Will test it later since it's my birthday and midsummer festival here in Finland so God Bless PW and hyvää juhannusta to everybody!

Link to comment
Share on other sites

Happy Birthday Roope! 

I personally don't like having arrays in GET variables (they are overly verbose and make ugly URLs). :) But if you want the MarkupPagerNav to keep arrays in their native GET variable state, you can tell it to by using the 'arrayToCSV' option and setting it to false. 

echo $mypages->renderPager(array('arrayToCSV' => false)); 
  • Like 1
Link to comment
Share on other sites

Thanks Ryan!

Man I was struggling with this but once I got the logic everything went smoothly.

I totally agree with what you said about arrays in GET vars. Now after form submission they are really ugly since it's submitted as is. Things get better when you move to different pages.

Maybe I should send form by jQuery so I could make prettier urls by default or how would you do it?

I did GET var whitelisting like this - pretty much as you suggested:

<?php
// open new instance of our import module since
// it holds field names and types we can use for validation
$deco = new DecoImport();

// there's some get data
if ($input->get->count() > 0) {
   
   foreach ($input->get as $key => $value) {
      
      // skip undefined fields
      if (array_key_exists($key, $deco->fieldTypes)) {
         
         // skip empty values
         if (empty($value)) continue;
         
         // sanitize key
         $key = $sanitizer->selectorField($key);
         
         // sanitize value
         if ($deco->fieldTypes[$key] == 'page') {
            if (is_array($value)) $dirty = $value;
            else $dirty = explode("|", $value);
            $value = array();
            foreach($dirty as $id) $value[] = (int) $id; // sanitize to INTs
            $value = implode("|", $value);
         } else $value = $sanitizer->selectorValue($value);
         
         // whitelist data
         $input->whitelist($key, $value);
         
      }
   }
}
Link to comment
Share on other sites

Maybe I should send form by jQuery so I could make prettier urls by default or how would you do it?

The need to have arrays in GET vars honestly doesn't come up very often in my projects. Usually when I'm using arrays, it's with POSTs. But if you want to avoid the array appearance in your URLs, you could always solve it by intercepting the request and reconstructing it to have your desired style, i.e.

if(!empty($input->get->array_var)) {
  $csv = '';
  foreach($input->get->array_var as $value) $csv .= ((int) $value) . ",";
  $session->redirect("./?csv_var=$csv"); 
}

Is it worth the overhead? Probably not, and all GET variables are ugly to some extent. :) But just showing it's possible to do without going the javascript route. 

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...