Простая ajax-фильтрация постов по таксономии

Разметка

<div class="filter-wrap">
      <form id="filter-form">
          <ul class="js-filter-list">
              <?php
                  $terms = get_terms(array('taxonomy' => 'products_cat', 'orderby' => 'name', 'parent' => 0));
                  foreach ($terms as $term) :
                      echo '<li class="js-filter-item"><label for="categories_' . $term->term_id . '">' . $term->name . '<input id="categories_' . $term->term_id . '" type="checkbox" name="categories[]" value="' . $term->term_id . '"><span class="checkmark"></span></label>';

                      $children = get_terms(array('taxonomy' => 'products_cat', 'orderby' => 'name', 'parent' => $term->term_id));
                      if (!empty($children)) {
                          echo '<ul>';
                          foreach ($children as $child) {
                              echo '<li><label for="categories_' . $child->term_id . '">' . $child->name . '<input id="categories_' . $child->term_id . '" type="checkbox" name="categories[]" value="' . $child->term_id . '"><span class="checkmark"></span></label></li>';
                          }
                          echo '</ul>';
                      }
                      echo '</li>';
                  endforeach;
              ?>
          </ul>
          <button class="js-filter-btn btn" type="submit">Применить фильтр</button>
          <button class="js-filter-btn btn" type="button" id="reset-filter">Сбросить фильтр</button>
      </form>
  </div>

filter.js

jQuery(document).ready(function ($) {
    $('#filter-form').on('submit', function (e) {
        e.preventDefault();

        var categories = [];
        $('input[name="categories[]"]:checked').each(function () {
            categories.push($(this).val());
        });

        $.ajax({
            url: wpAjax.ajaxUrl,
            data: {
                action: 'filter',
                categories: categories,
            },
            type: 'post',
            dataType: 'html',
            success: function (result) {
                $(".js-filter").html(result);
            },
            error: function (xhr, status, error) {
                console.error(xhr.responseText);
            },
        });
    });

    $('#reset-filter').on('click', function () { // Обработчик сброса фильтра
        $('input[name="categories[]"]').prop('checked', false);
        $('#filter-form').submit(); // После сброса сразу отправляем форму для обновления данных
    });
});

functions.php

// Ajax post filter script.
function starter_filter_scripts() {
	wp_register_script( 'starter-filter', get_stylesheet_directory_uri() . '/assets/js/filter.js', array( 'jquery' ), '_S_VERSION', true );
	wp_enqueue_script( 'starter-filter' );
	wp_localize_script( 'starter-filter', 'wpAjax', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ) ) ); 
}
add_action( 'wp_enqueue_scripts', 'starter_filter_scripts' );

// Ajax post filter function.
function starter_filter_ajax(){
    $args = array(
        'post_type' => 'products',
        'posts_per_page' => -1,
        'orderby'   => 'id',
        'order'     => 'ASC',
    );

    if (isset($_POST['categories']) && !empty($_POST['categories'])) {
        $args['tax_query'] = array(
            'relation' => 'OR',
            array(
                'taxonomy' => 'products_cat',
                'field' => 'id',
                'terms' => $_POST['categories']
            )
        );
    }

    $query = new WP_Query($args);
    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();
            get_template_part('template-parts/content', get_post_type());
        }
    } else {
        echo 'Товаров не найдено';
    }
    wp_reset_postdata();

    die;
}
add_action('wp_ajax_filter', 'starter_filter_ajax');
add_action('wp_ajax_nopriv_filter', 'starter_filter_ajax');

стили

.js-filter-list {
    display: flex;
    flex-direction: column;
}

.js-filter-item {
    margin-bottom: 10px;
}

.js-filter-item:last-of-type {
    margin-bottom: unset;
}

.js-filter-item label {
    display: block;
    position: relative;
    padding-left: 35px;
    margin-bottom: 20px;
    cursor: pointer;
    font-size: 16px;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.js-filter-item label input {
    position: absolute;
    opacity: 0;
    cursor: pointer;
    height: 0;
    width: 0;
}

.js-filter-item > ul {
    margin-top: 20px;
    padding-left: 20px;
}

.checkmark {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    left: 0;
    height: 25px;
    width: 25px;
    background-color: #eee;
    border-radius: 4px;
    transition: all 0.2s;
}

.js-filter-item label:hover input ~ .checkmark {
    background-color: #ccc;
}

.js-filter-item label input:checked ~ .checkmark {
    background: rgb(152, 182, 228);
}

.checkmark:after {
    content: "";
    position: absolute;
    display: none;
}

.js-filter-item label input:checked ~ .checkmark:after {
    display: block;
}

.js-filter-item label .checkmark:after {
    left: 9px;
    top: 5px;
    width: 7px;
    height: 12px;
    border: solid white;
    border-width: 0 1px 1px 0;
    -webkit-transform: rotate(45deg);
    -ms-transform: rotate(45deg);
    transform: rotate(45deg);
}

.js-filter-btn {
    margin-top: 10px;
    width: 100%;
}