I am trying to accomplish a attribute and term list on the shop page using the hook woocommerce_shop_loop_item_title. The goal is to get the attribute(s) and term(s) for the product and then to display it like this example:
Color: Red, Blue, Green
Size: Small, Medium, Large
Dimensions: 90*90, 100*100 and 120*120
but without the spaces between the rows.
It should "fetch" all the attributes used with the product and the attributes terms.
I've tried this but got fatal error.
add_action( 'woocommerce_shop_loop_item_title', 'variable_att_and_terms_on_loop');
function variable_att_and_terms_on_loop() {
foreach( $product->get_variation_attributes() as $taxonomy => $terms_slug ) {
$taxonomy_label = wc_attribute_label( $taxonomy, $product );
foreach($terms_slug as $term) {
$term_name = get_term_by('slug', $term, $taxonomy)->name;
$attributes_and_terms_names[$taxonomy_label][$term] = $term_name;
}
}
foreach ( $attributes_and_terms_names as $attribute_name => $terms_name ) {
$terms_string = implode( ', ', $terms_name );
echo '<p>' . $attribute_name . ': ' . $terms_string . '</p>';
}
}
I've also tried this:
add_action('woocommerce_shop_loop_item_title','add_attribute', 5);
function add_attribute() {
global $product;
$product_attributes = array( 'pa_weight', 'pa_quantity', 'pa_length', 'pa_color' );
$attr_output = array();
foreach( $product_attributes as $taxonomy ){
if( taxonomy_exists($taxonomy) ){
$label_name = get_taxonomy( $taxonomy )->labels->singular_name;
$value = $product->get_attribute('pa_weight');
if( ! empty($value) ){
$attr_output[] = '<span class="'.$taxonomy.'">'.$label_name.': '.$value.'</span>';
}
}
}
echo '<div class="product-attributes">'.implode( '<br>', $attr_output ).'</div>';
}
without any result.
After trying the new result below from LoicTheAztec, this is what I get:
Uppdate 2020 - Removed an error when trying to get the term name from a term slug.
In your first code snippet there are some mistakes:
the $product variable was not defined
The function needed to be restricted to variable products only
the $attributes_and_terms_names variable was not initialized…
Here is the revisited code (without the spaces between the rows):
add_action( 'woocommerce_shop_loop_item_title', 'variable_att_and_terms_on_loop');
function variable_att_and_terms_on_loop() {
global $product;
if( ! $product->is_type('variable') ) return; // Only for variable products
$variation_attributes = $product->get_variation_attributes();
if( sizeof($variation_attributes ) == 0 ) return; // Exit if empty
$attributes = array(); // Initializing
foreach( $product->get_variation_attributes() as $taxonomy => $terms_slug ) {
$taxonomy_label = wc_attribute_label( $taxonomy, $product );
$terms_name = array();
foreach($terms_slug as $term_slug ) {
// We try to get the term name when it's a term slug
$term = get_term_by('slug', $term_slug, $taxonomy);
$terms_name[] = ! is_a($term, 'WP_Term') ? $term_slug : $term->name;
}
$attributes[] = $taxonomy_label . ': ' . implode( ', ', $terms_name );
}
echo '<div class="product-attributes">';
echo '<span>' . implode('</span><br><span>', $attributes) . '</span>';
echo '</div>';
}
Code goes in function.php file of your active child theme (active theme). Tested and works.
Related
I have set up an attribute for my products for a delivery time. And I am using the following functions to display it on product archives, on single product pages, on Orders and emails notifications:
add_action( 'woocommerce_single_product_summary', 'product_attribute_delivery', 27 );
function product_attribute_delivery(){
global $product;
$taxonomy = 'pa_delivery';
$value = $product->get_attribute( $taxonomy );
if ( $value && $product->is_in_stock() ) {
$label = get_taxonomy( $taxonomy )->labels->singular_name;
echo '<small>' . $label . ': ' . $value . '</small>';
}
}
add_action('woocommerce_order_item_meta_end', 'custom_item_meta', 10, 4 );
function custom_item_meta($item_id, $item, $order, $plain_text)
{ $productId = $item->get_product_id();
$product = wc_get_product($productId);
$taxonomy = 'pa_delivery';
$value = $product->get_attribute($taxonomy);
if ($value) {
$label = get_taxonomy($taxonomy)->labels->singular_name;
echo '<small>' . $label . ': ' . $value . '</small>';
}
}
add_action( 'woocommerce_after_shop_loop_item', 'product_attribute_delivery_shop', 1 );
function product_attribute_delivery_shop(){
global $product;
$taxonomy = 'pa_delivery';
$value = $product->get_attribute( $taxonomy );
if ( $value && $product->is_in_stock() ) {
$label = get_taxonomy( $taxonomy )->labels->singular_name;
echo '<small>' . $label . ': ' . $value . '</small>';
}
}
I have two questions:
Is there a way o combine these functions to optimize and clean up the code?
For the archive page (but not the single product page!) I want the text to change when the product is not on stock. Instead of not being displayed at all, I would like it to be "Sold Out".
Note that the rule on StackOverFlow is one question at the time. You can use a custom function that you will call on each hooked function like:
// Custom function that handle the code to display a product attribute
function custom_display_attribute( $product, $taxonomy = 'pa_delivery') {
$value = $product->get_attribute( $taxonomy );
if ( ! empty($value) && $product->is_in_stock() ) {
$label = wc_attribute_label( $taxonomy );
echo '<small>' . $label . ': ' . $value . '</small>';
}
}
// On product archive pages
add_action( 'woocommerce_after_shop_loop_item', 'product_attribute_delivery_archives', 1 );
function product_attribute_delivery_archives() {
global $product;
custom_display_attribute( $product );
// When product is out of stock displays "Sold Out"
if ( ! $product->is_in_stock() ) {
echo __("Sold Out", "woocommerce");
}
}
// On product single pages
add_action( 'woocommerce_single_product_summary', 'product_attribute_delivery_single', 27 );
function product_attribute_delivery_single() {
global $product;
custom_display_attribute( $product );
}
// On orders and email notifications
add_action('woocommerce_order_item_meta_end', 'custom_item_meta', 10, 4 );
function custom_item_meta( $item_id, $item, $order, $plain_text ) {
custom_display_attribute( wc_get_product( $item->get_product_id() ) );
}
It should works.
On archive pages only when product is not in stock, it will displays "Sold Out".
I want to add some attributes to the shop page of wordpress.
This code i found on Stackoverflow, is shows all attribute labes but on all the same attribute names.
add_action('woocommerce_after_shop_loop_item_title','add_attribute');
function add_attribute() {
global $product;
$product_attributes = array( 'pa_country','pa_class','pa_faction','pa_gender' );
$attr_output = array();
foreach( $product_attributes as $taxonomy ){
if( taxonomy_exists($taxonomy) ){
$label_name = get_taxonomy( $taxonomy )->labels->singular_name;
$value = $product->get_attribute('pa_country','pa_class','pa_faction','pa_gender');
if( ! empty($value) ){
$attr_output[] = '<span class="'.$taxonomy.'">'.$label_name.': '.$value.'</span>';
}
}}
echo '<div class="product-attributes">'.implode( '<br>', $attr_output ).'</div>';
}
current state
I just need a bit help to get it to show all the right attributes.
There a some little mistakes in your code. Try the following instead:
add_action('woocommerce_after_shop_loop_item_title', 'display_shop_loop_product_attributes');
function display_shop_loop_product_attributes() {
global $product;
// Define you product attribute taxonomies in the array
$product_attribute_taxonomies = array( 'pa_country', 'pa_class', 'pa_faction', 'pa_gender' );
$attr_output = array(); // Initializing
// Loop through your defined product attribute taxonomies
foreach( $product_attribute_taxonomies as $taxonomy ){
if( taxonomy_exists($taxonomy) ){
$label_name = wc_attribute_label( $taxonomy, $product );
$term_names = $product->get_attribute( $taxonomy );
if( ! empty($term_names) ){
$attr_output[] = '<span class="'.$taxonomy.'">'.$label_name.': '.$term_names.'</span>';
}
}
}
// Output
echo '<div class="product-attributes">'.implode( '<br>', $attr_output ).'</div>';
}
Code goes in functions.php file of your active child theme (or active theme). tested and works.
For simple products only you will use the following instead:
add_action('woocommerce_after_shop_loop_item_title', 'display_shop_loop_product_attributes');
function display_shop_loop_product_attributes() {
global $product;
// Only for simple products
if ( ! $product->is_type( 'simple' ) ) return;
// Define you product attribute taxonomies in the array
$product_attribute_taxonomies = array( 'pa_country', 'pa_class', 'pa_faction', 'pa_gender' );
$attr_output = array(); // Initializing
// Loop through your defined product attribute taxonomies
foreach( $product_attribute_taxonomies as $taxonomy ){
if( taxonomy_exists($taxonomy) ){
$label_name = wc_attribute_label( $taxonomy, $product );
$term_names = $product->get_attribute( $taxonomy );
if( ! empty($term_names) ){
$attr_output[] = '<span class="'.$taxonomy.'">'.$label_name.': '.$term_names.'</span>';
}
}
}
// Output
echo '<div class="product-attributes">'.implode( '<br>', $attr_output ).'</div>';
}
Code goes in functions.php file of your active child theme (or active theme). tested and works.
I solved the problem. its not pretty but it works.
add_action( 'woocommerce_after_shop_loop_item_title', 'display_size_attribute', 5 );
function display_size_attribute() {
global $product;
if ( $product->is_type('simple') ) {
$taxonomy = 'pa_country';
echo '<span class="attribute-s">Country: ' . $product->get_attribute($taxonomy) . '</span>','<br>';
}
if ( $product->is_type('simple') ) {
$taxonomy = 'pa_class';
echo '<span class="attribute-s">Class: ' . $product->get_attribute($taxonomy) . '</span>','<br>';
}
if ( $product->is_type('simple') ) {
$taxonomy = 'pa_faction';
echo '<span class="attribute-s">Faction: ' . $product->get_attribute($taxonomy) . '</span>','<br>';
}
if ( $product->is_type('simple') ) {
$taxonomy = 'pa_gender';
echo '<span class="attribute-s">Gender: ' . $product->get_attribute($taxonomy) . '</span>','<br>';
}}
I am trying to add Publisher, Topic and Author to a Single Product with help of categories/subcategories. This is how it looks after hours of coding/and copying (very fresh with WooCommerce tbh)
This is what I am getting, but it shows ALL subcategories, not only the ones associated to the Product, this is the code I am using
function get_product_subcategories_list( $category_slug ){
$terms_html = array();
$taxonomy = 'product_cat';
// Get the product category (parent) WP_Term object
$parent = get_term_by( 'slug', $category_slug, $taxonomy );
// Get an array of the subcategories IDs (children IDs)
$children_ids = get_term_children( $parent->term_id, $taxonomy );
// Loop through each children IDs
foreach($children_ids as $children_id){
$term = get_term( $children_id, $taxonomy ); // WP_Term object
$term_link = get_term_link( $term, $taxonomy ); // The term link
if ( is_wp_error( $term_link ) ) $term_link = '';
// Set in an array the html formated subcategory name/link
$terms_html[] = '' . $term->name . '';
}
return '<span class="subcategories-' . $category_slug . '">' . implode( ', ', $terms_html ) . '</span>';
}
add_action('woocommerce_single_product_summary','monolith_cat_scan', 31);
function monolith_cat_scan() {
echo '<p>Topic : ';
echo get_product_subcategories_list( 'topics' );
echo '</p>';
echo '<p>Publisher : ';
echo get_product_subcategories_list( 'publishers' );
echo '</p>';
echo '<p>Author: ';
echo get_product_subcategories_list( 'authors' );
echo '</p>';
}
But I can't get the whole thing to work like I want to and get the subcategories of the Single Product, in this example only Spirituality, SOUNDS TRUE INC (only sub cat in Publishers), and Allan Watts should be there.
I'd appreciate every help!
I got a working code (it doesn't look beautiful I know but it's the best I could do and it does the trick.
add_action('woocommerce_single_product_summary','monolith_cat_scan', 31);
function monolith_cat_scan() {
global $post;
$cats = get_the_terms( $post->ID, 'product_cat' );
if ( ! empty( $cats ) ) {
foreach ( $cats as $term ) {
if( $term->parent == 30 ) {
echo '<p>Topic : ' . $term->name . '';
}
}
}
}
add_action('woocommerce_single_product_summary','monolith_cat_scan2', 32);
function monolith_cat_scan2() {
global $post;
$cats = get_the_terms( $post->ID, 'product_cat' );
if ( ! empty( $cats ) ) {
foreach ( $cats as $term ) {
if( $term->parent == 31 ) {
echo '<p>Author : ' . $term->name . '';
}
}
}
}
add_action('woocommerce_single_product_summary','monolith_cat_scan3', 33);
function monolith_cat_scan3() {
global $post;
$cats = get_the_terms( $post->ID, 'product_cat' );
if ( ! empty( $cats ) ) {
foreach ( $cats as $term ) {
// If parent cat ID = 116 echo subcat name...
if( $term->parent == 32 ) {
echo '<p>Publisher : ' . $term->name . '';
}
}
}
}
I need an imploded list of terms from three custom Woocommerce taxonomies including the taxonomy name to display in the product loop. I'll also need to be able to display multiple terms for each taxonomy. However, I can only get it to work with one taxonomy. And I can't figure out how to display the corresponding taxonomy name.
My custom taxonomies are 'artists', 'illustrators' and 'authors'. Here's what I'm trying to accomplish:
Robert Douglas (Author), Bill Johnston (Illustrator), Kyle McBeth (Artist)
function list_author_terms() {
global $post;
$person = get_the_terms(get_the_ID(), 'authors', 'artists', 'illustrators');
if ( $person
&& !is_wp_error( $person )
) {
#usort( $person, function ( $a, $b )
{
return strcasecmp(
$a->slug,
$b->slug
);
});
// Display your terms as normal
$term_list = [];
foreach ( $person as $term )
$term_list[] = '' . esc_html( $term->name ) . '<span class="attribute"> (Author)</span> ';
$term_names[] = $term->name;
echo implode( ', ', $term_list);
echo '<br>';
}
}
Add follows code snippet to achieve your task -
add_action( 'woocommerce_after_shop_loop_item', 'list_author_terms', 6 );
function list_author_terms(){
$taxonomies = array( 'authors', 'artists', 'illustrators' );
$pro_list_terms = array();
foreach ( $taxonomies as $taxonomy ) {
$term_obj_list = get_the_terms( get_the_ID(), $taxonomy );
$tax_obj = get_taxonomy( $taxonomy );
if( $term_obj_list && ! is_wp_error( $term_obj_list ) ){
foreach ( $term_obj_list as $term ) {
$link = get_term_link( $term, $taxonomy );
$pro_list_terms[] = '' . $term->name . ' (' .$tax_obj->labels->singular_name . ')';
}
}
}
echo join( ', ', $pro_list_terms );
}
I want to make some modification of my site, but for some reason, can get it. i tryed to use this function that found into this thread of Stack :
add_filter( 'woocommerce_variation_option_name',
'customizing_variations_terms_name', 10, 1 );
function customizing_variations_terms_name( $term_name ){
if(is_admin())
return $term_name;
global $product;
$second_loop_stoped = false;
// Get available product variations
$product_variations = $product->get_available_variations();
// Iterating through each available product variation
foreach($product_variations as $variation){
$variation_id = $variation['variation_id'];
$variation_obj = new WC_Product_Variation( $variation_id );
## WOOCOMMERCE RETRO COMPATIBILITY ##
if ( version_compare( WC_VERSION, '3.0', '<' ) ) # BEFORE Version 3 (older)
{
$stock_status = $variation_obj->stock_status;
$stock_qty = intval($variation_obj->stock);
// The attributes WC slug key and slug value for this variation
$attributes_arr = $variation_obj->get_variation_attributes();
}
else # For newest verions: 3.0+ (and Up)
{
$stock_status = $variation_obj->get_stock_status();
$stock_qty = $variation_obj->get_stock_quantity();
// The attributes taxonomy key and slug value for this variation
$attributes_arr = $variation_obj->get_attributes();
}
if(count($attributes_arr) != 1) // Works only for 1 attribute set in the product
return $term_name;
// Get the terms for this attribute
foreach( $attributes_arr as $attr_key => $term_slug){
// Get the attribute taxonomy
$term_key = str_replace('attribute_', '', $attr_key );
// get the corresponding term object
$term_obj = get_term_by( 'slug', $term_slug, $term_key );
if( $term_obj->name == $term_name ){ // If the term name matches we stop the loops
$second_loop_stoped = true;
break;
}
}
if($second_loop_stoped)
break;
}
if( $stock_qty>0 )
return $term_name .= ' - ' . $stock_status . ' ('.$stock_qty.')';
else
return $term_name .= ' - ' . $stock_status;
}
but for some reason when insert into functions, show me "outofstock" next to every variation. I dont use standard Woocommerce dropdown variation style, and use WC Variations Radio Buttons to show radio buttons next to each variation, instead of dropdown. The problem is that i want to show only "Out Of Stock" , next to each variation. not "In Stock", so customer will know that wanted variation is not in stock before press Add to Cart button. SO seems that issue is this code:
if( $stock_qty>0 )
return $term_name .= ' - ' . $stock_status . ' ('.$stock_qty.')';
else
return $term_name .= ' - ' . $stock_status;
}
function looks like return
return $term_name .= ' - ' . $stock_status;
all the time. Any help ? Preview from my issue can be seen here. Thanks.
EDIT: This is the code from variable.php Radio Button Plugin where print variations as radio buttons:
<td class="value">
<?php
if ( ! empty( $options ) ) {
if ( taxonomy_exists( $name ) ) {
// Get terms if this is a taxonomy - ordered. We need the names too.
$terms = wc_get_product_terms( $product->get_id(), $name, array( 'fields' => 'all' ) );
foreach ( $terms as $term ) {
if ( ! in_array( $term->slug, $options ) ) {
continue;
}
print_attribute_radio( $checked_value, $term->slug, $term->name, $sanitized_name );
}
} else {
foreach ( $options as $option ) {
print_attribute_radio( $checked_value, $option, $option, $sanitized_name );
}
}
}
echo end( $attribute_keys ) === $name ?
apply_filters( 'woocommerce_reset_variations_link', '<a
class="reset_variations" href="#">' . __( 'Clear', 'woocommerce' ) . '</a>'
) : '';
?>
</td>
Maybe need to update something there to show properly?
do this instead
if( $stock_qty>0 )
//return $term_name .= ' - ' . $stock_status . ' ('.$stock_qty.')';
return $term_name;
else
//return $term_name .= ' - ' . $stock_status;
return $term_name .= ' - Out Of Stock';