Jump to content
Vigilante

What are the methods to sort/filter $pages query in front end?

Recommended Posts

This is a pretty typical thing. Open a page, it does a $pages query, finds 112 things and I list them on the page. There is pagination too, 20 per page.

I want a sort dropdown box so the visitor can change alpha sort or whatever other sorts and filters I eventually use.

My first thought is to just refresh the page with a url query like "page/?sort=az" and then adjust the query in the template code. But to do this, it will require a page refresh, which means the sort box goes back to its default, and not sure how it effects pagination.

If I do a page refresh, I'll have to keep the sort settings in the session or something, to make sure I always apply correct sort on page load.

But at the same time, I've already got the $pages array, it would be much nicer to shuffle it and update the page without a page refresh, rather than run the query over and over again.

But then again, the pagination buttons already cause page refreshes, so that is already happening anyway, unless I convert the pagination buttons to also be no-refresh somehow.

 

I figure this is a very common problem, to paginate results and give users a sorting/filtering option. What is the common methods for handling it? Session, url query, ajax? If I just add the sort to the url query, how do I make that work in the pagination links?

Share this post


Link to post
Share on other sites

The beauty of Processwire is that it doesn't predefine output of content, so there's no reason why you couldn't create a template that returns JSON and call it using an ajax request from the HTML template that you want to update.

It does mean two templates for one page, although using URL segments it might be possible to have a single template that can return either HTML or JSON depending on the value of the URL segment, although you could do that with parameters as well.

 

Share this post


Link to post
Share on other sites

Well, today you'd use lazy-loading techniques (load 20 items on load, and then 20 more with "show more" etc.), therefore eliminating the need for classic pagination, or show the current page-set in the URL.

With endless scrolling and pagination, you could try something like this: https://elkfox.github.io/Ajaxify/ 
Ajaxination - Normal pagination style but load the page without reloading, uses push states.

 

  • Like 1

Share this post


Link to post
Share on other sites
14 hours ago, dragan said:

Well, today you'd use lazy-loading techniques (load 20 items on load, and then 20 more with "show more" etc.), therefore eliminating the need for classic pagination, or show the current page-set in the URL.

With endless scrolling and pagination, you could try something like this: https://elkfox.github.io/Ajaxify/ 
Ajaxination - Normal pagination style but load the page without reloading, uses push states.

 

That's cool but seems to be a Shopify plugin.

I would prefer the endless click one to load more, but that does mean it's not so easy to bookmark or link to page 4 or 18. To come back to the page only to have to click 'more' 6 more times is annoying without very robust URL hashing techniques. It's overkill for this project.

So I'll stick to either classic page-refresh pagination, or an ajax based no-refresh pagination as long as the URL works for it.

Share this post


Link to post
Share on other sites
14 hours ago, Pixrael said:

you can use https://processwire.com/docs/tutorials/how-to-use-url-segments/ 

you will get page/a-z instead of page/?sort=az ..using this segments you can search, filter, sort the pages results and update too the "sort box" (select, radio buttons, tabs, any) by this value

I wonder if segments are the best in my case given that it could potentially have more than just alpha sort. 

Right now I'm only sorting a list of companies, so alpha sort is probably all I'll need. But on the same site will be a catalog of products, and of course that could have a dozen different sortable/filterable values. I don't want URLs like page/a-z/blue/under-100/newest/....  The classic URL properties would work best I think. Plus segments are not really hackable. In the above URL, what if they don't sort by under-100 and that part is missing? I would have to test every segment to figure out which filter it is, in what order. 

Share this post


Link to post
Share on other sites
On 11/30/2017 at 2:57 PM, Vigilante said:

My first thought is to just refresh the page with a url query like "page/?sort=az" and then adjust the query in the template code. But to do this, it will require a page refresh, which means the sort box goes back to its default, and not sure how it effects pagination.

The sort box will go back to the default/first option, unless you program some basic logic to make it selected.  Something like this should work:

<?php
$sort = $input->get->string('sort'); // sanitize url variable shorthand
?>

<select name="sort">
  <option value=""></option>
  <option value="title" <?php if($sort=="title"): ?>selected<?php endif; ?>>Title (Asc)</option>
  <option value="-title" <?php if($sort=="-title"): ?>selected<?php endif; ?>>Title (Desc)</option>
  <option value="price" <?php if($sort=="price"): ?>selected<?php endif; ?>>Price (Asc)</option>
  <option value="-price" <?php if($sort=="-price"): ?>selected<?php endif; ?>>Price (Desc)</option>
</select>

 

  • Like 1

Share this post


Link to post
Share on other sites
12 hours ago, Jonathan Lahijani said:

The sort box will go back to the default/first option, unless you program some basic logic to make it selected.  Something like this should work:

Yes, not sure why I didn't realize that before.

 

Well for now I'm doing full page refreshes, it's ok for this particular site, but I would like to explore the ajax no-refresh solutions that can keep URLs in tact and support back/forward actions.

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 Flashmaster82
      Hi, i need some help with the filtering based on the Skyscrapers demo/func. I´m not that great with php so be patient.
      My structure looks like this
      Youtube videos > Youtube channel > Video
      on the video template (youtube_channel_video) i have multiple drop down fields and other fields that i would like to filter on the front end. I also have other pages that need this functions with search/filter etc but with different filters.
       
      This is the code i have in my search-form.php. Right now i experimenting with the field/option (category) that every video have in their template. The first filter (youtube_channel) works but im trying to get the category filter to work.
      <div id='skyscraper-search' class='uk-panel uk-panel-box xuk-panel-box-primary uk-margin-bottom'> <h3 class='h3'>Youtube videos</h3> <form class='uk-form uk-form-stacked' method='get' action='<?php echo $config->urls->root?>search/'> <div class='row'> <label class='uk-form-label' for='search_keywords'>Keywords</label> <div class='uk-form-controls'> <input type='text' class='uk-form-width-large' name='keywords' id='search_keywords' value='<?php if($input->whitelist('keywords')) echo $sanitizer->entities($input->whitelist('keywords')); ?>' /> </div> </div> <div class='col-6'> <div class='row'> <label class='uk-form-label' for='youtube_channel'>Youtube channel</label> <div class='uk-form-controls'> <select id='youtube_channel' name='youtube_channel' class='uk-form-width-large'> <option value=''></option> <?php // generate the youtube_channel options, checking the whitelist to see if any are already selected foreach($pages->find("template=youtube_channel_page") as $youtube_channel) { $selected = $youtube_channel->name == $input->whitelist->youtube_channel ? " selected='selected' " : ''; echo "<option$selected value='{$youtube_channel->name}'>{$youtube_channel->title}</option>"; } ?> </select> </div> </div> </div> <div class='col-6'> <div class='row'> <label class='uk-form-label' for='category'>Category</label> <div class='uk-form-controls'> <select id='category' name='category' class='uk-form-width-large'> <option value=''></option> <?php // generate the category options, checking the whitelist to see if any are already selected foreach($pages->find("template=youtube_channel_video") as $category) { $selected = $category->youtube_video_category == $input->whitelist->youtube_video_category ? " selected='selected' " : ''; echo "<option$selected value='{$category->youtube_video_category}'>{$category->youtube_video_category->title}</option>"; } ?> </select> </div> </div> </div> <div class='uk-margin-top'> <button type='submit' id='search_submit' class='uk-button uk-button-primary' name='submit' value='1'> <i class='uk-icon-search'></i> Search </button> </div> </form> </div>  
      This is my search.php
      <?php namespace ProcessWire; $selector = ''; $summary = array( "title" => "", "youtube_channel" => "", "category" => "", "country" => "", ); if($input->get('youtube_channel')) { $youtube_channelName = $sanitizer->pageName($input->get('youtube_channel')); $youtube_channel = pages("/youtube-videos/$youtube_channelName/"); if($youtube_channel->id) { $selector .= "parent=$youtube_channel, "; $summary['youtube_channel'] = $youtube_channel->title; $input->whitelist('youtube_channel', $youtube_channel->name); } } foreach(array('category') as $key) { if(!$value = $input->get($key)) continue; else { $value = (int) $value; $selector .= "$key=$value, "; $summary[$key] = $value; $input->whitelist($key, $value); } } if($input->get('keywords')) { $value = $sanitizer->selectorValue($input->get('keywords')); $selector .= "title|body|category%=$value, sort=title"; $summary["keywords"] = $sanitizer->entities($value); $input->whitelist('keywords', $value); } $videos = findSkyscrapers($selector); $browserTitle = 'Youtube video search - '; foreach($summary as $key => $value) { if($value) { $key = ucfirst($key); $browserTitle .= ucfirst($key) . ": $value, "; } else { unset($summary[$key]); } } region('browserTitle', rtrim($browserTitle, ', ')); region('content', files()->render('./includes/search-summary.php', array('items' => $summary)) . renderSkyscraperList($videos) );  
      This is my skyscraper-list-item.php file
       
      <?php echo " <div class='col-12 col-sm-12 col-md-6 col-lg-6 col-xl-4 col-xxl-4 col-xxxl-4 bmar10'> <div class='youtube_search_holder'> <a data-fancybox data-autoclose='true' data-width='1500' data-height='844' data-height='360' href='{$skyscraper->youtube}autoplay=1'> <div class='youtube_thumbnail_placeholder'><img src='{$skyscraper->youtube_thumbnail->url}' class='youtube_thumbnail_image w-100'> <div class='playicon'></div></div></a> <div class='youtube_search_thumbnail_content'> <div class='h6 text-uppercase green tmar3 title'><a href='{$skyscraper->parent->channel_url}' target='_blank' title='{$skyscraper->parent->title}'>{$skyscraper->parent->title}</a></div><div class='text-uppercase white h3 limit'><a href='{$skyscraper->youtube}' data-fancybox data-width='1500' data-height='844' data-height='360'>{$skyscraper->title}</a></div> <div class='h5 text-uppercase gray date'>{$skyscraper->youtube_video_publishdate}</div> <span class='white h7'> {$skyscraper->youtube_video_category->title} {$skyscraper->countries->title} {$skyscraper->competition->title} {$skyscraper->competition->parent->parent->title} {$skyscraper->armwrestler_competition_gender->title} {$skyscraper->armwrestler_arm->title} {$skyscraper->armwrestler_age_category->title} {$skyscraper->competition_weight_class->title} {$skyscraper->competition_video_match->title} {$skyscraper->videotags} </span> </div></div></div> "; ?> This is the front end right now (no styling 🙂

      In the category filter, right now there is multiple categories with the same name, i would also like to restrict it to just one result per category.
      Please help!
    • By Bacelo
      Hi there,
      I have a bit of trouble on filtering correctly some event pages by some selectors...
      I do have the following 2 date fields:
      - start date (fieldname = date)
      - end date (fieldname = enddate)

      Some events are a single day event (only start date) - some are a multi day event (end date).
      Past single day events should not show up.
      Current multi day events should show up (even if start day is in the past, but end date is future).
      So I have the following selector:
      if ($standort == '') { $termine = $page->children("sort=date, limit=10, (date>=today, enddate=''), (enddate>=today)"); } else { $termine = $page->children( "(standort_reference~=$standort), (standort_alle=1), (date>=today, enddate=''), (enddate>=today), sort=date, limit=10"); } This selector
      $termine = $page->children("sort=date, limit=10, (date>=today, enddate=''), (enddate>=today)"); works fine, but the follwing does not work (all past entries are also shown):
      $termine = $page->children( "(standort_reference~=$standort), (standort_alle=1), (date>=today, enddate=''), (enddate>=today), sort=date, limit=10"); I have no clue what I'm missing - any ideas?
    • By opalepatrick
      Hi, trying to order pages by modified date, date. I can do 'sort=-date_modified, sort=-date' but that will always put the modified date first regardless of actual date order. I just want to coalesce the two fields and sort. Any ideas would be appreciated.
    • By Moritz Both
      Greetings,
      when I give users the user-admin-* permission to administer users who have a certain role, they can indeed see and edit those users. However the filter / column panel does not show in the admin interface. How can I enable the filter functionality for user-admin-* members?
      ProcessWire 3.0.123
      Moritz
    • By louisstephens
      I have done a bit of searching, but I can not seem to find an actual answer. I have a list of services as child pages under "Services". I can output the services just fine, but I cant wrap my head around how to group them "alphabetically" like:
      Services A - Service "A" 1 - Service "A" 2 - Service "A" 3 B - Service "B" 1 - Service "B" 2 - Service "B" 3 C - Service "C" 1 - Service "C" 2 - Service "C" 3 Has anyone achieved this type of functionality before?
×
×
  • Create New...