Search code examples
phpfunctionwoocommerceshortcodetaxonomy-terms

Shortcode that display all product attributes set for a WooCommerce product


I keep searching for a way to do this, but I can't find anything unfortunately.

I an trying to display all the product's attributes and values, separated by a pipe, in a custom place on the single-product (so for that I was thinking to create a shortcode, so I can place it anywhere I want). the output would be something like this:

BRAND: RENAULT | MODEL: 12 | YEAR: 1973

The code on the Woocommerce template product-attributes.php lists the attributes of the current product on single-product page, but it will list it with some styles I don't want in a place I don't want.

I want to create a shortcode with that code, which is:

<?php foreach ( $product_attributes as $product_attribute_key => $product_attribute ) : ?>
    
            <?php echo wp_kses_post( $product_attribute['label'] ); ?>: <?php echo wp_kses_post( $product_attribute['value'] ); ?> | 
    
    <?php endforeach; ?>

How can I create a shortcode with it? I know the general code for a shortcode, but I don't know how to actually integrate the above one in it:


function custom_attributes_product_page() { 
 
// integrate the required code

// Output needs to be return
return 
} 
// register shortcode
add_shortcode('custom-attributes', 'custom_attributes_product_page'); 

Would be great if this shortcode would list the attributes and their values separated by a column, like I said above (how to do that?)

Any help is highly appreciated.


Solution

  • Try the following shortcode that will display all product attribute(s) set for a product and their value(s), handling custom attributes too:

    function get_product_attributes_shortcode($atts ) {
        // Extract shortcode attributes
        extract( shortcode_atts( array(
            'id'    => get_the_ID(),
        ), $atts, 'display-attributes' ) );
    
        global $product;
    
        if ( ! is_a($product, 'WC_Product') ) {
            $product = wc_get_product( $id );
        }
    
        if ( is_a($product, 'WC_Product') ) {
            $html = []; // Initializing
    
            foreach ( $product->get_attributes() as $attribute => $values ) {
                $attribute_name = wc_attribute_label($values->get_name());
                $attribute_data = $values->get_data();
                $is_taxonomy    = $attribute_data['is_taxonomy'];
    
                $option_values    = array(); // Initializing
    
                // For taxonomy product attribute values
                if( $is_taxonomy ) {
                    $terms = $values->get_terms(); // Get attribute WP_Terms
    
                    // Loop through attribute WP_Term(s)
                    foreach ( $terms as $term ) {
                        $term_link       = get_term_link( $term, $attribute );
                        $option_values[] = '<a href="'.$term_link.'">'.$term->name.'</a>';
                    }
                }
                // For "custom" product attributes values
                else {
                    // Loop through attribute option values
                    foreach ( $values->get_options() as $term_name ) {
                        $option_values[] = $term_name;
                    }
                }
    
                $html[] = '<strong>' . $attribute_name . '</strong>: ' . implode(', ', $option_values);
            }
    
            return '<div class="product-attributes">' . implode(' | ', $html) . '<div>';
        }
    }
    add_shortcode( 'display-attributes', 'get_product_attributes_shortcode' );
    

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

    USAGE: [display-attributes] or with a defined product Id [display-attributes id="254"]

    You will get a display like: BRAND: RENAULT | MODEL: 12 | YEAR: 1973

    If you don't want the linked terms, replace:

                        $term_link       = get_term_link( $term, $attribute );
                        $option_values[] = '<a href="'.$term_link.'">'.$term->name.'</a>';
    

    by this:

                        $option_values[] = $term->name;