3

In WooCommerce, I'm currently building a function that will echo some product attributes in the shop page. I would like to separate these with commas if there is multiple attribute values available, but I don't know how.

My code:

add_action('woocommerce_after_shop_loop_item_title', 'TitleVariations', 10);
function TitleVariations()
{
global $product;
    
$colormonth = $product->get_attribute('color-month');
$finish = $product->get_attribute('finish');
$design = $product->get_attribute('design');

echo '<span class="variation-display">';
echo __($colormonth, 'woocommerce');
echo __($finish, 'woocommerce');
echo __($crossdesign, 'woocommerce');
echo '</span>';
}
Dharman
  • 21,838
  • 18
  • 57
  • 107
Josh933
  • 35
  • 3
  • 2
    @Loic this question is a mega-duplicate. I do not appreciate you unhammering the closure. If you don't like my dupe target, find another one -- there will be dozens to choose from. – mickmackusa Jan 13 '21 at 15:39
  • 1
    @mickmackusa Sorry this has nothing to do with WooCommerce Product categories… See my answers… WooCommerce Product Attributes are a very specific custom taxonomy, that is used for product variations… There is also custom product attributes that are not taxonomy… so this is not a dup. – LoicTheAztec Jan 13 '21 at 15:56
  • 1
    @Josh please post WordPress questions on [wordpress.se] -- a dedicated WordPress Stack Exchange community. – mickmackusa Jan 13 '21 at 15:58
  • This is probably close enough to a duplicate to close with: https://stackoverflow.com/a/49630369/2943403 After all, the OP isn't struggling with retrieving the data, the OP just wants to know how to implode the array of non-empty values. – mickmackusa Jan 13 '21 at 16:36
  • Or https://stackoverflow.com/a/31532691/2943403 – mickmackusa Jan 13 '21 at 16:52

2 Answers2

3

Collect your values to array and then implode this array:

$values = [
    __($colormonth, 'woocommerce'),
    __($finish, 'woocommerce'),
    __($crossdesign, 'woocommerce'),
];

// if some values returned by `__()` are empty strings, 
// you can filter your array so as to remove them
$values = array_filter($values);

echo '<span class="variation-display">';
echo implode(', ', $values);
echo '</span>';
u_mulder
  • 51,564
  • 5
  • 39
  • 54
  • Thank you for the prompt response! I have implemented this however some products have only one attribute and some could have between 1-5 different attributes (i've yet to add the others). How could I hide these commas if there's only 1 attribute for example? – Josh933 Jan 13 '21 at 15:18
  • You didn't yet try this solution with a single value ...did you? – mickmackusa Jan 13 '21 at 15:20
  • @mickmackusa Yes I did, and the result on a single value is comma on each side of the value. – Josh933 Jan 13 '21 at 15:27
  • That is not what this answer will generate. – mickmackusa Jan 13 '21 at 15:35
  • 2
    @mickmackusa probably the value returned by `__()` is empty string. That's why there're some strange `,`. – u_mulder Jan 13 '21 at 15:45
  • __Updated__ my answer with `array_filter` example for removing empty strings. – u_mulder Jan 13 '21 at 15:48
  • 2
    "How to remove empty elements?" and "How to join strings with commas?" are both mega-duplicate questions. This question is Unclear because we don't know what the input is. `array_filter()` is a greedy killer of falsey values, so this native technique may damage the output. – mickmackusa Jan 13 '21 at 15:48
  • 1
    @Loic this is why the veterans must be relied upon to curate good content and not answer duplicate questions. This way Stack Overflow becomes a better, less redundant resource for researchers. – mickmackusa Jan 13 '21 at 16:14
  • This answer is basically equivalent to Loic's answer, but is more concise. – mickmackusa Jan 13 '21 at 16:47
2

The WC_Product method get_attribute() gives a comma separated string of values when there is more than one value… You also need to check that each different attribute has at list one term…

To get the product attribute label name, yo can use wc_attribute_label() product attribute function.

1). If you want to get each product attribute with the label name and the term(s) value(s) (each different attribute in one line), you will use the following instead.

This code handle also custom product attributes:

add_action('woocommerce_after_shop_loop_item_title', 'display_loop_product_attributtes', 10);
function display_loop_product_attributtes()
{
    global $product;
    
    // Here define your product attribute names (slugs)
    $attribute_names = array('color-month', 'finish', 'design'); 
    $attributes      = array(); // Initializing
    
    // Loop Through product attributes array
    foreach( $attribute_names as $attribute_name ) {
        if( taxonomy_exists( 'pa_' . $attribute_name )  ) {
            $attribute = 'pa_' . $attribute_name; // Custom taxonomy
        } else {
            $attribute = $attribute_name; // Custom attribute (not a taxonomy)
        }

        $values_str = $product->get_attribute($attribute);

        if ( $values_str ) {
            $attributes[] = '<strong>' . wc_attribute_label($attribute) . ':</strong> ' . $values_str;
        }
    }

    // Output product attribute label / values pairs (one by line)
    if( ! empty( $attributes ) ) { 
        echo '<span class="variation-display">' . implode( '<br>', $attributes ) . '</span>';
    }
}

2). But if you want to get all your product attributes terms as a comma separated string, your code will be something like in Display specific product attributes under product title in Woocommerce archive pages.

So for your code:

add_action('woocommerce_after_shop_loop_item_title', 'display_loop_product_attributtes', 10);
function display_loop_product_attributtes()
{
    global $product;
        
    $color_month = $product->get_attribute('color-month');
    $finish      = $product->get_attribute('finish');
    $design      = $product->get_attribute('design');

    $attributes  = array(); // Initializing
    
    if ( $color_month ) {
        $attributes[] = $color_month;
    }
    if (  $finish ) {
        $attributes[] = $finish;
    }
    if ( $design ) {
        $attributes[] = $design;
    }

    // Output product attribute values
    if( ! empty( $attributes ) ) { 
        echo '<span class="variation-display">' . implode( ', ', $attributes ) . '</span>';
    }
}

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

LoicTheAztec
  • 184,753
  • 20
  • 224
  • 275
  • 1
    Is it different from this answer? https://stackoverflow.com/a/53161699/1839439 – Dharman Jan 13 '21 at 15:55
  • The comas should be commas. All these `!empty()` checks are useless since the variables are already set/declared -- just check if the values are falsey. – mickmackusa Jan 13 '21 at 15:55
  • 1
    Please do not beg for upvotes, you no longer need rep and your comment normalizes this bad commenting to newer members. – mickmackusa Jan 13 '21 at 16:11
  • `! empty( $attributes )` is also needless overhead when a truthy check will do. – mickmackusa Jan 13 '21 at 16:15
  • That does not make it right, it means that other codes are doing needless extra work too. `$attributes` is declared, the only thing to do is check if it is truthy and nothing more. To check if `$attributes` is empty: `if (!$attributes) {` or if non-empty: `if ($attributes) {`. – mickmackusa Jan 13 '21 at 16:37