Erik Posted March 17, 2021 Share Posted March 17, 2021 I want to build a product catalog where products can be filtered by 5 attributes. It must be possible to filter on multiple attributes. e.g. size, weight. Now I am looking for the simplest way to do this in Processwire. Who will help me on my way? Link to comment Share on other sites More sharing options...
elabx Posted March 17, 2021 Share Posted March 17, 2021 What exactly do you need help with? The most common/straightforward way to do this is to grab and sanitize the GET variables from a form submission and use them to create a selector: <?php //Default selector to get ALL products $selector = "template=products"; // Get color variable and sanitize $color = $input->get->text('color'); if($color){ $selector = "template=products, color=$color"; } $products = $pages->find($selector); ?> <form action="."> <select name="color"> <option value="red">Red</option> </select> </form> <div class="products"> <?php // Render the products list foreach($products as $product){ echo "<div>....</div>" } ?> </div> Link to comment Share on other sites More sharing options...
Klenkes Posted March 17, 2021 Share Posted March 17, 2021 Something like here? https://www.historische-baustoffe-ostalb.de/baustoffe/tueren/haustueren/ Sorry, website only in german, but I could give you some tips to get you started. 1 Link to comment Share on other sites More sharing options...
rick Posted March 17, 2021 Share Posted March 17, 2021 52 minutes ago, Klenkes said: Something like here? https://www.historische-baustoffe-ostalb.de/baustoffe/tueren/haustueren/ Those are beautiful doors Link to comment Share on other sites More sharing options...
elabx Posted March 17, 2021 Share Posted March 17, 2021 54 minutes ago, Klenkes said: Something like here? https://www.historische-baustoffe-ostalb.de/baustoffe/tueren/haustueren/ Yep, pretty much like that! Link to comment Share on other sites More sharing options...
Klenkes Posted March 17, 2021 Share Posted March 17, 2021 1 hour ago, rick said: Those are beautiful doors And not just the doors. The guys have more than 1000 lamps of all the electrified ages ? They are clients of mine since 2004. The website design is a little bit outdated but the priority is to keep everything rolling... according to the owner ? 2 Link to comment Share on other sites More sharing options...
Erik Posted March 17, 2021 Author Share Posted March 17, 2021 3 hours ago, Klenkes said: Something like here? https://www.historische-baustoffe-ostalb.de/baustoffe/tueren/haustueren/ Sorry, website only in german, but I could give you some tips to get you started. That's what I'm looking for. Can you roughly indicate how you have set up this website in Processwire? Link to comment Share on other sites More sharing options...
elabx Posted March 17, 2021 Share Posted March 17, 2021 Well in this case I'd say each of your products would have a field per category. For example with the door's website: Max Price: Integer field DIN left or right: Select Options or Page Reference field (I'd use page reference) With glass: Checkbox field Width: Integer field Height: Integer field This would be template door, and child of a unique page with template doors. So in this scenario, since each product category has a different set of filters, I'd say each product has its own template, so you'd have templates: handles, door locks, door signs, accessories, each of them with its own set of fields. So you'd end up with a tree like: Products -- Doors --- Doors 1 --- Doors 2 -- Accesories --- Acc 1 --- Acc 2 Link to comment Share on other sites More sharing options...
Erik Posted March 18, 2021 Author Share Posted March 18, 2021 11 hours ago, elabx said: Well in this case I'd say each of your products would have a field per category. For example with the door's website: Max Price: Integer field DIN left or right: Select Options or Page Reference field (I'd use page reference) With glass: Checkbox field Width: Integer field Height: Integer field This would be template door, and child of a unique page with template doors. So in this scenario, since each product category has a different set of filters, I'd say each product has its own template, so you'd have templates: handles, door locks, door signs, accessories, each of them with its own set of fields. So you'd end up with a tree like: Products -- Doors --- Doors 1 --- Doors 2 -- Accesories --- Acc 1 --- Acc 2 Okay, I understand. But how do you filter on the front-end? I installed the skyscraper demo (https://demo.processwire.com/) to see how it works but find it too complex for what I want. Are there any other examples? Link to comment Share on other sites More sharing options...
Klenkes Posted March 18, 2021 Share Posted March 18, 2021 15 hours ago, elabx said: So in this scenario, since each product category has a different set of filters, I'd say each product has its own template, so you'd have templates: handles, door locks, door signs, accessories, each of them with its own set of fields. Mhh... no. There is only one template for all categories. The editors switch on/off filters how they please with checkboxes, and I check for those in the category template. The editors are quite educated in using this functionality, for example a lamp has no width attributes, or at least it doesn't make sense, and they know it. Link to comment Share on other sites More sharing options...
Klenkes Posted March 18, 2021 Share Posted March 18, 2021 @Erik for the sake of simplicity lets assume you have only a field for price. Your filter would be in a category/listing template, that lists your products(like in my example) /* The general outline would be: 1. Check if a filter was set by checking GET-parameter in URL 2. Read the parameter and build your selector for the $pages->find(""); 3. Execute the $pages->find with your selector 4. In case no filter was set execute your standard pages->find 5. List the result */ // 1. and 2. Check for GET-parameter in your URL if($input->get->price != ''){ $price = $sanitizer->int($input->get->price);// in my case price is integer not float $selector .= ', price<='.$price; $value_price = $price;// save the value for use in the filter input } // ...more parameter/filter to check here // ... // Very simplified... if($input->get){ // 3. execute the find on your products $allpages = $pages->find("parent=$page, $selector"); $log->save('filter', $selector);// write the build selector to a log, so you can check it }else{ // 4. on input->get so list all unfiltered pages $allpages = $pages->find("parent=$page"); } // 5. List your products foreach($allpages as $one){ // your list of products, filtered or not... } This would be the first step. The second step would be to build the form with the filter input field: // in my case I use delayed output, but you may not... $filterform .= '<form id="filter" action="'.$page->url.'" method="get">'; $filterform .= "<label for='price'>Max Price</label>"; $filterform .= "<input type='number' name='price' id='price' placeholder='input max price...' value='$value_price'>"; // ... $content .= $filterform; The rest is pretty much fine tuning... 2 Link to comment Share on other sites More sharing options...
Erik Posted March 18, 2021 Author Share Posted March 18, 2021 2 hours ago, Klenkes said: @Erik for the sake of simplicity lets assume you have only a field for price. Your filter would be in a category/listing template, that lists your products(like in my example) /* The general outline would be: 1. Check if a filter was set by checking GET-parameter in URL 2. Read the parameter and build your selector for the $pages->find(""); 3. Execute the $pages->find with your selector 4. In case no filter was set execute your standard pages->find 5. List the result */ // 1. and 2. Check for GET-parameter in your URL if($input->get->price != ''){ $price = $sanitizer->int($input->get->price);// in my case price is integer not float $selector .= ', price<='.$price; $value_price = $price;// save the value for use in the filter input } // ...more parameter/filter to check here // ... // Very simplified... if($input->get){ // 3. execute the find on your products $allpages = $pages->find("parent=$page, $selector"); $log->save('filter', $selector);// write the build selector to a log, so you can check it }else{ // 4. on input->get so list all unfiltered pages $allpages = $pages->find("parent=$page"); } // 5. List your products foreach($allpages as $one){ // your list of products, filtered or not... } This would be the first step. The second step would be to build the form with the filter input field: // in my case I use delayed output, but you may not... $filterform .= '<form id="filter" action="'.$page->url.'" method="get">'; $filterform .= "<label for='price'>Max Price</label>"; $filterform .= "<input type='number' name='price' id='price' placeholder='input max price...' value='$value_price'>"; // ... $content .= $filterform; The rest is pretty much fine tuning... I have already made many (simple) Processwire websites, but never with this functionality. I have studied this example for an hour, but I think my knowledge of PHP is now lacking. Link to comment Share on other sites More sharing options...
Erik Posted March 18, 2021 Author Share Posted March 18, 2021 On 3/17/2021 at 3:46 PM, elabx said: What exactly do you need help with? The most common/straightforward way to do this is to grab and sanitize the GET variables from a form submission and use them to create a selector: <?php //Default selector to get ALL products $selector = "template=products"; // Get color variable and sanitize $color = $input->get->text('color'); if($color){ $selector = "template=products, color=$color"; } $products = $pages->find($selector); ?> <form action="."> <select name="color"> <option value="red">Red</option> </select> </form> <div class="products"> <?php // Render the products list foreach($products as $product){ echo "<div>....</div>" } ?> </div> Thanks @elabx, I've used your example and I'm starting to get it. But what does your code look like if there is a second choice next to "color" in the search form? For example: size Link to comment Share on other sites More sharing options...
elabx Posted March 18, 2021 Share Posted March 18, 2021 A bit like this. Fixed the initial template to singular "product", its the same idea I just like it better this way ? <?php //Default selector to get ALL products $selector = "template=product"; // Get color and size variables and sanitize $color = $input->get->text('color'); $size = $input->get->int('size'); // I changed the approach here to append the possible parameters to the selector string. if($color){ $selector = $selector .= ",color=$color"; } if($size){ // See how this uses greater than or equal to $selector = $selector .= ",size>=$size"; } // At this point, if you have both parameters for the search, you'll have a selector like this: // 'template=product,color=blue,size>=10' $products = $pages->find($selector); ?> <form action="."> <select name="color"> <option value="red">Red</option> </select> <input type="text" name="size"> </form> <div class="products"> <?php // Render the products list foreach($products as $product){ echo "<div>....</div>" } ?> </div> 1 Link to comment Share on other sites More sharing options...
Erik Posted March 19, 2021 Author Share Posted March 19, 2021 22 hours ago, elabx said: A bit like this. Fixed the initial template to singular "product", its the same idea I just like it better this way ? <?php //Default selector to get ALL products $selector = "template=product"; // Get color and size variables and sanitize $color = $input->get->text('color'); $size = $input->get->int('size'); // I changed the approach here to append the possible parameters to the selector string. if($color){ $selector = $selector .= ",color=$color"; } if($size){ // See how this uses greater than or equal to $selector = $selector .= ",size>=$size"; } // At this point, if you have both parameters for the search, you'll have a selector like this: // 'template=product,color=blue,size>=10' $products = $pages->find($selector); ?> <form action="."> <select name="color"> <option value="red">Red</option> </select> <input type="text" name="size"> </form> <div class="products"> <?php // Render the products list foreach($products as $product){ echo "<div>....</div>" } ?> </div> Thanks for this example @elabx. I made my own version with checkboxes (multiselect). Only then did I come across the following problem. When I check 2 checkboxes in the same group, For example: Color = Red and Color = Green then only the products with the field green are displayed. After submit this what my url looks like: domain.com/?color=red&color=green I think it's too hard for me on a Friday ? 1 Link to comment Share on other sites More sharing options...
elabx Posted March 19, 2021 Share Posted March 19, 2021 How are you doing your markup? You should have something like this: <input type="checkbox" name="color[]" value="red"> <input type="checkbox" name="color[]" value="blue"> Now color is an array: $selector = ""; $colorOptions = $sanitizer->array($input->get->color,'text'); if(count($colorOptions){ $colorOptions = implode('|',$colorOptions); $selector = ",color=$colorOptions"; } 2 1 Link to comment Share on other sites More sharing options...
Erik Posted March 23, 2021 Author Share Posted March 23, 2021 @elabx I studied PHP this weekend. As a result, I am starting to understand more and more of your code. I'm not quite there yet. 1 Link to comment Share on other sites More sharing options...
elabx Posted March 23, 2021 Share Posted March 23, 2021 2 hours ago, Erik said: I studied PHP this weekend. As a result, I am starting to understand more and more of your code. I'm not quite there yet. Awesome! Great to hear that! Sometimes you just have to stare at the code a bit of time until it clicks, keep on it! Let me know if I can help you with something else. 4 Link to comment Share on other sites More sharing options...
Ksenia Posted October 28, 2021 Share Posted October 28, 2021 On 3/23/2021 at 3:33 PM, elabx said: Awesome! Great to hear that! Sometimes you just have to stare at the code a bit of time until it clicks, keep on it! Let me know if I can help you with something else. Hello! I am also new to PW and on my internship I need to do a frontend for the research database encoded into PW. Mostly I need filters with AND logic (checkboxes) for various fields. I have figured out how to do it with Page Reference fields, but I cannot figure out how to include simpler Text Tag fields into this structure. So it works like this but including the lists of options from the text tag fields. So, if I have the Text Tag field "type of document" which has options "book, interview, audio", let's say, I want to be able to check a box and be able to only find a book with tag "Russia" and ingredient "lucid dream". If you have ideas, I would be super grateful! New to php so theres a lot of friction for me in figuring it all out :---). Link to comment Share on other sites More sharing options...
Alexandr Posted July 9, 2024 Share Posted July 9, 2024 (edited) @elabx delete this comment, please Edited July 15, 2024 by Alexandr Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now