So I almost got it, but this last detail of specifying WooCommerce emails is leaving my head in a bit of a knot here.
I need to show ACF (advanced custom fields) fields of products (in this case it's a custom shipping time)
But only in the new order email (processing order and waiting payment order sent to the client) and then new order email to admin.
This was the main way I found: "Display product ACF field value in Woocommerce transaction emails" Thank you in advance #LoicTheAztec
I also added some conditional settings to it (mind me my PHP is very beginning copy-pasty)
which are working pretty well.
However what I can't get around is making it work only on new order emails.
I have it setup like this, and it works, however it shows on all emails that contain the email order details, and I can't have the shipping time showing on the completed order emails as it will create confusion.
// Display product ACF custom field value shipping 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 ( 'new_order' == $email->id )
return $item_name;
// Get the WC_Product object (from order item)
$product = $item->get_product();
$othershipping = get_field( 'shipping_custom', $product->get_id());
if( $shpng_value = get_field('shipping_', $product->get_id())== "24h") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . '<p>Get it tomorrow(24h)</p>' . '</p>';
}
elseif( $shpng_value = get_field('shipping_', $product->get_id())== "2-5 days") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . '<p>2-5 days</p>' . '</p>';
}
elseif( $shpng_value = get_field('shipping_', $product->get_id())== "other") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . $othershipping . '</p>';
}
return $item_name;
}
I have tried switching the
if ( 'new_order' == $email->id )
to
if ( 'new_order' != $email->id )
But that just makes it not work anywhere.
I also thought it could be this part
function custom_order_item_name( $item_name, $item ) {
Where I need to add ($order, $sent_to_admin, $plain_text, $email )
function custom_order_item_name( $item_name, $item, $order, $sent_to_admin, $plain_text, $email )
But it makes the email return an error.
Normally this should work with the code below
Note: my answer is largely based on: "Customize order item meta only for WooCommerce admin email notifications". CREDITS: #Loictheaztec so don't forget to upvote that answer to!
// Setting the "sent_to_admin" as a global variable
function email_order_id_as_a_global($order, $sent_to_admin, $plain_text, $email) {
$GLOBALS['email_data'] = array(
'sent_to_admin' => $sent_to_admin, // <== HERE we set "$sent_to_admin" value
'email_id' => $email->id, // The email ID (to target specific email notification)
);
}
add_action('woocommerce_email_before_order_table', 'email_order_id_as_a_global', 1, 4);
function custom_order_item_name( $item_name, $item ) {
if ( ! is_wc_endpoint_url() && $item->is_type('line_item') ) {
// Getting the custom 'email_data' global variable
$refNameGlobalsVar = $GLOBALS;
$email_data = $refNameGlobalsVar['email_data'];
// Only for new order
if( is_array( $email_data ) && $email_data['email_id'] == 'new_order' ) {
// Get the WC_Product object (from order item)
$product = $item->get_product();
$othershipping = get_field( 'shipping_custom', $product->get_id());
if( $shpng_value = get_field('shipping_', $product->get_id())== "24h") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . '<p>Get it tomorrow(24h)</p>' . '</p>';
}
elseif( $shpng_value = get_field('shipping_', $product->get_id())== "2-5 days") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . '<p>2-5 days</p>' . '</p>';
}
elseif( $shpng_value = get_field('shipping_', $product->get_id())== "other") {
$item_name .= '<br><p class="item-shpng" style="margin:12px 0 0;">
<strong>' . __( 'Shipping time', 'woocommerce' ) . ': </strong>' . $othershipping . '</p>';
}
}
}
return $item_name;
}
add_filter( 'woocommerce_order_item_name', 'custom_order_item_name', 10, 2 );
Related
i have two codes to change the product name on my woocommerce variable product.
The first one works fine everywhere, but not in my "floating cart plugin" (it use the default product name).
add_action( 'woocommerce_before_calculate_totals', 'custom_cart_items_prices', 10, 1 );
function custom_cart_items_prices( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
foreach ( $cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
$modell = $product->get_attribute('pa_modell');
$reparatur = $product->get_attribute('pa_reparatur');
$original_name = method_exists( $product, 'get_name' ) ? $product->get_name() : $product->post->post_title;
$new_name = '<class="new-product-name">' . $original_name . __( " ", "woocommerce") . $modell . __( " - ", "woocommerce") . $reparatur;
if( method_exists( $product, 'set_name' ) )
$product->set_name( $new_name );
else
$product->post->post_title = $new_name;
}
}
The second one are working on my "floating cart plugin", but if i use it too, i have the same name 2 times on cart and checkout page table.
function show_model_in_cart_items( $item_name, $cart_item, $cart_item_key ) {
$product = $cart_item['data'];
$modell = $product->get_attribute('pa_modell');
$reparatur = $product->get_attribute('pa_reparatur');
{
$item_name = '<class="product-model">' . $item_name . __( " ", "woocommerce") . $modell . __( " - ", "woocommerce") . $reparatur;
}
return $item_name;
}
add_filter( 'woocommerce_cart_item_name', 'show_model_in_cart_items', 99, 3 );
Some parts of this codes are found on the internet, others are from myself.
Does anyone has an idea how to combine it so that it works anywhere without the same name 2 times in cart?
I've found a solution. And sometimes it's so simple... like a simple if and else.
add_filter( 'woocommerce_cart_item_name', 'show_model_in_cart_items', 99, 3 );
function show_model_in_cart_items( $item_name, $cart_item, $cart_item_key ) {
if ( is_checkout() ) {
return $item_name;
}
else {
$product = $cart_item['data'];
$modell = $product->get_attribute('pa_modell');
$reparatur = $product->get_attribute('pa_reparatur');
{
$item_name = '<class="reparatur-beschreibung">' . $item_name . __( " ", "woocommerce") . $modell . __( " - ", "woocommerce") . $reparatur;
}
return $item_name;
}}
Now the floating cart plugin can use it anywhere, except the checkout where i have the other code to correct the product title.
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;
}
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
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.
We're using the following script to allow users to enter a custom price for their gift card purchase on this page: http://oceanapoke.staging.wpengine.com/pages/gift-card/
The problem is that the custom price is no longer totally correctly in the cart itself with the recent WooCommerce 3.0.8 update.
Troubleshooting this is way outside my wheelhouse. Is there anyone that can point me in the right direction?
function wpr_custom_price() {
if ( !class_exists( 'woocommerce' ) && !class_exists( 'rpgc_woocommerce' ) )
return;
}
add_action('plugins_loaded ', 'wpr_custom_price', 20 );
// Adds the box to enter in the cost of the giftcard.
function wpr_add_remove_field() {
$currency_symbol = get_woocommerce_currency_symbol();
$currency_pos = get_option( 'woocommerce_currency_pos' );
_e('Enter Gift Card Value');
?>
<br />
<?php
switch ( $currency_pos ) {
case 'left' :
echo '<strong>' . $currency_symbol . '</strong> <input
name="rpgc_price" id="rpgc_price" placeholder="' . __('0.00',
WPR_CP_CORE_TEXT_DOMAIN ) . '" class="input-text" style="margin-bottom:5px;
width: 100px;">';
break;
case 'right' :
echo '<input name="rpgc_price" id="rpgc_price" placeholder="' .
__('0.00', WPR_CP_CORE_TEXT_DOMAIN ) . '" class="input-text" style="margin-
bottom:5px; width: 100px;"><strong> ' . $currency_symbol . '</strong>';
break;
case 'left_space' :
echo '<strong>' . $currency_symbol . ' </strong> <input
name="rpgc_price" id="rpgc_price" placeholder="' . __('0.00',
WPR_CP_CORE_TEXT_DOMAIN ) . '" class="input-text" style="margin-bottom:5px;
width: 100px;">';
break;
case 'right_space' :
echo '<input name="rpgc_price" id="rpgc_price" placeholder="' .
__('0.00', WPR_CP_CORE_TEXT_DOMAIN ) . '" class="input-text" style="margin-
bottom:5px; width: 100px;"> <strong> ' . $currency_symbol . '</strong>';
break;
}
}
add_action( 'rpgc_before_all_giftcard_fields', 'wpr_add_remove_field', 10 );
// Removes the display of the price on a gift card product
function wpr_remove_price( $price, $post ) {
$is_giftcard = get_post_meta( $post->id, '_giftcard', true );
if ( $is_giftcard == "yes" )
$price = "";
return $price;
}
add_filter( 'woocommerce_get_price_html', 'wpr_remove_price', 10, 2 );
**// Saves the Gift card amount on adding it to the cart
function wpr_add_cart_item($data) {
if ( isset( $_POST['rpgc_price'] ) )
$data['Price'] = (double) woocommerce_clean( $_POST['rpgc_price'] );
return $data;
}
add_filter('rpgc_giftcard_data', 'wpr_add_cart_item', 10, 1);
// Replaces the $0 price of the Gift card with the amount entered by the
customer
function wpr_add_custom_price( $cart_object ) {
foreach ( $cart_object->cart_contents as $key => $value ) {
if( isset( $value["variation"]["Price"] ) )
$value['data']->price = $value["variation"]["Price"];
}
}
add_action( 'woocommerce_before_calculate_totals', 'wpr_add_custom_price' );
// Updates the price in the Mini Cart
function wpr_minicart_price ( $price, $cart_item, $cart_item_key ){
$is_giftcard = get_post_meta( $cart_item [ "product_id" ], '_giftcard', true
);
if ( $is_giftcard == "yes" ) {
$price = woocommerce_price( $cart_item ["variation"]["Price"] );
}
return $price;
}
add_filter('woocommerce_cart_item_price','wpr_minicart_price', 10, 3);
add_filter('woocommerce_add_to_cart_validation',
'my_custom_checkout_field_process', 10, 2);
function my_custom_checkout_field_process( $state, $product_id ) {
$is_giftcard = get_post_meta( $product_id, '_giftcard', true );
if ( $is_giftcard == "yes" ) {
// Check if set, if its not set add an error.
if ( ! $_POST['rpgc_price'] ) {
wc_add_notice( __( 'Please enter a price for the gift card.' ),
'error' );
$state = false;
}
}
return $state;
}**
/**
* Load the Text Domain for i18n
*
* #return void
* #access public
*/
function rpgc_custprice_loaddomain() {
load_plugin_textdomain( 'rpgc-customprice', false, dirname( plugin_basename(
__FILE__ ) ) . "/languages" );
}
add_action( 'init', 'rpgc_custprice_loaddomain' );
?>
Replace this line $value['data']->price = $value["variation"]["Price"]; with this
$value['data']->set_price( $value["variation"]["Price"] ); because in the new version we only get an object with the product through that object. We can call the set_price() function to set the current price.