Jump to content

Search with merged PageArrays + pagination = not working


Go to solution Solved by isellsoap,

Recommended Posts

Hey there.
 
The pagination for my search isn’t working. I guess it has something to do with the merging of PageArrays beforehand. Take a look at the (simplified) search.php:

$out = "";

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

	$input->whitelist( "q", $q );

	$pa = new PageArray();
	$value = $pages->find( "title%=$q" );
	
	$pa->import( $pages->find( "template=abc, …|…|…=$value" ) );
	$pa->import( $pages->find( "template=abc, title%=$q" ) );

	$result = $pa->find( "start=0, limit=4" );
	$pagination = $result->renderPager();

	$count = count( $pa );

	if( $count ) {

		$out .= "<h2>Search results found</h2>";
		$out .= "<ul>";

		foreach( $result as $r ) {
			$out .= "<li>{$r->title}</li>";
		}

		$out .= "</ul>";
		$out .= $pagination;

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

include("./head.inc");

echo $out;

include("./foot.inc");

Pagination names are activated for the search template and the output of the pagination list is correct. When I go to "page2", "page3", etc. the result is always the very first 4 matches. Any help is appreciated, thanks!

p.s.: I have to do the merging because one time I search for page references to a page (the "…" in the code) and one time for the title of a page with the template "abc". (offtopic: if you know a better solution to this just let me know) :)

Link to post
Share on other sites

I ran into this too. See the code and explanation if the other post. Basicly you have to merge all $pages->find and include them again in a find. This feels very hacky (and potentially has issues with performance), so it would be preferred to use one $pages->find. 

$latestPosts = $pages->find("template=post, frontpage=1, max_date>=$today")->add($pages->find("template=post, frontpage=1, max_date=null"));

$pages->find("id=$latestPostsMaxDate, limit=3, sort=-created");
Link to post
Share on other sites

Pagination module doesn't work with in memory page arrays. Once you manipulate or merge arrays you operating in memory. Pager does need a single find db query to work. You'd need to create your own pager functions for in memory page arrays using the start and limit selectors.

  • Like 4
Link to post
Share on other sites
  • Solution

Ha, I did it!

Instead of 

$pa = new PageArray();
$value = $pages->find( "title%=$q" );
	
$pa->import( $pages->find( "template=abc, …|…|…=$value" ) );
$pa->import( $pages->find( "template=abc, title%=$q" ) );

I wrote this

$pa = $pages->find( "template=abc, bla1.title|bla2.title|bla3.title|…|title%=$q, limit=4" );

I don’t search for the page references but for the titles of the page references with ".title". Works like a charm.  :-)

  • Like 3
Link to post
Share on other sites

On a different note: I’d like to throw a 404 error when a page is reached where no content appears. E.g. pagination only goes until "page5" but when I type "page6" in the address bar it doesn’t throw an error. Can one of you reproduce this behaviour?

I tested it a bit further and apparently the pagination limit is 999. :-)

Link to post
Share on other sites
$value = $pages->find( "title%=$q" );
$pa->import( $pages->find( "template=abc, …|…|…=$value" ) );
$pa->import( $pages->find( "template=abc, title%=$q" ) );

What should that do? You have to explaing a little more for a short minded like me. :)

I have an example that shows how to construct your own pager using the PW PagerNav class:

// include paginator class
require_once($config->paths->MarkupPagerNav . "PagerNav.php");

$pa = new PageArray();
$res1 = $pages->find("template=xyz, title%=space");
$res2 = $pages->find("template=abc, title%=hal");
$pa->import($res1);
$pa->import($res2);

// config paginator
$baseUrl = $page->url;
$limit = 4;
$start = ($input->pageNum - 1) * $limit;
$total = $pa->getTotal();
$pagerNav = new PagerNav($total, $limit, $input->pageNum);
$pager = $pagerNav->getPager();

// construct paginator markup
foreach($pager as $link) {
    if($link->pageNum == $input->pageNum) $class .= "on";
    if($link->type == "separator") $item = '…';
        else $item = "<a class='$class' href='{$baseUrl}page{$link->pageNum}/'>$link->label</a>";
    $pagerMarkup .= "<li>$item</li>";
}
// output paginator markup
echo "<ul class='pager'>" . $pagerMarkup . "</ul>";

echo "total: $total<br/>";
echo "start: $start<br/>";
echo "limit: $limit<br/>";

echo "<ul>";
foreach($pa->find("start=$start, limit=$limit") as $p){
    echo "<li>$p->title</li>";
}
echo "</ul>";
 

Also in my ever growing gist examples https://gist.github.com/somatonic/5420536

  • Like 5
Link to post
Share on other sites

On a different note: I’d like to throw a 404 error when a page is reached where no content appears. E.g. pagination only goes until "page5" but when I type "page6" in the address bar it doesn’t throw an error. Can one of you reproduce this behaviour?

I tested it a bit further and apparently the pagination limit is 999. :-)

Yeah that normal and expected behaviour. And who would enter page number manually anyway?

Edit: ah, to manually call a 404 you do

throw new Wire404Exception();
Link to post
Share on other sites

Yeah that normal and expected behaviour. And who would enter page number manually anyway?

I guess it‘s just a matter of principle. Why would I want a page that doesn’t make sense at all but doesn’t throw an error? Better to throw an error. Do you know how to get the number of the last page generated in a pagination?

What should that do? You have to explaing a little more for a short minded like me. :)

Like I wrote in the starting post:

p.s.: I have to do the merging because one time I search for page references to a page (the "…" in the code) and one time for the title of a page with the template "abc". (offtopic: if you know a better solution to this just let me know)

But I got a solution by now. :-)

Link to post
Share on other sites

Uhm? I totally agree, but that wasn’t what I meant. :-)

Like for instance: if the pagination has 5 pages, is there a way to get the last page of that pagination so that when someone tries to go to "page6" I can throw an 404 exception?

Link to post
Share on other sites

Well you test for if any results are found at all.What I do is check for if theres a result and show "no results found" or "out of range" and a link to first, or a redirect. Not sure its a good idea to show the a 404, like you also dont show one on a search result page if theres nothing found.

Link to post
Share on other sites
Like for instance: if the pagination has 5 pages, is there a way to get the last page of that pagination so that when someone tries to go to "page6" I can throw an 404 exception?

It's not a bad idea to throw a 404 in that condition. Though the only way someone could access such a page is by manually editing the address bar URL. But if you want to account for it, here's how you could do it:

$results = $pages->find("your selector goes here"); 
if($input->pageNum > 1 && !count($results)) throw new Wire404Exception();
Link to post
Share on other sites
  • 4 months later...

THen there's this $a->setTotal() $a->setLimit() $a->setStart() on page arrays we can use to configure built in MarkupPagerNav to work with merged page array in memory. Kind same as my above example but much simpler.

/**
* here is a example with using the built in pager
* we can use $a->setTotal($n) to configure page array to work with pager
*/

// create new page array for storing pages
$pa = new PageArray();
$res1 = $pages->find("template=mytemplate");
$res2 = $pages->find("template=house");

// import the found pages
$pa->import($res1);
$pa->import($res2);

// configuration for pagination needed
$limit = 10;
$total = $pa->count();
$start = ($input->pageNum-1)*$limit;

// example output with limited list we filter from the complete page array
foreach($pa->filter("sort=-created, limit=$limit, start=$start") as $p){
     echo "<p>$p->title</p>";
}

// page array let's you set the parameters for pagination manually
$pa->setLimit($limit);
$pa->setTotal($total);
$pa->setStart($start);

// now the renderPager() on the page array works as usual
echo $pa->renderPager();
 
Added this to the previous gist snippet here https://gist.github.com/somatonic/5420536#file-paginator_manual-php
  • Like 5
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 fruid
      $limit = 12; $start = $limit * ($input->pageNum() - 1); $allcasts = pages("template=cast"); $casts = $allcasts->find("has_parent=$page, sort=$sort"); $casts = sortOutEmpty($casts, $decider); $casts->setTotal($casts->count()); $casts->setStart($start); $casts->setLimit($limit); // just to test echo $casts->getStart(); // 0 or 12 or 24 or 30 respectively echo $casts->getLimit(); // 12 echo $casts->getTotal(); // 31 or whatever the total echo casts($casts); // never mind this, it's just for markup creation and works fine $pager->render($casts, $pagerOptions); // I store the name of a specific field as a string in a variable so I can dynamically sort out content of which that field is empty in the current language  function sortOutEmpty($items, $decider) {     $casts = new PaginatedArray;     foreach ($items as $item) :         if ($item->$decider != '') :             $casts->add($item);         endif;     endforeach;     return $casts; } I get the right number of pages in the pager. Pager works but the results never paginate.
      This pagination API is driving me nuts, it just doesn't work!
      I can't be the only one who's having issues with this, it's hard to find any topic where issues are discussed and the API-documentation is, as usual, very laconic.
      Thanks for help!
    • By fedeb
      Hi,
      I am trying to style the pager navigation bar based on a simple example I found on bootstrap:
      <nav aria-label="..."> <ul class="pagination"> <li class="page-item disabled"> <a class="page-link" href="#" tabindex="-1" aria-disabled="true">Previous</a> </li> <li class="page-item"><a class="page-link" href="#">1</a></li> <li class="page-item active" aria-current="page"> <a class="page-link" href="#">2</a> </li> <li class="page-item"><a class="page-link" href="#">3</a></li> <li class="page-item"> <a class="page-link" href="#">Next</a> </li> </ul> </nav> The code I am using is the following:
      <?php echo $entries->renderPager(array( 'nextItemLabel' => "Next", 'previousItemLabel' => "Prev", 'listMarkup' => "<ul class='pagination'>{out}</ul>", 'itemMarkup' => "<li class='page-item'>{out}</li>", 'linkMarkup' => "<a class='page-link' href='{url}'>{out}</a>", 'currentItemClass' => "page-item active", )); ?> which renders this result: the current page is not styled!

      If I run the original bootstrap example everything works fine, but not through the renderPager options. The problem seems trivial but since I am new to ProcessWire (also to web design) I cannot find it! My main reference is this one.
      Thanks in advance!
       
    • By donatas
      Hello,
      how would I do a multi-language website search with just a selector?
      I have many multi-lang fields and I want to do a search through all of them at once and through all of their language values.
      Is there a "selector way" of doing this? Maybe something like `title|title:de|title:it`? It seems I have seen this somewhere a long time ago but can't find in any documentation or forum search...
      Or the only way of doing it is by running separate searches for each language with output formatting off and then consolidating it all in one single results array?
      Because I still want to give users a result, even if it is in another language than current $user. Visitors mostly will be searching for specific terms that are very similar in all languages, but might be not used in one language version of a single page, for example. Or the user might not have switched language tohis prefered and did the search first, etc.. (many use cases in my situation)
      Example:
      $pages->find('title~='.$q) - maybe different operator is needed? /en/search/?q=visit = 1 results /it/search/?q=visit = 0 results Thanks for any advice!
    • By fruid
      I'm having and always have a hard time building PaginatedArrays, I never know where to put the "limit=24" selector so please enlighten me.
      Here's what I'm doing…
      $categories = $page->protable('start=0, limit=999999'); // this I need in order to retrieve the pages's "categories" and I don't know how to make use of $rows instead for that purpose because of this confusing limit-API $rows = $page->protable; // put ("limit=20") here? $custom = buildSelector($input, $rows); // this function returns an array of selectors depending on the user input $items = new PaginatedArray; // or here? // or here? $items->find("limit=20") // or like this? $items("limit=20") // or like this? $items = $items("limit=20") // or like this? $items = $items->find("limit=20") foreach ($rows as $r) : if ($custom->get('selector')->matches($r)) : $items->add($r); endif; endforeach; // or at this point? and then
      if ($items) { // or maybe somewhere here?     echo '<span class="grey">'.$items->getPaginationString(array(     'label' => 'entries',     'zeroLabel' => '0 entries', // 3.0.127+ only     'usePageNum' => false,     'count' => count($items),     'start' => $items->getStart(),     'limit' => count($items),     'total' => $items->getTotal()     )); and then of course…
      $pager = $modules->get("MarkupPagerNav"); echo '<div class="uk-flex uk-flex-center">'.$pager->render($items, $options).'</div>'; I'm out of ideas and confused cause it doesn't make sense to me either way.
      ____
      The buildSelector function above returns and array…
      $selected = new Selectors("$letter, $searchterm, $category"); $custom = new Wirearray; $custom->set('selector', $selected); $built->set('sort', $sort); return $custom; and each of the new selectors are basically strings ("category=whatever")
      Also, you cannot put the "sort=title" or whatever as a selector for the Selectors function (see above). Why, I know not.
      I don't know if that is the proper way but selecting kind of works now as opposed to many other ways I tried. Selectors always require a lot of trial and error, it seems to have a very sensitive API, always depends on double quotes, single quotes and how you concatenate.
      Thanks for help!
    • By picarica
      Hello si have this gallery, pretty good website, but yesterday client uploaded over 3000 images oto the site, and it cannot handle filtering them out and showing them at the same time , i wanted some simple pagination maybe infinite scrool or onclikc load whatever, but i cannot seem to implement infinite ajax scrool and any other JS methods, nut sure why i still got stuck at the next method, like there is not next page.
      so i wanted to implement PW method of paginating i wanted to use MarkupPagerNav
      so far i have  this code for outputting images
      $pa = $pages->find("template=basic-page|art_gallery, images.tags!=''"); /* $pa = $pages->find("has_parent!=2,id!=2|7,status<".Page::statusTrash.",include=all"); */ echo "<div class='js-filter' id='gal' >"; /* row gtr-50 gtr-uniform */ $frame = $pages->get('/settings/')->watermark; foreach ($pa as $p) { foreach($p->images as $image) { if(!$image->hasTag("act")) { $options = array('quality' => 80, 'upscaling' => true, 'cropping' => 'north', 'sharpening'=>'medium'); $large = $image->size(1200, 0, $options); $wmImage = $large->pim2Load('wm1', ['quality'=>80, 'upscaling' => true, 'sharpening'=>'medium', 'defaultGamma'=>-1])->watermarkLogo($frame, $position='se',$padding=1.5)->pimSave(); /* zmazanie variacii, treba odpoznakovat ked sa menia nastavenie vyssie */ /* $image->pim2Load('wm1')->removePimVariations(); */ $thumb = $image->size(400, 300, $options); echo "<div class='$image->tags grid-item' style=''>"; echo "<span style='overflow:hidden;'class='image fit'>"; echo "<a class='hvr-reveal' href='$wmImage->url'>"; echo "<img uk-scrollspy='cls: uk-animation-fade; repeat: false' src='$thumb->url' alt='$image->tags'>"; echo "</a>"; echo "</span>"; echo "</div>"; } else { $options = array('quality' => 80, 'upscaling' => true, 'cropping' => 'north', 'sharpening'=>'medium'); $large = $image->size(1200, 0, $options); $wmImage = $large->pim2Load('wm2', ['quality'=>80, 'upscaling' => true, 'sharpening'=>'medium', 'defaultGamma'=>-1])->pixelate(25)->smooth(255)->watermarkLogo($frame, $position='se',$padding=1.5)->pimSave(); /* zmazanie variacii, treba odpoznakovat ked sa menia nastavenie vyssie */ /* $image->pim2Load('wm2')->removePimVariations(); */ $thumb = $image->size(400, 300, $options); echo "<div class='$image->tags blur grid-item' style=''>"; echo "<span style='overflow:hidden;'class='image fit'>"; echo "<a class='hvr-reveal' href='$wmImage->url'>"; echo "<img uk-scrollspy='cls: uk-animation-fade; repeat: false' src='$thumb->url' alt='$image->tags'><span>18+</span>"; /* <span>BY OPENING THIS IMAGE YOU CONSET THAT YOU'RE 18 YEARS OR OLDER</span> text copyraightova,y dat vedla obrazky potom */ echo "</a>"; echo "</span>"; echo "</div>"; } } }; to put it  simply, it first searches for sites, and then outputs all images from those sites, pretty simple, it also uses watermarking and uikit filtering
      i have filtering done like this
      $num = 1; echo "<ul class='uk-subnav uk-subnav-pill'>"; foreach(array_unique($alltags) as $key => $tag) { echo"<li uk-filter-control='filter: .$tag;group: $num' class='butt$num' uk-toggle='target: .butt$num ; animation: uk-animation-fade; queued: true'><a href='#'>$tag</a></li>"; echo"<li uk-filter-control='group: $num' class='butt$num active' aria-hidden='true' hidden='' uk-toggle='target: .butt$num; animation: uk-animation-fade'><a href='#'>remove - $tag</a></li>"; $num++; } echo "</ul>"; simple, but i have NO idea how to implement pagination, just because it seems to work that it like find all images, and stores with limit, and then just paginates them, but i cannot apply this method in my code.
      any idea how to make any JS inifite scroll work ? or just how to make this work ? with my setup, or with some modifications, it just have to work as is now
×
×
  • Create New...