FacetWP nested checkboxes conditional rendering

34 Views Asked by At

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.

1

There are 1 best solutions below

0
AugustoM On

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:
  • It checks if the facet being processed is named "categories."
  • It sorts the facet values based on their depth representing the hierarchical structure.
  • It organizes the facet values into states and cities based on their depth in the hierarchy.
  • It generates HTML markup for displaying the facet values, with states displayed as top-level checkboxes and cities as nested checkboxes under their respective states.
  • It adds expand/collapse functionality ([+] sign) for cities that have child cities.

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>