Best way to create filters like Newegg or B&H Photo

Here is a simple example with Tagger that uses a custom snippet (as a replacement for TaggerGetResourcesWhere) to allow for the mixing of AND and OR (as described in my last post).

I created two groups in Tagger:

  • Group “color” (Id=1) with the tags “red”, “green” and “blue”
  • Group “size” (Id=2) with the tags “small”, “medium” and “large”

Template

[[!SetSubquery]]

<form method="post" action="[[~[[*id]]]]" id="my_filter_form">
    <h3>Color</h3>
    [[TaggerGetTags? &groups=`1` &rowTpl=`tplTagCheckbox`]]
    <h3>Size</h3>
    [[TaggerGetTags? &groups=`2` &rowTpl=`tplTagCheckbox`]]
    <input type="submit" value="Filter data">
</form>
<hr>
[[!getResources? &where=`[[!+filter_subquery]]`
    &parents=`1`
    &depth=`0`
    &limit=`0`
    &tpl=`@INLINE <h2>[[+pagetitle]] ([[+id]])</h2>`
]]

Set the property &parents to the right value.

Chunk "tplTagCheckbox"

<label for="filter-tag-[[+id]]"><input type="checkbox" id="filter-tag-[[+id]]" name="filter[[+group_id]][]" value="[[+id]]" [[!+filter_tag_ids:FormItIsChecked=`[[+id]]`]]/>[[+tag]]</label>

This chunk uses the snippet FormItIsChecked from the extra FormIt.

Snippet "SetSubquery"

<?php
$tagger = $modx->getService('tagger','Tagger',$modx->getOption('tagger.core_path',null,$modx->getOption('core_path').'components/tagger/').'model/tagger/',$scriptProperties);
if (!($tagger instanceof Tagger)) return '';

$group_ids = array(1,2); //The groups to include in the filtering
$all_checked_tags = array();
$where = array();
foreach($group_ids as $group_id){
    if (isset($_POST['filter'.$group_id])) {
        $tag_ids = $_POST['filter'.$group_id];
        if (is_array($tag_ids)){
            $tag_ids = array_map('intval', $tag_ids);
            $where[] = "EXISTS (SELECT 1 FROM {$modx->getTableName('TaggerTagResource')} r WHERE r.tag IN (" . implode(',',$tag_ids) . ") AND r.resource = modResource.id)";
            $all_checked_tags = array_merge($all_checked_tags,$tag_ids);
        }
    }
}
//This placeholder is used to preserve the "checked"-state of the checkboxes
$modx->setPlaceholder('filter_tag_ids',$modx->toJson($all_checked_tags));
//This placeholder is used for the getResources subquery
$modx->setPlaceholder('filter_subquery',$modx->toJSON($where));
return '';

This example uses the id of the tags instead of the alias to keep the code simple.

Similar code could be used for the extra Taxonomies. That extra has the database table tax_page_terms that it basically the same as the table modx_tagger_tag_resources from Tagger.

2 Likes