Mairyu
Mairyu

Reputation: 839

How to implement a WooCommerce product archive filter

I hope it's okay to ask a very generic top view question. I started out with WordPress and want to improve my (non-existent) HTML/CSS/PHP/JS etc. coding skills to customize my site.

I got WooCommerce & Elementor and I'm fairly happy with my shop page, but I'm getting tired of trying plugin after plugin to get exactly what I need (I'm in now rush at all, so this can be a long journey, but I want to make sure I'm going in the right direction).

So what I'm wondering is what does it take to be able to revamp the filter and archive pages so I can get exactly what I want? Obviously, I need HTML/CSS skills, but how do I implement the actual filtering?

I added custom fields to the WooCommerce products via ACF, so ideally I want to filter by that. I also want to add badges or custom elements to the individual products (in the archive page) based on those custom fields.

I assume I can do something via JS (add the badges) by (somehow) querying the field value (if I can access those from within WooCommerce), but how is the filtering done? Do I have to rebuild the entire HTML (table) or can this be done smarter by filtering the input to whatever generates the archive page (might be way off here ...)

So again, not asking for the exact code, just want to know if I should try to ramp up on JS to get this implemented, and/or is it possible to access those WooCommerce custom fields (which method would I use for that)?

Hope this is not too generic a question and it makes somewhat sense to you all ...

Upvotes: 2

Views: 2309

Answers (1)

Alisson Custodio
Alisson Custodio

Reputation: 31

There are two hooks for you to create custom filters using product fields and product categories/tags.

woocommerce_product_query

Its use can be applied to all fields that are registered in the database in the "wp_usermeta" table (the "wp_" in front is the prefix that was registered when installing wordpress), such as the standard Woocommerce fields or the custom ones created from woocommerce_wp_text_input for example.

add_action( 'woocommerce_product_query', 'name_of_function_to_call' );

inside your function you will build the query that will be used to search the information in the database, this is an example of how to search (or not) products in a specific price range:

function name_of_function_to_call()
{
    $min_price = isset($_GET['min-price']) ? str_replace(",", ".", str_replace(".", "", str_replace("R$ ", "", $_GET['min-price']))) : false;
    $max_price = isset($_GET['max-price']) ? str_replace(",", ".", str_replace(".", "", str_replace("R$ ", "", $_GET['max-price']))) : false;

    if($min_price && $max_price){   
        $price_filter = array(
            'key'       => '_price',
            'value'     => array( $min_price , $max_price ),
            'compare'   => 'BETWEEN',
            'type'      => 'numeric'  
          ); 
        array_push($args, $price_filter);
    } elseif($min_price){
        $price_filter = array(
            'key'       => '_price',
            'value'     => array( $min_price , 9999999999 ),
            'compare'   => 'BETWEEN',
            'type'      => 'numeric'  
          ); 
        array_push($args, $price_filter);        
    } elseif($max_price){
        $price_filter = array(
            'key'       => '_price',
            'value'     => array( 0 , $max_price ),
            'compare'   => 'BETWEEN',
            'type'      => 'numeric'  
          ); 
        array_push($args, $price_filter);        
    }
    
    $q->set( 'meta_query', array_filter($args) );
}

At the end of this step, Wordpress will treat the items you entered in "meta_query" as a WHERE in the database search SQL (don't worry if you don't understand this part).

woocommerce_product_query_tax_query

Its use can be applied to taxonomies (categories) and tags, which are registered in the database in the "wp_terms" table (the "wp_" in front is the prefix that was registered when installing wordpress). To call a function from its execution, use:

add_action( 'woocommerce_product_query_tax_query', 'name_of_function_to_call_for_taxonomy' );

Inside your function you will build the query that will be used to fetch the information in the database, this is an example of how to fetch (or not) categories and tags where the category stores the product brand and the tag its color:

function name_of_function_to_call_for_taxonomy($q='')
{
    $brand = isset($_GET['brand']) ? $_GET['brand'] : false;
    $color = isset($_GET['color']) ? $_GET['color'] : false;
    $tax_query = array();

    if($brand){
        $taxonomy = 'product_cat';
        $terms = array( $brand );

        $tax_query[] = array(
            'taxonomy' => $taxonomy,
            'field'    => 'term_id', // Or 'slug' or 'term_id'
            'terms'    => $terms,
        );
    }

    if($color){
        $taxonomy = 'product_tag';
        $terms = array( $color );

        $tax_query[] = array(
            'taxonomy' => $taxonomy,
            'field'    => 'term_id', // Or 'slug' or 'term_id'
            'terms'    => $terms,
        );
    }

    return array_filter($tax_query);
}

Search Form

to pass the fields just create a standard form, in the case of the examples above it will be something like:

<form action="" method="GET" role="search">
    <div class="ac-filters-main">
        <div>
            <label>Price Min</label>
            <input id="price_min" class="ac-valid-price" type="text" name="min-price" value="<?php if(isset($_GET['min-price'])){ echo $_GET['min-price']; }?>" placeholder="Price Min">
        </div>
        <div>
            <label>Price Max</label>
            <input id="price_max" class="ac-valid-price" type="text" name="max-price" value="<?php if(isset($_GET['max-price'])){ echo $_GET['max-price']; }?>" placeholder="Price Max">
        </div>
        <?php 
            $categories = get_terms('product_cat');
            if($categories){ 
        ?>
            <div>
                <label>Brand</label>
                <select name="brand">
                    <option value="">Select</option>
                    <?php
                        foreach ($categories as $k => $v) {
                    ?>
                        <option value="<?=$v->term_id?>" <?php if(isset($_GET['brand']) && $_GET['brand'] == $v->term_id){ echo'selected=""'; } ?>><?=$v->name?></option>
                    <?php } ?>
                </select>
            </div>
        <?php } ?>
        <?php       
            $colors = get_terms('product_tag');
            if($colors){
        ?>
            <div>
                <label>Color</label>
                <select name="color">
                    <option value="">Select</option>
                    <?php
                        foreach ($colors as $k => $v) {
                    ?>
                        <option value="<?=$v->term_id?>" <?php if(isset($_GET['color']) && $_GET['color'] == $v->term_id){ echo'selected=""'; } ?>><?=$v->name?></option>
                    <?php } ?>
                </select>
            </div>
        <?php } ?>
    </div>
    <div class="ac-filters-bottom">
        <input type="text" name="s" value="<?php if(isset($_GET['s'])){ echo $_GET['s']; }?>" placeholder="I'm looking for..." class="ac-search-input">
        <button type="submit" class="ac-search-btn">Search</button>
    </div>
</form>

Upvotes: 3

Related Questions