Search code examples
phpwordpresswoocommercecustom-taxonomytaxonomy-terms

Display WooCommerce Custom Product Attributes and all terms on single products


I created six custom attributes on the WooCommerce single product page with a custom function. They consist of: an icon, a label and terms.

Based on Replace WooCommerce attribute labels by a custom image for each answer code, I used the following function (with custom HTML markup, different from the markup in the WooCommerce product-attributes.php template):

add_action('woocommerce_single_product_summary', 'pa_custom_attributes', 25);
function pa_custom_attributes(){
    global $product;

    $attributes = $product->get_attributes();

    if ( ! $attributes ) return;

    $out = '<div class="custom-attributes">';

    foreach ( $attributes as $attribute ) {

        if ( $attribute->get_variation() ) continue;

        if ( $attribute->is_taxonomy() ) {
            
            $taxonomy = $attribute->get_name();
            $taxo_obj = $attribute->get_taxonomy_object();
            $name = $taxo_obj->attribute_name;
            $label = $taxo_obj->attribute_label;
            $label_name = wc_attribute_label( $taxonomy );

            $out .= '<div class="' . esc_attr( $taxonomy ) . ' single-attribute">';

            $out .= '<div><img class="attribute-image" src="'.get_stylesheet_directory_uri().'/woocommerce/attributes/'.$name.'.svg" alt="Attribute '.$label.'"/></div>';

            $out .= '<div class="attribute-label '.$label.'">'.$label_name.'</div>';
            
            $out .= '<div class="attribute-values">';

            $terms = wp_get_post_terms( $product->get_id(), $taxonomy, array('fields' => 'names') );

            foreach ( $terms as $term_name )
                $term_names['names'] = $term_name;

            $out .= implode(', ', $term_names);
            $out .= '</div></div>';

        } else {
            $value_string = implode( ', ', $attribute->get_options() );
            $out .= '<div class="' . sanitize_title($taxonomy) . ' ' . sanitize_title( $value_string ) . '">';
            $out .= '<div class="attribute-label">' . $taxonomy . ': </div> ';
            $out .= '<div class="attribute-value">' . esc_html( $value_string ) . '</div></div>';
        }
    }
    $out .= '</div>';

    echo $out;
}

The function works correctly, but it has a problem: if the terms of a specific attribute are more than one (e.g. colors: red, blue, green), on the screen the function prints only the last value of the array.

I read the documentation and made many tests and checked that there were no problems on the CSS. I also read practically every answer to the questions on the subject here on StackOverflow and online but I couldn't find an answer.

Is there anyone who can help me understand where the error is?


Solution

  • The problem comes from the following in your code:

                $terms = wp_get_post_terms( $product->get_id(), $taxonomy, array('fields' => 'names') );
    
                foreach ( $terms as $term_name )
                    $term_names['names'] = $term_name;
    
                $out .= implode(', ', $term_names);
    

    That you can replace with this:

                $terms = wp_get_post_terms( $product->get_id(), $taxonomy, array('fields' => 'names') );
    
                $term_names = []; // Initializing
    
                // Loop through each terms
                foreach ( $terms as $term_name ) {
                    $term_names[] = $term_name;
                }
    
                $out .= implode(', ', $term_names);
    

    Or even better with one line of code:

                $out .= $product->get_attribute( $taxonomy );