phpwordpressfacetwp

FacetWP nested checkboxes conditional rendering


I am using FacetWP on a Wordpress site and it works like a charm, recently was asked to render the checkboxes filter using a conditional logic so, some of them will be hidden or not rendered if the condition mets, I started to play with a FacetWP hook to render the facet checkboxes, but cannot make it working, checked on the documentation but couldn't find a useful case.

add_filter('facetwp_facet_html', 'custom_hide_single_child_facets', 10, 2 );

function custom_hide_single_child_facets( $output, $params ) {
    if ( 'categories' == $params['facet']['name'] ) {        
      $values = $params['values'];
      $filtered = [];

      foreach ($values as $value) {
        if ($value['depth'] != 2) {
          $filtered[] = $value;
        }
      }

      $params['values'] = $filtered;
    }
    return $output;
}

The above does not filter anything so all checkboxes are there, and was hoping to get the third level of checkboxes hidden. If I can have this working, I can continue with the implementation of the conditional. Any guidance is highly appreciated.


Solution

  • Here is the answer, in my case scenario, the 'categories' are used to mark physical locations like states, and cities, and the third level depth is used for those locations that have additional specificity, then, the categories in the third level are mapped including most of the times the same value as in the second level which is unwanted, then I thought naively that just somehow messing with the values array in FacetWP (which contains all the shown values) could be enough, but for this hook likes it does not impact the output at all, then I had to rebuild the facets using their template like the below:

    add_filter('facetwp_facet_html', 'custom_hide_single_child_facets', 10, 2 );
    
    function custom_hide_single_child_facets( $output, $params ) {    
        if ( $params['facet']['name'] == 'categories' ) {        
          $values = $params['values'];
          $states = [];
          $cities = [];
          $str  = '';
    
          usort($values, function($a, $b){
            return $a['depth'] - $b['depth'];
          });
    
          foreach ($values as $value) {
            if ($value['depth'] == 0) {
              $states[$value['term_id']] = $value;
            }
    
            if ($value['depth'] == 1) {
              $cities[$value['term_id']]['city'][] = $value;
            }
    
            if ($value['depth'] == 2) {
              $cities[$value['parent_id']]['city']['children'][] = $value;
            }
          }
          
          foreach ($states as $state) {        
            $str .= '<div class="facetwp-checkbox" data-value="'.trim($state['facet_value']).'">';
              $str .= '<span class="facetwp-display-value">'.trim($state['facet_display_value']).'</span>';
              $str .= '<span class="facetwp-counter">('.trim($state['counter']).')</span>';
              $str .= '<span class="facetwp-expand">[+]</span>';
            $str .= '</div>';
    
            $str .= '<div class="facetwp-depth">';
              foreach ($cities as $city) {
                if ($state['term_id'] == $city['city'][0]['parent_id']) {
                  $children = $city['city']['children'] ?? [];
                  $str .= '<div class="facetwp-checkbox" data-value="'.trim($city['city'][0]['facet_value']).'">';
                    $str .= '<span class="facetwp-display-value">'.trim($city['city'][0]['facet_display_value']).'</span>';
                    $str .= '<span class="facetwp-counter">('.trim($city['city'][0]['counter']).')</span>';
                    if (count($children) > 1) {
                      $str .= '<span class="facetwp-expand">[+]</span>';
                    }              
                  $str .= '</div>';
    
                  $str .= '<div class="facetwp-depth">';              
                    if (count($children) > 1) {
                      foreach ($children as $child) {
                        $str .= '<div class="facetwp-checkbox" data-value="'.trim($child['facet_value']).'">';
                          $str .= '<span class="facetwp-display-value">'.trim($child['facet_display_value']).'</span>';
                          $str .= '<span class="facetwp-counter">('.trim($child['counter']).')</span>';
                        $str .= '</div>';
                      }
                    }
                  $str .= '</div>';
                }            
              }
            $str .= '</div>';
          }
          
          $output = $str;
        }
        return $output;
    }
    

    What the above does is:

    1. It hooks into the facetwp_facet_html filter with the function custom_hide_single_child_facets.
    2. Inside the custom_hide_single_child_facets function:

    However the above has a side effect with the JS script side and the 'checked' status was somehow missed, then had to write a small JS script to fix it like the below:

    <script>
      document.addEventListener('facetwp-loaded', function(){
        let checkboxes = document.querySelectorAll('.facetwp-checkbox');
        let query = window.location.search;
        let params = new URLSearchParams(query);
        let category = params.get('fwp_categories');      
    
        checkboxes.forEach(item => {
          if (item.dataset.value == category) {
            item.classList.add('checked');
            let parent = item.parentElement;
            while(!parent.classList.contains('facetwp-facet')){
              if (!parent.classList.contains('facet-depth')) {
                parent.classList.add('visible');
              }
              parent = parent.parentElement;
            }          
          }
        })
      }, false);
    </script>