简体   繁体   中英

WP_Query not "resetting" when AJAX filter params become empty

This question was originally posted in wordpress.stackexchange , but deemed to be off-topic for some reason, so I'm posting here per the suggestion in the ruling comment.

I've created an AJAX taxonomy( product_cat ) filter that's used on my WooCommerce product archive page ( archive-product.php ). The page loads the normal WooCommerce shop loop onload:

woocommerce_product_loop_start();

if (wc_get_loop_prop('total')) {
    while (have_posts()) {
        the_post();

        /**
         * Hook: woocommerce_shop_loop.
         *
         * @hooked WC_Structured_Data::generate_product_data() - 10
         */
        do_action('woocommerce_shop_loop');

        wc_get_template_part('content', 'product');
    }
}

woocommerce_product_loop_end();

That page loads correctly, showing all products. The filter also works great. It filters one or more taxonomies correctly.

The problem is when I uncheck all the checkboxes. I want it to clear any filters and show all products again. Instead, I currently get an error:

POST .../wp-admin/admin-ajax.php 500

The relevant product filter js:

function handleFilterCheckboxesChange(event) {
    const data = {
        action: 'wpf_update_products',
        filters: get_current_filters()
    };
    $.ajax({
        type: 'POST',
        url: '/wp-admin/admin-ajax.php',
        data: data,
        success: function (res) {
            console.log("AJAX Success: ", data.filters);
            // > ["example_category_slug"]
            $('.products').html(res);
        },
        error: function (err) {
            console.error("AJAX Error: ", data.filters);
            // > []
        }
    });

    $(document.body).trigger('post-load');
}

function get_current_filters() {
    const checkboxes = $('.product-cat-filter-checkbox').get();
    let checked = [];
    for (let i = 0; i < checkboxes.length; i++) {
        if (checkboxes[i].checked) {
            checked.push(checkboxes[i].id);
        };
    }
    return checked;
}

The server-side action:

function wpf_update_products() {
    
    $filter_terms = $_POST['filters'];
    
    $args = [
        'post_type'      => 'product',
        'posts_per_page' => 20,
        'post_status'    => 'publish',
    ];

    // I expect the next line to check for empty filter terms and "reset"/skip this tax_query, but I still get a 500 error
    if ($filter_terms !== null && isset($filter_terms) && $filter_terms !== '' && !empty($filter_terms)) {
        $args['tax_query'][] = [
            'taxonomy' => 'product_cat',
            'field'    => 'slug',
            'terms'    => $_POST['filters']
        ];
    }

    $ajax_query = new WP_Query($args);
    $response = '';

    if ($ajax_query->have_posts()) {
        ob_start();
        while ($ajax_query->have_posts()) : $ajax_query->the_post();
            $response .= wc_get_template_part('content', 'product');
        endwhile;
        $output = ob_get_contents();
        ob_end_clean();
        wp_reset_postdata();
    } else {
        echo __('Sorry, there are no products that fit your query.', 'wpf');
    }
    echo $output;
    die();
}

...hooked from the same class:

add_action('wp_ajax_wpf_update_products', array($this, 'wpf_update_products'));
add_action('wp_ajax_nopriv_wpf_update_products', array($this, 'wpf_update_products'));

When I var_dump the query on successful filtering, it correctly shows the added tax_query, but I'm unable to dump the query on unsuccessful [empty] filtering because the server responds with 500.

Can't figure out why it's returning the error if I'm handling the empty $_POST['filters'] on the server side. Can anyone see what I'm missing?

UPDATE: I added an else to the server-side query, and was able to get around the 500 error. The updated if statement to set the filter query args is:

if ($filter_terms !== null && isset($filter_terms) && $filter_terms !== '' && !empty($filter_terms)) {
    $args['tax_query'][] = [
        'taxonomy' => 'product_cat',
        'field'    => 'slug',
        'terms'    => $filter_terms
    ];
} else {
    $args['tax_query'][] = [
        'taxonomy' => 'product_cat'
    ];
}

Now, the query tries to run, but I get the 'Sorry, there are no products that fit your query.' statement because no posts were found. WP_Query doesn't seem to like a tax_query with only the taxonomy set. I var_dumped the query and see that the tax_query is filled correctly with the three args when a filter is checked:

'tax_query' => 
    array (size=1)
      0 => 
        array (size=3)
          ...

...and when all filters become unchecked, the tax_query has the one 'taxonomy' => 'product_cat' arg:

'tax_query' => 
    array (size=1)
      0 => 
        array (size=1)
          ...

I just can't seem to clear the tax_query if filters is empty. With the original code—no else statement if filters is empty—I just got the 500 error, but even if my else statement sets the tax_query completely empty like so: $args['tax_query'][] = [] , it still throws the 500 error. Why doesn't WP fall back to the rest of the original query if tax_query is empty?

And finally, I also tried setting the query args manually to all possible taxonomy terms like so:

if ($filter_terms !== null && isset($filter_terms) && $filter_terms !== '' && !empty($filter_terms)) {
    $args['tax_query'][] = [
        'taxonomy' => 'product_cat',
        'field'    => 'slug',
        'terms'    => $filter_terms
    ];
} else {
    $all_terms = get_terms(array('taxonomy' => 'product_cat', 'fields' => 'slugs'));
    $args['tax_query'][] = [
        'taxonomy' => 'product_cat',
        'field'    => 'slug',
        'terms'    => $all_terms
    ];
}

...but I just get the 500 error again:/ Dumping $all_terms gives me this, a list of all terms that contain any products:

array (size=4)
  0 => string 'bakeware' (length=8)
  1 => string 'cookware' (length=8)
  2 => string 'cutlery-kitchen-tools' (length=21)
  3 => string 'linens' (length=6)

I don't see the $filter_terms variable being set within the scope of your wpf_update_products() function. If I'm understanding the intent of your code correctly, try the following:

// I expect the next line to check for empty filter terms and "reset"/skip this tax_query, but I still get a 500 error
if ( ! empty( $_POST['filters'] ) ) {
    $args['tax_query'][] = [
        'taxonomy' => 'product_cat',
        'field'    => 'slug',
        'terms'    => $_POST['filters']
    ];
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM