In a Wordpress + Woocommerce website I have a menu with some custom links that recall specific shop pages URLs using advanced queries taxonomies.
These are example links I use for these custom menu entries:
https://example.com/product-category/cat1/?pa_attrib1=value1&pa_attrib2=value3
https://example.com/product-category/cat2/?pa_attrib1=value2&pa_attrib3=value4`
https://example.com/product-category/cat2/?pa_attrib1=value5&pa_attrib4=value5,value7,value8,value9
In this way I can configure "direct" entries to the various shop departments.
Now I need to show, in the shop and archive page, the name and the values of the attributes set in the url in a similar way:
Category Name - Attribute 1 name: value1 - Atttribute 2 Name: value2, ...
I suppose I need to use the hook woocommerce_archive_description in functions.php but I don't know how recall and show the values I need
add_action ( 'woocommerce_archive_description', 'show_term_description', 20 );
function show_term_description() {
echo term_description( $term_id, $taxonomy ); // print Category Name
// ...
// ...
}
thanks
This can be done with the following commented code inserted in your hooked function:
add_action ( 'woocommerce_archive_description', 'show_term_description', 20 );
function show_term_description() {
// Only for product category archive pages
if( ! is_product_category()) return;
global $wp;
// Get the requested Url category/subcategories
$request = $wp->request;
// Set them in an array
$request = explode( '/', $request );
// Remove 'product-category' from the array
if( 'product-category' == $request[0] )
unset($request[0]);
// Starting html formatting
$html = '<p><strong>';
// The main category and sub-categories names
foreach( $request as $category ){
// Get the category name
$category_term = get_term_by( 'slug', $category, 'product_cat' );
// Set category and subcategories in an array
$categories_name[] = $category_term->name;
}
// Formatting the category/subcategories in an html string
$html .= implode( '</strong> - <strong>', $categories_name );
// The product attributes names and related values
if( ! empty($_GET) ){
$html .= '</strong> - <strong>'; // Formatting html
$count = 0; // Initializing the counter
$attr_count = count($_GET); // get the length of the array
// Loop through the attribute/values from the $_GET
foreach($_GET as $taxonomy => $values ){
$count++;
$terms_names = array(); // Initializing
// If the taxonomy doesn't exist,
if( ! taxonomy_exists( $taxonomy ) ){
continue; // We go to next attribute
}
// Set the attribute terms in an array
$term_slugs = explode( ',', $values );
// Loop through the attribute term
foreach( $term_slugs as $term_slug ){
// Get the WP_Term object
$term = get_term_by( 'slug', $term_slug, $taxonomy );
if( ! term_exists( $term->term_id, $taxonomy ) )
continue; // We go to next term
// Set The term name in an array
$terms_names[] = $term->name;
}
// If there is no corresponding terms for the taxonomy
if( sizeof($terms_names) == 0 ){
continue; // We go to next attribute
}
// Add the attribute label name to the output
if( $count > 1 ) $html .= ' - ';
$html .= wc_attribute_label( $taxonomy );
// Formatting the term names in a string and add them to the output
$html .= ':</strong> ' . implode( ', ', $terms_names) . '<strong>';
}
}
// Outputing The html
echo $html.'</p>';
echo $attr_count .' | '.$count;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works…
Related
I display the breadcrumbs inside my product pages. I am trying to manually replace the category link of "Horlogerie" with a custom link '/test'.
Here is my code using this answer :
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 10, 2 );
function custom_breadcrumb( $crumbs, $object_class ){
// Loop through all $crumb
var_dump($crumbs);
foreach( $crumbs as $key => $crumb ){
$taxonomy = 'product_cat'; // The product category taxonomy
// Check if it is a product category term
$term_array = term_exists( $crumb[0], $taxonomy );
// if it is a product category term
if ( $term_array !== 0 && $term_array !== null ) {
// Get the WP_Term instance object
$term = get_term( $term_array['term_id'], $taxonomy );
// HERE set your new link with a custom one
$crumbs[$key][1] = 'test';
}
}
return $crumbs;
}
But the link doesn't get changed. I tried using the "Twenty Twenty-one" theme, but the problem persists.
Thank you for your help.
You have simply just added one condition. try the below code.
function custom_breadcrumb( $crumbs, $object_class ){
// Loop through all $crumb
var_dump($crumbs);
foreach( $crumbs as $key => $crumb ){
$taxonomy = 'product_cat'; // The product category taxonomy
// Check if it is a product category term
$term_array = term_exists( $crumb[0], $taxonomy );
// if it is a product category term
if ( $term_array !== 0 && $term_array !== null ) {
// Get the WP_Term instance object
$term = get_term( $term_array['term_id'], $taxonomy );
if( $term->name == 'your specific term name' ){
// HERE set your new link with a custom one
$crumbs[$key][1] = 'test';
}
}
}
return $crumbs;
}
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 10, 2 );
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.
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[] = ''.$term->name.'';
}
}
// 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[] = ''.$term->name.'';
by this:
$option_values[] = $term->name;
Please pardon me if there's a better way to do this as I am not very familiar with this code. I would like to display only the link to the homepage and the current product on the breadcrumb.
Desire result:
Currently:
I found the code for the breadcrumb, is there a way to only display the first and last crumb regardless of the hierarchy?
foreach ( $breadcrumb as $key => $crumb ) {
echo $before;
if ( ! empty( $crumb[1] ) && sizeof( $breadcrumb ) !== $key ) {
echo '' . esc_html( $crumb[0] ) . '';
} else if(!is_product() && !flatsome_option('wc_category_page_title')) {
echo esc_html( $crumb[0] );
}
echo $after;
// Single product or Active title
if(is_product() || flatsome_option('wc_category_page_title')){
$key = $key+1;
if ( sizeof( $breadcrumb ) > $key) {
echo ' <span class="divider">'.$delimiter.'</span> ';
}
} else{
// Category pages
if ( sizeof( $breadcrumb ) !== $key + 1 ) {
echo ' <span class="divider">'.$delimiter.'</span> ';
}
}
}
The reason why I am doing this is that some of the products have multiple categories and by default, it will only show the breadcrumb for the primary category. I would rather make a truncated version as suggested by the owner.
I was also wondering if I can simply dynamically retrieve the product title and link + static homepage link, make it into a shortcode so that I can paste it in the product page.
Hi – the first example in the answer above, also removes the shop from woocommerce breadcrumb. Here is a working example, that only removes the category:
// remove only the category from woocommerce breadcrumbs
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 20, 2 );
function custom_breadcrumb( $crumbs, $breadcrumb ) {
//print the array and look for the key with the category
//echo '<pre>';
//print_r($crumbs);
//echo '</pre>';
//unset($crumbs[2]); in my case it is key 2
// only on the single product page
if ( ! is_product() ) {
return $crumbs;
} else {
unset($crumbs[2]); // this isn't enough, it would leave a trailing delimiter
$newBreadC = array_values($crumbs); //therefore create new array
return $newBreadC; //return the new array
}
}
If you want to remove categories and subcategories from product breadcrumbs on the product page you can use the woocommerce_get_breadcrumb hook.
// change the breadcrumb on the product page
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 20, 2 );
function custom_breadcrumb( $crumbs, $breadcrumb ) {
// only on the single product page
if ( ! is_product() ) {
return $crumbs;
}
// gets the first element of the array "$crumbs"
$new_crumbs[] = reset( $crumbs );
// gets the last element of the array "$crumbs"
$new_crumbs[] = end( $crumbs );
return $new_crumbs;
}
The code has been tested and works. Add it to your active theme's functions.php.
A good alternative is to set the primary product category for each product. You can do this by installing the Yoast SEO plugin.
You can use the _yoast_wpseo_primary_product_cat product meta to set the id of the primary product category.
After setting the primary category id by editing the product in the
backend or importing a .csv file you will only need to change the
permalink and breadcrumbs based on the primary product category.
To update the product permalink:
// update the product permalink based on the primary product category
add_filter( 'wc_product_post_type_link_product_cat', 'change_product_permalink_by_cat', 10, 3 );
function change_product_permalink_by_cat( $term, $terms, $post ) {
// get the primary term as saved by Yoast
$primary_cat_id = get_post_meta( $post->ID, '_yoast_wpseo_primary_product_cat', true );
// if there is a primary and it's not currently chosen as primary
if ( $primary_cat_id && $term->term_id != $primary_cat_id ) {
// find the primary term in the term list
foreach ( $terms as $term_key => $term_object ) {
if ( $term_object->term_id == $primary_cat_id ) {
// return this as the primary term
$term = $terms[ $term_key ];
break;
}
}
}
return $term;
}
To update the product breadcrumbs on the product page:
// change the breadcrumb on the product page
add_filter( 'woocommerce_get_breadcrumb', 'custom_breadcrumb', 20, 2 );
function custom_breadcrumb( $crumbs, $breadcrumb ) {
// only on the single product page
if ( ! is_product() ) {
return $crumbs;
}
global $product;
$new_crumbs = array();
if ( $product->get_meta( '_yoast_wpseo_primary_product_cat', true ) ) {
// gets the first element of the array "$crumbs"
$new_crumbs[] = reset( $crumbs );
// gets the id of the primary product category
$primary_cat_id = $product->get_meta( '_yoast_wpseo_primary_product_cat', true );
// create an array with all parent categories (based on the id of the primary product category)
$parent_categories = get_ancestors( $primary_cat_id, 'product_cat' );
$parent_categories = array_reverse($parent_categories);
$parent_categories[] = $primary_cat_id;
// for each product category it gets the name and the permalink
foreach ( $parent_categories as $cat_id ) {
$term = get_term_by( 'id', $cat_id, 'product_cat' );
$new_crumbs[] = array(
0 => $term->name,
1 => esc_url( get_term_link( $term, 'product_cat' ) )
);
}
// gets the last element of the array "$crumbs"
$new_crumbs[] = end( $crumbs );
} else {
// gets the first element of the array "$crumbs"
$new_crumbs[] = reset( $crumbs );
// gets the last element of the array "$crumbs"
$new_crumbs[] = end( $crumbs );
}
return $new_crumbs;
}
The code has been tested and works. Add it to your active theme's functions.php.
This is my code for display an atributte below a product title. How can I display it like a link to archive page of this attributte?
add_action( 'woocommerce_single_product_summary', 'custom_template_single_title', 5 );
function custom_template_single_title() {
global $product;
$brand_name = $product->get_attribute('Autor');
echo '<div class ="author-product">';
if( $brand_name )
echo $brand_name;
echo '</div>';
}
First, $product->get_attribute('Autor') can give multiple coma separated term names.
Below, we add the term link to each term name (if there is more than one):
add_action( 'woocommerce_single_product_summary', 'custom_template_single_title', 5 );
function custom_template_single_title() {
global $product;
$taxonomy = 'pa_autor'; // <== The product attribute taxonomy
$linked_terms = []; // Initializing
if ( $term_names = $product->get_attribute($taxonomy) ) {
// Loop through the term names
foreach( explode(', ', $term_names) as $term_name ) {
$term_id = get_term_by('name', $term_name, $taxonomy)->term_id; // get the term ID
$term_link = get_term_link( $term_id, $taxonomy ); // get the term link
$linked_terms[] = '' . $term_name . '';
}
// Output
echo '<div class ="author-product">' . implode(', ', $linked_terms) . '</div>';
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
I want to show two attributes on the category pages, with the attribute name and value only on specific categories.
This code that I found displays the labels of the attributes, but is duplicating the value and I am really struggling with a show if categories variable. Any help is greatly appreciated.
The code:
add_action('woocommerce_after_shop_loop_item','add_attribute');
function add_attribute() {
global $product;
$product_attributes = array( 'pa_set', 'pa_team');
$attr_output = array();
// Loop through the array of product attributes
foreach( $product_attributes as $taxonomy ){
if( taxonomy_exists($taxonomy) ){
$label_name = get_taxonomy( $taxonomy )->labels->singular_name;
$value = $product->get_attribute('pa_set');
if( ! empty($value) ){
// Storing attributes for output
$attr_output[] = '<span class="'.$taxonomy.'">'.$label_name.':
'.$value.'</span>';
}
}
}
// Output attribute name / value pairs separate by a "<br>"
echo '<div class="product-attributes">'.implode( '<br>', $attr_output
).'</div>';
}
Updated - The problem comes from the following line, where the product attribute attribute value is always for the same product attribute:
$value = $product->get_attribute( 'pa_set' );
and it should be this instead:
$value = $product->get_attribute( $taxonomy );
The complete revisited code will be:
add_action('woocommerce_after_shop_loop_item','display_loop_product_attribute' );
function display_loop_product_attribute() {
global $product;
$product_attributes = array('pa_set', 'pa_team'); // Defined product attribute taxonomies.
$attr_output = array(); // Initializing
// Loop through the array of product attributes
foreach( $product_attributes as $taxonomy ){
if( taxonomy_exists($taxonomy) ){
if( $value = $product->get_attribute($taxonomy) ){
// The product attribute label name
$label_name = wc_attribute_label($taxonomy);
// Storing attributes for output
$attr_output[] = '<span class="'.$taxonomy.'">'.$label_name.': '.$value.'</span>';
}
}
}
// Output attribute name / value pairs separate by a "<br>"
echo '<div class="product-attributes">'.implode('<br>', $attr_output).'</div>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Targeting Product category archive pages:
You will use the conditional tag is_product_category() inside the function on an IF statement…
For specific product category archive pages, you can set them as explained here inside the function in an array, like:
if( is_product_category( array('chairs', 'beds') ) {
// Here go the code to be displayed
}
You will just need to set the right product categories slugs in the array…
Related: Show WooCommerce product attributes in custom home and product category archives