I'm wanting to display custom ACF fields in a product within the order complete e-mail, I have this hook which works great for none-variable products:
add_filter( 'woocommerce_order_item_name', 'custom_order_item_name', 10, 2 );
function custom_order_item_name( $item_name, $item ) {
// Targeting email notifications only
if( is_wc_endpoint_url() )
return $item_name;
// Get the WC_Product object (from order item)
$product = $item->get_product();
if( $date = get_field('date', $product->get_id()) ) {
$item_name .= '<br /><strong>' . __( 'Date', 'woocommerce' ) . ': </strong>' . $date;
}
if( $location = get_field('location', $product->get_id()) ) {
$item_name .= '<br /><strong>' . __( 'Location', 'woocommerce' ) . ': </strong>' . $location;
}
return $item_name;
}
However, while it displays my custom fields (date and location) fine for simple products within the e-mail, it does not for variable products.
I can't seem to understand why?
I found the solution.
When it is a simple product, the product ID is the post ID. However when it is a variable product, they then use a variable product ID, not the post ID. Which means the ACF fields are not looking at the post ID of the product, so won't display.
To fix this for variable products you must get the parent ID from the array:
$parent_id=$product->get_parent_id();
// If it is a variable product, get the parent ID
if($parent_id){
$product_id = $parent_id;
// else, it is a simple product, get the product ID
}else{
$product_id = $product->get_id();
}
Full code is:
// Display Items Shipping ACF custom field value in email notification
add_filter( 'woocommerce_order_item_name', 'custom_order_item_name', 10, 2 );
function custom_order_item_name( $item_name, $item ) {
// Targeting email notifications only
if( is_wc_endpoint_url() )
return $item_name;
// Get the WC_Product object (from order item)
$product = $item->get_product();
$parent_id=$product->get_parent_id();
// If it is a variable product, get the parent ID
if($parent_id){
$product_id = $parent_id;
// else, it is a simple product, get the product ID
}else{
$product_id = $product->get_id();
}
if( $date = get_field('date', $product_id) ) {
$item_name .= '<br /><strong>' . __( 'Date', 'woocommerce' ) . ': </strong>' . $date;
}
if( $location = get_field('location', $product_id) ) {
$item_name .= '<br /><strong>' . __( 'Location', 'woocommerce' ) . ': </strong>' . $location;
}
return $item_name;
}
Related
Is there any way to replace range price of variable products in woocommerce on shop page and instead of it showing a list of variations and their prices per product in order to display variations to customer and showing 'Add to Cart' for all type of products not 'Choose an Option' for variable products.
I have tested a lot of code snippets without success.
Below code is the closest to what I need, I used code suggested here Get specific product attribute name and value for each WooCommerce variation of a variable product and changed it. but still the problem is that part of attribute is not shown.
add_filter( 'woocommerce_variable_price_html', 'custom_variable_price_html', 10, 2 );
function custom_variable_price_html( $price, $product ) {
if(!is_admin()){
if(is_shop()){
$product_attribute_slug = 'ابعاد-فرش';
$targeted_taxonomy = 'pa_' . $product_attribute_slug;
$available_variations = $product->get_available_variations();
$output = '<div>';
foreach( $available_variations as $variation_data ){
if( $variation_data['display_price'] === $variation_data['display_regular_price'] ) {
$price_to_display = wc_price( $variation_data['display_price'] );
} else {
$variation = wc_get_product($variation_data['variation_id']); // Get the WC_Product_Variation Object
$price_to_display = wc_get_price_to_display( $variation, array('price' => $variation->get_sale_price() ) );
}
foreach ( $variation_data['attributes'] as $variation_attribute => $term_slug ) {
// Get the taxonomy slug
$taxonomy = str_replace( 'attribute_', '', $variation_attribute );
// Get the correct product attribute term value for this variation
if( $taxonomy === $targeted_taxonomy ) {
// Get the attribute value term name
$term_name = get_term_by( 'slug', $term_slug, $taxonomy )->name;
}
}
$output .= '<span>' . $term_name . ':' . wc_attribute_label( $targeted_taxonomy ) . ':' . strip_tags($price_to_display) . '</span><br>';
}
$output .= '</div>';
$price = $output;
return $price;
} else {
return $price;
}
} else {
return $price;
}
}
what I get is:
but I need something Like this:
As I noticed
$term_name
variable in code is empty.
Any help is appreciated.
Solution: set taxonomy as follow and use it in get_term_by() function:
$taxonomy = 'pa_ابعاد-فرش';
Based on "Show woocommerce product custom fields under the cart and order item name" answer to one of my previous questions, The code shows custom fields on the product edit page. When these fields are filled in, data is displayed on the product page.
Here is the code:
// Backend: Display additional product fields
add_action('woocommerce_product_options_general_product_data', 'add_fields_to_options_general_product_data');
function add_fields_to_options_general_product_data() {
// Custom Weight Field
woocommerce_wp_text_input(array(
'id' => '_custom_weight',
'label' => __('Weight dishes', 'woocommerce'),
));
// Calories Field
woocommerce_wp_text_input(array(
'id' => '_сalories',
'label' => __('Calories', 'woocommerce'),
));
// Ingredients Field
woocommerce_wp_textarea_input(array(
'id' => '_ingredients',
'label' => __('Ingredients', 'woocommerce'),
));
}
// Backend: Save the data value from the custom fields
add_action('woocommerce_admin_process_product_object', 'save_admin_product_custom_fields_values');
function save_admin_product_custom_fields_values($product) {
// Save Custom Weight Field
if (isset($_POST['_custom_weight'])) {
$product->update_meta_data('_custom_weight', sanitize_text_field($_POST['_custom_weight']));
}
// Save Calories Field
if (isset($_POST['_сalories'])) {
$product->update_meta_data('_сalories', sanitize_text_field($_POST['_сalories']));
}
// Save Ingredients Field
if (isset($_POST['_ingredients'])) {
$product->update_meta_data('_ingredients', sanitize_textarea_field($_POST['_ingredients']));
}
}
// Display product custom fields values on single product pages under short description and on archive pages
add_action('woocommerce_before_add_to_cart_form', 'display_custom_meta_field_value', 25);
add_action('woocommerce_after_shop_loop_item', 'display_custom_meta_field_value', 25);
function display_custom_meta_field_value() {
global $product;
if ($custom_weight = $product->get_meta('_custom_weight'))
echo '<p id="value-on-single-product">'.__("Weight:", "woocommerce").
' '.$custom_weight.
'g'.
'</p>';
if ($сalories = $product->get_meta('_сalories'))
echo '<p id="value-on-single-product">'.__("Calories:", "woocommerce").
' '.$сalories.
' kcal.'.
'</p>';
if ($ingredients = $product->get_meta('_ingredients'))
echo '<p id="value-on-single-product">'.__("Ingredients:", "woocommerce").
' '.$ingredients.
'</p>';
}
// Add custom fields values under cart item name in cart
add_filter('woocommerce_cart_item_name', 'custom_cart_item_name', 10, 3);
function custom_cart_item_name($item_name, $cart_item, $cart_item_key) {
if (!is_cart())
return $item_name;
if ($value1 = $cart_item['data']->get_meta('_custom_weight')) {
$item_name. = '<br><span class="custom-field"><strong>'.__("Weight", "woocommerce").
':</strong> '.$value1.
'g</span>';
}
if ($value2 = $cart_item['data']->get_meta('_сalories')) {
$item_name. = '<br><span class="custom-field"><strong>'.__("Calories", "woocommerce").
':</strong> '.$value2.
'kcal</span>';
}
if ($value3 = $cart_item['data']->get_meta('_ingredients')) {
$item_name. = '<br><span class="custom-field"><strong>'.__("Ingredients", "woocommerce").
':</strong> <br>'.$value3.
'</span>';
}
return $item_name;
}
// Display custom fields values on orders and email notifications
add_filter('woocommerce_order_item_name', 'custom_order_item_name', 10, 2);
function custom_order_item_name($item_name, $item) {
$product = $item - > get_product();
if ($value1 = $product->get_meta('_custom_weight')) {
$item_name. = '<br><span class="custom-field"><strong>'.__("Weight", "woocommerce").
':</strong> '.$value1.
'g</span>';
}
if ($value2 = $product->get_meta('_сalories')) {
$item_name. = '<br><span class="custom-field"><strong>'.__("Calories", "woocommerce").
':</strong> '.$value2.
'kcal</span>';
}
if ($value3 = $product->get_meta('_ingredients')) {
$item_name. = '<br><span class="custom-field"><strong>'.__("Ingredients", "woocommerce").
':</strong> <br>'.$value3.
'</span>';
}
return $item_name;
}
How to display custom fields on the edit order page in the admin panel? It is supposed to show these fields after the product name.
UPDATE
As I understand it, woocommerce_checkout_create_order_line_item is responsible for this. But I can't add the correct code. I ask for your help!
// Save chosen slelect field value to each order item as custom meta data and display it everywhere
add_action('woocommerce_checkout_create_order_line_item', 'save_order_item_product', 10, 4 );
function save_order_item_product( $item, $cart_item_key, $values, $order ) {
$product = $item->get_product();
if( $value1 = $product->get_meta('_custom_weight') ) {
$item_name .= '<br /><span class="custom-field"><strong>' . __("Weight dishes", "woocommerce") . ':</strong> ' . $value1 . ' g</span>';
}
return $item_name;
}
or
// Save chosen slelect field value to each order item as custom meta data and display it everywhere
add_action('woocommerce_checkout_create_order_line_item', 'save_order_item_product', 10, 4 );
function save_order_item_product( $item, $cart_item_key, $values, $order ) {
if( isset($values['_custom_weight']) ) {
$key = __('Weight dishes', 'woocommerce');
$value = $values['_custom_weight'];
$item->update_meta_data( $key, $value );
}
}
Here is the way to display your product custom fields on admin order items:
add_action( 'woocommerce_before_order_itemmeta', 'add_admin_order_item_custom_fields', 10, 2 );
function add_admin_order_item_custom_fields( $item_id, $item ) {
// Targeting line items type only
if( $item->get_type() !== 'line_item' ) return;
$product = $item-> get_product();
$value1 = $product->get_meta('_custom_weight');
$value2 = $product->get_meta('_сalories');
$value3 = $product->get_meta('_ingredients');
if ( ! empty($value1) || ! empty($value2) || ! empty($value3) ) {
echo '<table cellspacing="0" class="display_meta">';
if ( ! empty($value1) ) {
echo '<tr><th>' . __("Weight", "woocommerce") . ':</th><td>' . $value1 . 'g</td></tr>';
}
if ( ! empty($value2) ) {
echo '<tr><th>' . __("Calories", "woocommerce") . ':</th><td>' . $value2 . 'kcal</td></tr>';
}
if ( ! empty($value3) ) {
echo '<tr><th>' . __("Ingredients", "woocommerce") . ':</th><td>' . $value3 . '</td></tr>';
}
echo '</table>';
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and work.
Related:
Display product custom fields on WooCommerce Admin Order Items also for variable products
Using Woocommerce, I would like to add SKU instead of the product name in the order view page of My Account /my-account/view-order/[orderid]/
I am able to add the SKU with a link using the code below.
The SKU is displayed just after the product name on the same line.
add_filter( 'woocommerce_order_item_name', 'display_sku_in_order_item', 20, 3 );
function display_sku_in_order_item( $item_name, $item, $is_visible ) {
if( is_wc_endpoint_url( 'view-order' ) ) {
$product = $item->get_product();
if( $sku = $product->get_sku() )
$item_name .= '' . __( "Product ", "woocommerce") . $sku . '';
}
return $item_name;
}
However, I would like to remove the product name but I don't know the code to write to do this. Any help please?
You just need to replace $item_name .= by $item_name = in your code, like:
add_filter( 'woocommerce_order_item_name', 'display_sku_in_order_item', 20, 3 );
function display_sku_in_order_item( $item_name, $item, $is_visible ) {
if( is_wc_endpoint_url( 'view-order' ) ) {
$product = $item->get_product();
if( $sku = $product->get_sku() )
$item_name = '' . __( "Product ", "woocommerce") . $sku . '';
}
return $item_name;
}
Code goes in function.php file of your active child theme (or active theme). It should work.
I am trying to add the shipping class under each product to the new order emails for both admin and customers in WooCommerce. This is my first time posting a question so please forgive me if there are formatting issues.
I used the code found here: https://wordpress.stackexchange.com/questions/291637/woocommerce-add-shipping-class-below-each-product-in-shopping-cart-page
That adds the shipping class below each product in the cart but I want to be able to show it on the order emails also.
I am just unsure of which objects to call to grab the data for each product in the new order email.
Here's the code I'm using:
add_action( 'woocommerce_order_item_meta_start', 'ts_order_item_meta_start', 10, 4 );
function ts_order_item_meta_start( $item_id, $item, $order, $plain_text, $item_name ){
$product = $cart_item['data']; // Get the WC_Product object instance
$shipping_class_id = $product->get_shipping_class_id(); // Shipping class ID
$shipping_class_term = get_term( $shipping_class_id, 'product_shipping_class' );
if( empty( $shipping_class_id ) )
return $item_name; // Return default product title (in case of)
$label = __( 'Shipping class', 'woocommerce' );
return $item_name . '<br>
<p class="item-shipping_class" style="margin:12px 0 0;">
<strong>' .$label . ': </strong>' . $shipping_class_term->name . '</p>';
}
I expected the shipping class to be listed below each product in the "New Order" email but currently adding this code returns an internal server error upon checkout.
The following will display The product shipping class name in Woocommerce "New Order" Email notification:
// Setting the email_is as a global variable
add_action('woocommerce_email_before_order_table', 'the_email_id_as_a_global', 1, 4);
function the_email_id_as_a_global($order, $sent_to_admin, $plain_text, $email ){
$GLOBALS['email_id_str'] = $email->id;
}
// Display Items shipping class name in New Order email notification
add_filter( 'woocommerce_order_item_name', 'custom_order_item_name', 10, 3 );
function custom_order_item_name( $item_name, $item, $is_visible ) {
// Targeting email notifications only
if( is_wc_endpoint_url() ) return $item_name;
// Get the WC_Product object (from order item)
$product = $item->get_product();
if( $shipping_class_id = $product->get_shipping_class_id() ){
// Getting the email ID global variable
$refNameGlobalsVar = $GLOBALS;
$email_id = $refNameGlobalsVar['email_id_str'];
// Only for New Order email notification
if( ! empty($email_id) && 'new_order' === $email_id ) {
$shipping_class_name = get_term( $shipping_class_id, 'product_shipping_class' )->name;
$item_name .= '<br><p class="item-shipping_class" style="margin:12px 0 0;">
<strong>' . __( 'Shipping class', 'woocommerce' ) . ': </strong>' . $shipping_class_name . '</p>';
}
}
return $item_name;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
I'm trying to display my product variation description in my Cart. I have tried inserting this code in the cart.php template:
if ( $_product->is_type( 'variation' ) ) {echo $_product->get_variation_description();}
By following this documentation https://docs.woocommerce.com/document/template-structure/
But it's still not showing up.
Not sure what I'm doing wrong here.
Can anyone help on this?
Updated for WooCommerce version 3 and above
Since WooCommerce 3, get_variation_description() is now deprecated and replaced by get_description() WC_Product method.
To get your product item variation description (filtering variation product type condition), you can use the following hooked function instead:
// Cart page (and mini cart)
add_filter( 'woocommerce_cart_item_name', 'cart_item_product_description', 20, 3);
function cart_item_product_description( $item_name, $cart_item, $cart_item_key ) {
if ( ! is_checkout() ) {
if( $cart_item['variation_id'] > 0 ) {
$description = $cart_item['data']->get_description(); // variation description
} else {
$description = $cart_item['data']->get_short_description(); // product short description (for others)
}
if ( ! empty($description) ) {
return $item_name . '<br><div class="description">
<strong>' . __( 'Description', 'woocommerce' ) . '</strong>: '. $description . '
</div>';
}
}
return $item_name;
}
// Checkout page
add_filter( 'woocommerce_checkout_cart_item_quantity', 'cart_item_checkout_product_description', 20, 3);
function cart_item_checkout_product_description( $item_quantity, $cart_item, $cart_item_key ) {
if( $cart_item['variation_id'] > 0 ) {
$description = $cart_item['data']->get_description(); // variation description
} else {
$description = $cart_item['data']->get_short_description(); // product short description (for others)
}
if ( ! empty($description) ) {
return $item_quantity . '<br><div class="description">
<strong>' . __( 'Description', 'woocommerce' ) . '</strong>: '. $description . '
</div>';
}
return $item_quantity;
}
Now the description is just displayed between the title and the variation attributes values (if there is any).
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
This will work for WC 3.0
add_filter( 'woocommerce_cart_item_name', 'cart_variation_description', 20, 3);
function cart_variation_description( $title, $cart_item, $cart_item_key ) {
$item = $cart_item['data'];
if(!empty($item) && $item->is_type( 'variation' ) ) {
return $item->get_name();
} else
return $title;
}
You can get it via global variable $woocommerce also-
global $woocommerce;
$cart_data = $woocommerce->cart->get_cart();
foreach ($cart_data as $value) {
$_product = $value['data'];
if( $_product->is_type( 'variation' ) ){
echo $_product->id . '<br>';
}
}
I already check it.