Search code examples
phpwordpresswoocommerceshortcodecustom-taxonomy

Using a custom taxonomy for products shortcode in Woocommerce 3.3


I'm currently developing the homepage for a Woocommerce website and on this page the goal is to have 3 rows displaying products from different brands. Example; Row 1 will display Apple Products, Row 2 will display Samsung Products and Row three will display HTC products.

I've used the plugin CPT UI to create the custom taxonomy 'Brand'. Now I wish to use the example above to display only products listed under a particular brand.

Looking into the Woocommerce Shortcodes, I saw this:

[products limit="8" columns="4" category="hoodies, tshirts" cat_operator="AND"]

Is there away to do something like this with a custom taxonomy for this case brands? I.E:

[products limit="8" columns="4" brand="apple" cat_operator="AND"]

Any assistance or nudges in the right direction are much appreciated!


Solution

  • It's possible to extend Woocommerce [products] shortcode to To handle any custom taxonomy like "brand" with some kind of trick.

    The code:

    add_filter( 'woocommerce_shortcode_products_query', 'extend_products_shortcode_to_brand', 10, 3 );
    function extend_products_shortcode_to_brand( $query_args, $atts, $loop_name ){
        if ( ! empty($atts['class']) && strpos($atts['class'], 'brand') !== false ) {
            global $wpdb;
    
            $terms = array_map( 'sanitize_title', explode( ',', $atts['class'] ) );
            array_shift( $terms );
            $terms = implode(',', $terms);
            $terms = str_replace(",", "','", $terms);
    
            $ids = $wpdb->get_col( "
                SELECT DISTINCT tr.object_id
                FROM {$wpdb->prefix}term_relationships as tr
                INNER JOIN {$wpdb->prefix}term_taxonomy as tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
                INNER JOIN {$wpdb->prefix}terms as t ON tt.term_id = t.term_id
                WHERE tt.taxonomy LIKE 'brand' AND t.slug IN ('$terms')
            " );
    
            if ( ! empty( $ids ) ) {
                if ( 1 === count( $ids ) ) {
                    $query_args['p'] = $ids[0];
                } else {
                    $query_args['post__in'] = $ids;
                }
            }
        }
        return $query_args;
    }
    

    Code goes in function.php file of your active child theme (or active theme). Tested and works.


    USAGE

    We will use the class shortcode argument here:

    1) One Brand - Displaying products from "Apple" brand:

    [products limit="8" columns="4" class="brand,Apple"]
    

    2) multiple Brands - Displaying products from "Apple" and "Samsung" brands:

    [products limit="8" columns="4" class="brand,Apple,Samsung"]
    

    So the class "brand" is mandatory and needs to be the first one. Each term is coma separated.