Search code examples
phpwordpresswoocommerceproducttaxonomy-terms

Get a list of WooCommerce product attributes radio buttons from a product WP_Query


On a custom page I output products from a category using wp_query. How can I output a list of attributes and their number from these products for further filtering?

Size (pa_size) (radio or checkboxs)
-S (2)
-M (1)

Color (pa_color) (radio or checkboxs)
-Red (15)
-Blue (4)
...

wp_query products:

       $query = new WP_Query($args = array(
        'post_type'             => 'product',
        'post_status'           => 'publish',
        'ignore_sticky_posts'   => 1,
        'posts_per_page'        => -1,
        'tax_query'             => array(
            array(
                'taxonomy'      => 'product_cat',
                'terms'         => 41,
            ),
        ),
    ));
    ?>
   <div class="products">
    <?php
       if ($query->have_posts()) :
        while ($query->have_posts()) :
            $query->the_post();
    
            wc_get_template_part('content', 'product-list');
    
        endwhile;
        wp_reset_postdata();
    endif;
    
    ?>
    </div>

For example get_terms("pa_size"); shows all attributes. WC Filters on custom page do not work. I know how to filter further by attributes, but I don’t know how to get a list of attributes from these products.


Solution

  • You can use the following custom utilities function to get product attributes from a WP_Query and display radio buttons for each product attribute terms:

    function get_product_attributes_from_query( $query ){
        global $wpdb;
    
        $post_ids = implode(',', array_column( (array) $query->posts, 'ID', false) );
    
        return $wpdb->get_results("
            SELECT t.term_id, t.name, t.slug, tt.taxonomy, tt.count
            FROM {$wpdb->prefix}term_relationships as tr
            JOIN {$wpdb->prefix}term_taxonomy as tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
            JOIN {$wpdb->prefix}terms as t ON tt.term_id = t.term_id
            WHERE tt.taxonomy LIKE 'pa_%' AND tr.object_id IN ( {$post_ids} )
            GROUP BY t.term_id  ORDER BY tt.taxonomy
        " ); 
    }
    
    function display_related_product_attributes_radio_buttons( $query ) {
        if ( $query->have_posts() ) {
            echo ' <div class="attributes-radios">';
    
            if ( $results = get_product_attributes_from_query( $query ) ) {
                $terms_by_taxonomy = array(); // Initializing
    
                // Loop through attributes
                foreach ( $results as $result ) {
                    // Group by attribute taxonomy
                    $terms_by_taxonomy[$result->taxonomy][$result->term_id] = $result;
                }
    
                // Loop through grouped attributes by taxonomy
                foreach ( $terms_by_taxonomy as $taxonomy => $terms ) {
                    printf('<p class="form-row" id="%s_field"><label for="%s"><strong>%s:</strong></label>
                    <span class="woocommerce-input-wrapper">', 
                    $taxonomy, $taxonomy, wc_attribute_label($taxonomy) );
    
                    // Loop through terms from the current taxonomy
                    foreach ( $terms as $term_id => $term ) {
                        printf('<label for="%s_%s" class="radio">
                        <input type="radio" class="input-radio" value="%s" name="%s" id="%s_%s"> <span>%s&nbsp;(%s)</span></label>', $term->slug, $taxonomy, 
                        $taxonomy, $term->slug, $taxonomy, $term->slug, $term->name, $term->count );
                    }
                    echo '</span></p>';
                }
            }
            echo '</div>';
        }
    }
    

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

    USAGE: Then you can use it in your code like:

    $query = new WP_Query($args = array(
        'post_type'             => 'product',
        'post_status'           => 'publish',
        'ignore_sticky_posts'   => 1,
        'posts_per_page'        => -1,
        'tax_query'             => array(
            array(
                'taxonomy'      => 'product_cat',
                'terms'         => 41,
            ),
        ),
    )); 
    
    // Here we insert the function for example
    display_related_product_attributes_radio_buttons( $query );
    
    ?>
    <div class="products">
    <?php
       if ($query->have_posts()) :
        while ($query->have_posts()) :
            $query->the_post();
    
            wc_get_template_part('content', 'product-list');
    
        endwhile;
        wp_reset_postdata();
    endif;
    
    ?>
    </div>
    

    You will get something like:

    enter image description here