Jump to content

Search form drop down category/child page output support


RyanJ
 Share

Recommended Posts

Need some help with these this filter if anyone can point me in the right direction. I altered the below from the skyscraper profile to meet my needs, but can not seem to get it to work in my case. The actual drop down on the form works properly displaying all locations, but I cant get the output to search what is selected. What am I missing?

I am trying to grab all the employees when a specific location is selected.

My structure is

root
Location 1                     
  - employee                         
    -- jane doe

    -- jone doe

Location 2

  -employee

   -- jane smith

form drop down for child page

<select name="location">
           <option value="">any</option>
            <?php
         foreach($pages->get("/")->children("id!=10") as $location) {
              $selected = $location->title == $input->whitelist->location ? " selected='selected' " : '';
              echo "<option$selected value='{$location->id}'>{$location->title}</option>";
            } ?>
</select>

output for child page

if($input->get->location) {
$location = $pages->get("template=location" . $sanitizer->pageName($input->get->location));
if($location->id) {
  $selector .= "location={$location}, ";
  $input->whitelist('location', $location->name);
}}
Edited by RJay
Link to comment
Share on other sites

I'm not sure I get the context right, but there are some things that don't look right to me.

Here you've got a malformed selector:

$location = $pages->get("template=location" . $sanitizer->pageName($input->get->location));

Should be:

$location = $pages->get("template=location, name=" . $sanitizer->pageName($input->get->location));

This seems to have no function (but could of course be in use outside the provided clip):

$selector .= "location={$location}, ";

And the dropdown should use name as a value instead of title to match the search and whitelisting (and to be unique), like this:

$selected = $location->name == $input->whitelist->location ? " selected='selected' " : '';
echo "<option$selected value='{$location->name}'>{$location->title}</option>";

Maybe these will help? I didn't take a look at the original by Ryan so I may just be missing something obvious here.

  • Like 1
Link to comment
Share on other sites

Hi Nik,

Thanks for the response and advise. The $selector is used in a function to find the results. After reading a whole lot, I saw that Ryan recommended using integers, so I replaced $location->name with $location->id.

I think the problem I am having is that I have to grab each location. In my search form, I want to just grab all results pertaining to whichever location is selected.. I have updated the above code and the structure. Maybe it will help explain a little better. Thanks again. 

Link to comment
Share on other sites

I think I need version control to keep up with the changes in your post. ;)

It seems I'm even more lost now than I was before. Which template file are those snippets from exactly, which "child page" are you referring to? And what are the templates assigned to the pages in your structure? Which template has field 'location' you're using in $selector? What else goes into $selector? Can't see the whole picture here...

At least you've got a nice mess there as you're using id, name and title like they were the same. What I mean is

  1. there's page id as the value for an option in the dropdown
  2. you're whitelisting page name as location
  3. check for previously chosen item uses page title

Those three should be done using the same property, preferably id or name.

  • Like 1
Link to comment
Share on other sites

haha, Yes, version control would be nice and a mess is kind words for what I have and I do sincerely appreciate your patience. This is day 4 of figuring out my mess.  

 
1. there's page id as the value for an option in the dropdown
2. you're whitelisting page name as location
3. check for previously chosen item uses page title

I fixed this part as I realized it was not correct by any means and I'm a silly person for not realizing it.

The first snippet is from searchform.php which contains the drop down. So in the drop down are the options

"location 1"

"location 2"

The second is from search.php and is supposedly my logic to process the selected location.

My goal is in my search results is to output all employees that are children of its selected location. 

Location 1 

Location 2

are both assigned the same template named "location"

Each employee is assigned a template named "employee"

The employee template does not have a field of location, they are just children of their location. Here is a post of my complete structure. It may help you understand my logic and once again, I appreciate your time as I am trying to learn pw, so I dove in deep.

Link to comment
Share on other sites

OK, now we're back on track I think. :)
 
So, you've lined up those three things to use page id's? Then your search form would be like this:

<select name="location">
    <option value="">any</option>
    <?php
    foreach($pages->get("/")->children("id!=10") as $location) {
        $selected = $location->id == $input->whitelist->location ? " selected='selected' " : '';
        echo "<option$selected value='{$location->id}'>{$location->title}</option>";
    }
    ?>
</select> 

And now you could use something like this in search.php:

# has a location been selected?
if($input->get->location) {
    # sanitize (page id is always an integer)
    # no need to fetch the actual page as the search selector restricts results to employees
    $location = (int)$input->get->location;
    # employees have template 'employee' and their parent page is the chosen location
    $selector .= "parent={$location}, template=employee";
    # whitelist the sanitized value (and use from whitelist later on)
    $input->whitelist('location', $location);
}

Hope I didn't introduce any new errors there...

  • Like 2
Link to comment
Share on other sites

Hi Nik,

Definitely leaps and bounds from where I started, but I am getting no results found if a location is selected. The correct id's are showing in the url, so I am assuming it has something to do with the $selector maybe? Thank again for helping me out and cleaning up my mess :).

Looking at it further, I think because "Location 1" is not the actual parent of the list of employees, but "employee". Is there anyway to go one step down further? I guess I could just delete the employee container.

Edited by RJay
Link to comment
Share on other sites

Doh, I got that structure of yours wrong, sorry! So you're right, using parent wouldn't give the right results.

Yes, you could get rid of the container if there's no real need for one. But if that extra level is needed, you can change "parent" in the selector to "has_parent". Then the chosen location has to be one of the parents of the employee, but not the first one necessarily.

If it still doesn't work, try echoing $selector right before it's being used for finding the results so that we can see if there's still something wrong with it. And you do have $config->debug = true; in your site/config.php and no errors in site/assets/logs/errors.txt, right?

We'll get there, eventually. :D

Link to comment
Share on other sites

Hi Nik,

ahhhhh, you are a kind soul and life saver! :)    Yes, I have debug on and has_parent seems to work with no errors and although I only have two locations now the proper results are appearing. I did not see has_parent in the selectors cheat sheet? Any other selectors out there not on it? I cannot thank you enough for your help. I owe you BIG!

Link to comment
Share on other sites

Thanks, glad I could help you RJay! :)

I don't know why has_parent isn't in the cheatsheet (Soma/Ryan?) as it is mentioned in the API documentation (http://processwire.com/api/selectors/). There are one or two other selectors that are not mentioned in either of those I'm sure, but I think it's intentional as they're only for internal use for a reason or another. So everything you really need to know is documented ;).

Happy studying with ProcessWire and don't give up if you ever hit a wall. Ask away and someone will help you for sure. But do try and describe the context and what you're trying to achieve detailed enough and there will be a solution in way less than four days next time. :P

  • Like 1
Link to comment
Share on other sites

Hi Nik, 

I can not thank you enough. My first trip to Finland will be to buy you some beers or food or whatever. I will heed your advise and be sure I describe my problem thoroughly before I post it to be sure it is understood completely from others perspectives other then mine. I thought I had a good grasp on what I was trying to learn/achieve as this is just a mock site for me to learn from, but I was a tad bit over my head. 

I still have one other part of the form that I need to tackle, but I will attempt to achieve those results a few more days before asking for help. Thanks again and cheers!

  • Like 1
Link to comment
Share on other sites

Just a follow up question if I may. What logic would you recommend to only show the available selectors in the search form per location. For example

Location 1

  --employee

    --- Jane Doe

  --department

    --- Newbie

 -- year

   --- 2012

location 2

  --employee

  --- John Doe

 --department

  --- Newbie Trainer

 --year

   ---2010

Department children pages and year children pages are page fields and are both drop downs in the current search form. So when I am on the location 1 page, currently it shows all children of department and year from both locations.

Is it possible to only show the children of the location you are one. So if I am on the location 1 page, the search forms drop down would only show the Newbie department and the year 2012. 

If in location 2, the search form drop down would only show department Newbie Trainer and Year 2010. 

Hopefully I explained this well.  :undecided:

Link to comment
Share on other sites

Yes, explanation accepted :D.

OK, see above how the selector is formed to find the search results; there you're searching for employees under the chosen location. And now you need to search for department/year under current location (and list those as options in the dropdown). Anything familiar there? ;)

The biggest difference - the only one you haven't solved already - is chosen vs. current location. You do know about $page variable holding the page object of the current page, right? So what you need is a way to use the $page variable in your selector somehow.

Currently you're probably using something like $pages->find('template=department') to list options, correct? Now you need to add another part to that selector constraining the departments to your current location. As the same search form is used elsewhere as well (front page at least) you'd want that location constraint only when you actually are on a location page. Something like this should do the trick:

$departmentSelector = 'template=department';
# variable holding a page object in a string enclosed in double quotes is interpolated to id of the page
if($page->template == 'location') $departmentSelector .= ", parent=$page";
$departments = $pages->find($departmentSelector);

And same for years. Got it?

  • Like 1
Link to comment
Share on other sites

Hi Nik,

As you suggested, I am currently using this in searchform.php to pull in all of the departments in all locations. 

<?php 
    foreach($pages->find("template=department") as $department) {
    $selected = $department->id == $input->whitelist->department ? " selected='selected' " : '';
   echo "<option$selected value='{$department->id}'>{$department->title}</option>"; }
?>

I took your snippet and altered it to this but with no luck. I am not getting any results with it.

<select name="department">
  <option value="">Any</option>
     <?php
       $departmentSelector = 'template=department';
         if($page->template == 'location') $departmentSelector .= ", parent=$page";
         foreach($pages->find($departmentSelector) as $department) {
         $selected = $department->id == $input->whitelist->department ? " selected='selected' " : '';
         echo "<option$selected value='{$department->id}'>{$department->title}</option>"; }
      ?>
  </select>

I  was initially thinking of an if/ elseif statement or better a switch to check and see what location page the user was on and then just grab the locations department/year children, but If there are a lot of locations, this could be very time consuming and as always, thanks for educating us newbies :).

Link to comment
Share on other sites

Oops!... I Did It Again  :P

I somehow thought departments (and years) were direct children of locations, but there's this extra container there as well. So try changing parent to has_parent and it should work better.

Link to comment
Share on other sites

Hi Nik,

Strangely enough I had tried the has_parent last night after I learned it from your first lesson, but it did not work. I was either tired, delusional or thinking I misspelled location because it works perfect this morning.   :)

So to break down the code to make sure I understand it, 

$departmentSelector is grabbing all pages with the department template

the if is checking if the current page is using the template location and if so, it is grabbing that pages id and appending it to $departmentSelector?

You sir have excelled as my hero to now my Super Hero!

Link to comment
Share on other sites

Great, we're clearly making progress. Looks like you've understood it as well - and that's the ultimate goal when helping out. :)

Understanding selector formation is if not a necessity at least the key to unleashing the vast possibilities of ProcessWire. So to recap: $departmentSelector is initialized to a selector string that would match all the pages with template 'department'. Then, if current page has template 'location', the initial selector string is concatenated with another selector that would match all the pages having the current page as one of their parents. Comma separated selectors all have to match so that the whole selector matches (comma stands for 'and'). Thus with both of those selectors only pages with template 'department' that have the current page as one of their parents would match.

Still that selector string that has to be passed to a find() method to actually get the pages (or get() when only a single page is wanted). Using find() method from $pages object you're aiming at all the pages in your site that match the given selector string. But there are also other places where there's a find() method available. To restrict finding to a specific subtree you can first get the wanted root page and call find() for that page object. Or if you want to filter further a previously retrieved or formed PageArray, they also have a find() function. But do note that this one's different to the previous examples as the page objects are already in memory and the filtering happens there instead of the database.

But now I'm way off the original subject. I was supposed to describe things just a little bit deeper but got carried away... :P

Link to comment
Share on other sites

Hi Nik, I appreciate your detailed explanation and gain to absorb as much as possible, so please continue to get carried away. You answered a second question I had in my head but never asked. So the find() method gets pages and the get() gets a page? Again Sir, I cannot thank you enough. :)

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

×
×
  • Create New...