Jump to content

Filter results of selector using select/checkbox?


antknight
 Share

Recommended Posts

OK guys this one has me thinking.

I have an events section which is where all events site-wide are put. I have given people the ability to assign their event to a particular section of the site using pageListSelect.

On the front end, the events page lists all events regardless of the section they have been assigned to:

<?php
      $today = strtotime(date("Y-m-d H:i"));
      $events = $page->find("template=event, event_start>$today, sort=event_start, limit=10"); 
      $pagination = $events->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>"));
      echo "<ul class='list'>";
      foreach($events as $event) {
        echo "<li class='list-item'>";
        echo "<h5><a href='{$event->url}'>{$event->title}</a></h5>";
        echo "<em>{$event->event_start}</em>";
      }      
      echo "</ul>";
      echo $pagination;

While on the section page it only lists events assigned to that section:

<?php
      echo eventList($pages->find("template=event, section={$page}, event_start>=$today, sort=event_start, limit=5"));

What I would like is to give people the ability to filter the list of events on the events page to choose just the events assigned to the section they want to look at. I imagine the functionality to be similar to the modules section on the processwire.com site whereby you can select an author and the page reloads to show only modules by that author.

Can I use a select drop-down and have it update the variable and reload the page? Thanks in advance.

post-821-0-81186500-1368792990_thumb.png

Link to comment
Share on other sites

The modules page works in a simpler way. For what I understand, all it does is to store the url of each authors page as the value of each select, and link to it with javascript when that author is selected.

Link to comment
Share on other sites

Just build a select form with your section pages in it and send the page id over GET:

<select name="section">
<?php
  foreach($pages->find('template=section') as $s) {
    echo "<option value='{$s->id}'>{$s->title}</option>";
  }
?>
</select>

Then in the template where you display the events, check if the user has chosen a category

if ($input->get->section) {
  $section = (int) $input->get->section;
  // Add this to your selector string
  $selector .= ", section={$section}";
  // To make the pagination work, add the section get variable to the whitelist
  $input->whitelist('section', $section);
}
  • Like 4
Link to comment
Share on other sites

This is some code I have been using to generate filter options based on the page fields in a template. I cleaned it up a little, but there is still some stuff in there that is specific to me regarding formatting/output, but might be a useful start for someone. Basically it gets all the fields in the template for the current page (except those you choose to exclude) and builds a filtering form with all of them. You will likely want to ditch the text search field. The reason I excluded body and then added it back in like this was for labeling and ordering changes, but this could be done other, less lazy, ways. This is a POST, rather than GET form. It could be adapted, but the GET that is returned by InputfieldForm is not clean.

One thing you'll obviously need to change is where I have the format_results function.

I am also using HTMLKickstart, so the output of the filter side div and the no results message won't look great without it.

<?php

$filter_formcode = '';

if($input->post->filter_save) {
    // Search selector builder
    $search_string = '';
    $current_field = '';

    foreach($input->post as $field_name => $field_result){

        if (is_array($field_result)){
            foreach($field_result as $f_value){

                if($current_field == $pages->get($f_value)->template){
                    $search_string .= '|' . (int)$f_value;
                }
                else{
                    $search_string .= ',' . $pages->get($f_value)->template . '=' . (int)$f_value;
                }
                $current_field = $pages->get($f_value)->template;

            }
        }
        else{ //This is only needed if you want the text search field which is an optional add on below
            if($field_name == 'body' && $field_result != ''){
                $search_string .= $field_name . '%=' . $field_result;
            }
        }
    }

    $search_string = trim($search_string,',');
}
else{
    $search_string = '';
}

$filter_form_page = new Page();

$filter_form_page->template = $page->child()->template;

// Populate with the names of the fields you want to exclude OR include (see instructions below)
// Leave empty to output all the fields
$myfields = array('id','title','body');

$form = $modules->get('InputfieldForm');

$fields = $filter_form_page->getInputfields();

//This adds a text search field if you want it
$field = $this->modules->get('InputfieldText');
$field->attr('id', 'Inputfield_body');
$field->attr('name', 'body');
$field->label = "Search term";
$form->append($field);


// If array is not empty use it to filter the fields
if ($myfields){
    foreach($fields as $f){
        // Output all the fields minus the ones listed in the $myfields array
        // Instead, to output only the fields that are in the array, remove the (!) from the condition
        if (!in_array($f->name, $myfields)){
            $f->value = '';
            $form->append($f);
        }

    }
}
else{ // Else, include all the fields
    $form->append($fields);
}

// Add find button
$field = $this->modules->get('InputfieldSubmit');
$field->attr('id+name', 'filter_save');
$field->attr('value', 'Find');
$field->label = "find";
$form->append($field);


// Process the form
if($input->post->filter_save) {
    $form->processInput($input->post);
}

// render out form
$filter_formcode .= $form->render();

$filter_formcode = strip_selected_tags_by_id_or_class('InputfieldPageAdd', $filter_formcode); //Strip out the option to add new item to page field (if this has been allowed through admin) even though it only appears to certain admin users

$filter_formcode .= '<script>
 $(document).ready(function() {
    $(\'select\').css({"max-width":"270px"});
    $(\'li\').removeClass("InputfieldColumnWidth");
    $(\'li\').removeClass("InputfieldColumnWidthFirst");
    $(\'li\').attr("style", "");
 });
</script>'; //set select to max width and remove floating selects so each one on own line


$out = '';

$out .= '<div class="col_8">';

$filter_results = $page->children($search_string);

if(count($filter_results)==0){
    $out .= '<div class="notice error"><i class="icon-remove-sign icon-large"></i> Sorry, there are no results, please change your search parameters.<a href="#close" class="icon-remove"></a></div>';
}
else{
    foreach($filter_results as $result){
        $out .= format_results($result);
    }
}

$out .= '</div>

<div class="col_4">

    <h6>Find a Book</h6>
    <p>Leave filter options blank for all</p>

    ' . $filter_formcode . 

'</div>';

echo $out;

EDIT: See this post for a cleaner version: http://processwire.com/talk/topic/3583-filter-results-of-selector-using-selectcheckbox/?p=36182

Edited by adrian
  • Like 1
Link to comment
Share on other sites

Thanks - I should mention that this really comes in useful when you have lots of different categories assigned. You might want to change the generation of the $search_string variable depending on your needs. At the moment the different filters search such they match a resource with any of the selected options (ie OR), but between filters, the search works as AND. Hopefully that makes sense - have a play and you'll see what it does. Pretty easy to change this logic if needed.

Link to comment
Share on other sites

  • 2 weeks later...

hi Adrian i folow your example code but when i paste it in my template i get this error

Error:     Exception: New page '/real-estate/' must be saved before files
can be accessed from it (in
C:\wamp\www\real-estate\wire\core\PagefilesManager.php line 167)
#0 C:\wamp\www\real-estate\wire\core\PagefilesManager.php(136): PagefilesManager->path()
#1 C:\wamp\www\real-estate\wire\core\PagefilesManager.php(48): PagefilesManager->createPath()

and this is repeat until #6

i dont have page '/real-estate/' or template

any idea what i di wrong?? thank you!

Link to comment
Share on other sites

Hey Pitbull,

Sorry it's not working for you. A couple of things I can think of:

1. Does your current page have a child? The code above relies on that to set the template and therefore generate the filter fields.

2. Perhaps try replacing: $filter_form_page = new Page(); with $filter_form_page = $page;

Let me know if that helps at all.

Link to comment
Share on other sites

thank you Andrian! i tried it and now i get:

Internal Server Error The server encountered an internal error or misconfiguration and was unable to complete your request. Error has been logged.

and the log file is:

2013-05-29 01:36:15    admin    http://localhost/real-estate/    Error:     Exception: New page '/real-estate/' must be saved before files can be accessed from it (in C:\wamp\www\real-estate\wire\core\PagefilesManager.php line 167)  #0

repated untilunti l#6

1. Does your current page have a child? YES

i am think maybe is because of subdomain http://localhost/real-estate/

what do you think?

Link to comment
Share on other sites

I don't think it is a subdomain issue.

Did you make the change I suggested in 2 above?

Does this error happen when loading the page, or not until you've chosen some filter options and clicked find?

Link to comment
Share on other sites

I think this method to create a page with a template just to get the fields is not needed and I think if you have file field it will throw that error.

I think it's better you get them just using

$fields = $templates->get("mytempl")->fields;
Link to comment
Share on other sites

Soma,

Thanks for chiming in. Good point - actually not sure now why I went that route. However I do think it would be good to be able to make this code more portable so you don't have to specify the template. I actually use the above as an .inc in many templates and it works great, although obviously can be improved.

Pitbull - Soma is suggesting to eliminate these lines:

$filter_form_page = new Page();
$filter_form_page->template = $page->child()->template;

and replace:

$fields = $filter_form_page->getInputfields();

with:

$fields = $templates->get("mytempl")->fields;

I am not sure if that will work the same way, but maybe it will :)

I would still like to see something though that grabs the appropriate fields based on the template of the child of the current page. At least that is what I need to make it work for my purposes since it is the child pages that contain all the content we want to filter down to. Untested, but maybe something like:

$fields = $page->child()->fields;
Link to comment
Share on other sites

Actually that creates an error, but this works:

$fields = $page->child()->getInputfields();

Pitbull, I think if you remove those two lines I mention in #15 above and then use this line for getting the fields it should hopefully work for you. Let us know how it goes and I'll amend the initial code example.

Link to comment
Share on other sites

thank you Guys! now i get this error Error:     

Call to a member function getInputfields() on a non-object (line 63 of C:\wamp\www\real-estate\site\templates\properties-listing.php)

my pages tree is:

Property Sales                               (template used is: properties-type-listing.php)
  ---Houses                                     (template used is: properties-categorie-listing.php)
  ---Apartments                              (template used is: properties-categorie-listing.php)
  ---Villas                                        (template used is: properties-categorie-listing.php)
      -----Luxury Stone Villa 455tm    (template used is: property-detail.php)

the search code i used it in template properties-listing.php is this

<?php

$filter_formcode = '';

if($input->post->filter_save) {
    // Search selector builder
    $search_string = '';
    $current_field = '';

    foreach($input->post as $field_name => $field_result){

        if (is_array($field_result)){
            foreach($field_result as $f_value){

                if($current_field == $pages->get($f_value)->template){
                    $search_string .= '|' . (int)$f_value;
                }
                else{
                    $search_string .= ',' . $pages->get($f_value)->template . '=' . (int)$f_value;
                }
                $current_field = $pages->get($f_value)->template;

            }
        }
        else{ //This is only needed if you want the text search field which is an optional add on below
            if($field_name == 'body' && $field_result != ''){
                $search_string .= $field_name . '%=' . $field_result;
            }
        }
    }

    $search_string = trim($search_string,',');
}
else{
    $search_string = '';
}

$fields = $page->child()->getInputfields();

// Populate with the names of the fields you want to exclude OR include (see instructions below)
// Leave empty to output all the fields
$myfields = array('id','title','body');

$form = $modules->get('InputfieldForm');

$fields = $filter_form_page->getInputfields();

//This adds a text search field if you want it
$field = $this->modules->get('InputfieldText');
$field->attr('id', 'Inputfield_body');
$field->attr('name', 'body');
$field->label = "Search term";
$form->append($field);


// If array is not empty use it to filter the fields
if ($myfields){
    foreach($fields as $f){
        // Output all the fields minus the ones listed in the $myfields array
        // Instead, to output only the fields that are in the array, remove the (!) from the condition
        if (!in_array($f->name, $myfields)){
            $f->value = '';
            $form->append($f);
        }

    }
}
else{ // Else, include all the fields
    $form->append($fields);
}

// Add find button
$field = $this->modules->get('InputfieldSubmit');
$field->attr('id+name', 'filter_save');
$field->attr('value', 'Find');
$field->label = "find";
$form->append($field);


// Process the form
if($input->post->filter_save) {
    $form->processInput($input->post);
}

// render out form
$filter_formcode .= $form->render();

$filter_formcode = strip_selected_tags_by_id_or_class('InputfieldPageAdd', $filter_formcode); //Strip out the option to add new item to page field (if this has been allowed through admin) even though it only appears to certain admin users

$filter_formcode .= '<script>
 $(document).ready(function() {
    $(\'select\').css({"max-width":"270px"});
    $(\'li\').removeClass("InputfieldColumnWidth");
    $(\'li\').removeClass("InputfieldColumnWidthFirst");
    $(\'li\').attr("style", "");
 });
</script>'; //set select to max width and remove floating selects so each one on own line


$out = '';

$out .= '<div class="col_8">';

$filter_results = $page->children($search_string);

if(count($filter_results)==0){
    $out .= '<div class="notice error"><i class="icon-remove-sign icon-large"></i> Sorry, there are no results, please change your search parameters.<a href="#close" class="icon-remove"></a></div>';
}
else{
    foreach($filter_results as $result){
        $out .= format_results($result);
    }
}

$out .= '</div>

<div class="col_4">

    <h6>Find a Book</h6>
    <p>Leave filter options blank for all</p>

    ' . $filter_formcode . 

'</div>';

echo $out;
?>

my property-detail.php template fields are that i want to serch is:

Property_Title

Land_Area

Living_Space

Price

Link to comment
Share on other sites

Try replacing:

$fields = $page->child()->template->fields;

with:

$fields = $page->child()->getInputfields();

It's working great for me and no need for all that new page stuff - thanks Soma.

Are you getting the same error, or a different one?



EDIT: Is properties-listing.php the template for the parent page or the child pages. The filter code as I set it up needs to be in the parent template. Does that make sense?

Link to comment
Share on other sites

Catchable fatal error: Argument 1 passed to
InputfieldWrapper::append() must be an instance of Inputfield, instance
of Field given, called in
/xxx/site/templates/filter_form.inc on line 101 and
defined in /xxx/wire/core/InputfieldWrapper.php on line 159

Link to comment
Share on other sites

Actually I think with:

$page->child()->getInputfields() you get the inputfields from that page with the values for editing. I get errors when using it in outputformatting on...

to get the fields you simply do:

$page->template->fields;
Link to comment
Share on other sites

Just to clarify my setup, the fields are all ASM Page fields and I want the values so the user can choose the values to filter from (hence the need for getInputfields()). Wish I could show you guys the working version of this, but it's not live yet.

Link to comment
Share on other sites

Page field dont need values to function and show the list according to the field settings. The value I mean is which is selected.

But then your child page is empty then that could work out.

Link to comment
Share on other sites

Ahh I think I missed that you render out a form with those fields. Thats whats missing in my test.

So my code throws the error when rendering ..

Ok but pitbulls problem is that he seems to have image or file fields which throws the error. It says even what is wrong.

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...