Display product ACF value in Woocommerce admin email notifications - php

Trying to get an advanced custom field in a woocommerce product to pass to the new order email for the admin. It's only there for the admin reference and is specific to each product. I have tried and this gets it to the backend but not in the email.
add_action( 'woocommerce_before_order_itemmeta', 'product_size', 10, 3 );
function product_size( $item_id, $item, $product ){
// Only in backend Edit single Order pages
if( current_user_can('edit_shop_orders') ):
// The product ID
$product_id = $product->get_id();
// Get your ACF product value
$acf_value = __('Size: ') . get_field( 'package_size', $product_id );
// Outputing the value of the "package size" for this product item
echo '<div class="wc-order-item-custom"><strong>'. $acf_value .'</strong></div>';
endif;
}
I tried using this to get to the email but it killed the order process. It went through in the backend but after hitting place order, it just refreshes the checkout page and does not go to the thank you or generate an email.
add_action( 'woocommerce_email_order_details', 'display', 10, 4 );
function display( $order, $sent_to_admin, $plain_text, $email ) {
global $product;
$id = $product->get_id();
$value = get_field( "package_size", $id );
if($value) {
echo "<p>Package Size : ".$value ."</p>";
}
}
Any suggestions or help is appreciated.

The WC_Product object $product can't be defined as a global variable. You need to use a foreach loop to get order items first.
But as an order can have many items (products) you may get many displays for this ACF field.
Your revisited code:
add_action( 'woocommerce_email_order_details', 'display_package_size_email_order_details', 10, 4 );
function display_package_size_email_order_details( $order, $sent_to_admin, $plain_text, $email ) {
// Only admin notifications
if( ! $sent_to_admin )
return; // Exit
foreach( $order->get_items() as $item ) {
if( $package_size = get_field( "package_size", $item->get_product_id() ) ){
echo '<p><strong>'.__('Package Size').': </strong>'.$package_size.'</p>';
}
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Related: Display value from ACF field in Woocommerce order email

Related

About Woocommerce product insertion hooks

I added a field to the product display page. I did some research but was not successful.
I have a form element like the one below, it may be text in this picture.
https://prnt.sc/vql93m
I want to save a field as a post meta while creating the product.
Then I want to show the relevant meta on the order page, actually I did it partially, but I can't save the relevant data.
https://prnt.sc/vqlbfs
And I can only add to cart on the single product display page, all other sections should be removed.
https://prnt.sc/vql8mj
Hooks and codes I used.
add_action('woocommerce_before_add_to_cart_button', 'woocommerce_custom_fields_display');
function woocommerce_custom_fields_display()
{
?>
<label>Product type:</label><br><input type="text" id="product-type" name="product-type"><br><br>
<?php
}
add_action( 'woocommerce_before_order_itemmeta', 'so_32457241_before_order_itemmeta', 10, 3 );
function so_32457241_before_order_itemmeta( $item_id, $item, $_product ){
$order = json_decode( $item );
echo get_post_meta( $order['order_id'], 'product-type', true );
}
add_action( 'woocommerce_new_order', 'custom_woocommerce_order' );
function custom_woocommerce_order( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
var_dump( $order );
var_dump( $_POST );
}
add_action('woocommerce_add_to_cart', 'custome_add_to_cart');
function custome_add_to_cart() {
$p_id=$_POST['product-type'];
WC()->cart->add_to_cart( $p_id );
}

Woocommerce custom redirection based on purchased product after payment

I am looking out to redirect user to specific pages which will vary from product to product. So, once user completes payment for Product A, he will be redirected to Link A , which is an external link.
If he buys Product B, he will be redirected to Product B.
If not, At least I want to display dynamic URL on checkout page based on the product, once user completes payment.
Any input for this functionality ?
I tried the Affiliate link/Virtual products in woo commerce but its a different thing ..
I created a simple plugin using the code below to accomplish something similar...
/*
Plugin Name: Woocommerce Custom Thank You page per Product
Description: This plugin will allow you to set up a custom thank you page per product for woocommerce.
Author: Gabriel Collignon
*/
add_action( 'woocommerce_thankyou', 'redirect_product_based', 1 );
function redirect_product_based ( $order_id ){
$order = wc_get_order( $order_id );
foreach( $order->get_items() as $item ) {
// Add whatever product id you want below here
if ( $item['product_id'] == 181 ) {
// URL
wp_redirect( 'https://www....' );
} else {
// The other URL
wp_redirect( 'https://www....' );
}
}
}
The following will redirect to specifics Url based on order item (product Id) once customer complete payment and order has 'processing' or 'completed' status:
add_action( 'template_redirect', 'thankyou_custom_redirection', 10, 1 );
function thankyou_custom_redirection( $order_id ){
global $wp;
$order_id = get_query_var('order-received');
if( is_wc_endpoint_url('order-received') && ! empty($order_id) && $order_id > 0 ){
// Get the WC_Order Object instance
$order = wc_get_order( absint($order_id) );
// Allowed order statuses
$order_statuses = array('processing', 'completed');
if ( is_a($order, 'WC_Order') && in_array($order->get_status(), $order_statuses) ) {
$settings = product_ids_for_links_settings(); // Load settings
// Loop through order items
foreach( $order->get_items() as $item ) {
$product = $item->get_product();
$product_id = $item->get_variation_id() > 0 ? $item->get_variation_id() : $item->get_product_id();
print_pr($product_id);
if( in_array( $product_id, array_keys($settings) ) ){
$link_redirect = esc_url($settings[$product_id]);
break;
}
}
}
if( isset($link_redirect) && ! empty($link_redirect) ) {
// (optional) passing variables to URL
$link_redirect .= '?order_id='.$order_id.'&product_id='.$product_id;
// Redirection
wp_redirect( $link_redirect );
exit();
}
}
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
Related: Redirect automatically from Woocommerce thankyou to an external link passing variables
Your algoritm:
Get a ID product from your order.
Get permalink find product.
Used wp_redirect(permalink);

Which hooks for WooCommerce stock saved or updated

I am creating an event ticketing WordPress theme and I am using WooCommerce and Advanced custom fields (ACF) plugins.
I want to update a custom post type called event. With the stock of a specific ticket. That way my client does not need to look at the woo-commerce products page but can just simply open an "Event"
I tried using the update_post_meta hook but that only works when an admin updates the product in the admin tool. Not with a new order.
function sync_product_stock( $meta_id, $post_id, $meta_key, $meta_value ) {
$postType = get_post_type( $post_id );
if ($postType == 'product' ) {
if ( $meta_key == '_stock' ) {
$product = wc_get_product( $post_id );
$eventId = $product->get_attribute( 'event_id' );
$productName = $product->get_name();
if ($productName.include('Early Bird')) {
update_field( 'event_early_bird_group_event_early_bird_amount_of_tickets', $meta_value, $eventId );
} else if ($productName.include('Regular')) {
update_field( 'event_regular_group_event_regular_amount_of_tickets', $meta_value, $eventId );
} else if ($productName.include('Member')) {
// nothing needs to be updated
}
}
}
}
add_action( 'updated_post_meta', 'sync_product_stock', 10, 4);
How can I get notified when the _stock field is updated? (I don't want to handle the stock-keeping myself
There are some mistakes in your code. Try the following using woocommerce hooks:
// On processed update product stock event
add_action( 'woocommerce_updated_product_stock', 'wc_updated_product_stock_callback' );
// On admin single product creation/update
add_action( 'woocommerce_process_product_meta', 'wc_updated_product_stock_callback' );
// On admin single product variation creation/update
add_action( 'woocommerce_save_product_variation', 'wc_updated_product_stock_callback' );
function wc_updated_product_stock_callback( $product_id ) {
// get an instance of the WC_Product Object
$product = wc_get_product( $product_id );
$stock_qty = $product->get_stock_quantity();
$event_id = $product->get_attribute('event_id');
$product_name = $product->get_name();
if ( strpos($product_name, 'Early Bird') !== false ) {
update_field( 'event_early_bird_group_event_early_bird_amount_of_tickets', $stock_qty, $event_id );
} elseif ( strpos($product_name, 'Regular') !== false ) {
update_field( 'event_regular_group_event_regular_amount_of_tickets', $stock_qty, $event_id );
} elseif ( strpos($product_name, 'Member') !== false ) {
// nothing needs to be updated
}
}
Code goes in function.php file of the active child theme (or active theme). It should work.

Display a product custom field value in WooCommerce cart and checkout table

In WooCommerce and I have added a custom field "description" for each product.
I was able to find a way to show both, the label name and the value:
add_filter( 'woocommerce_add_cart_item_data', 'save_days_field', 10, 2 );
function save_days_field( $cart_item_data, $product_id ) {
$special_item = get_post_meta( $product_id , 'description',true );
if(!empty($special_item)) {
$cart_item_data[ 'description' ] = $special_item;
// below statement make sure every add to cart action as unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'description', $special_item );
}
return $cart_item_data;
}
// Render meta on cart and checkout
add_filter( 'woocommerce_get_item_data','rendering_meta_field_on_cart_and_checkout', 10, 2 );
function rendering_meta_field_on_cart_and_checkout( $cart_item_data, $cart_item ) {
if( isset( $cart_item['description'] ) ) {
$cart_item_data[] = array( "name" => __( "Description", "woocommerce" ), "value" => $cart_item['description'] );
}
return $cart_item_data;
}
Now I need to display ONLY the value (not the label name "Description") of this custom field in the cart and checkout table. I need to display with <small>, like the attribute I am displaying with this code:
add_filter('woocommerce_cart_item_name', 'wp_woo_cart_attributes', 10, 2);
function wp_woo_cart_attributes($cart_item, $cart_item_key){
$productId = $cart_item_key['product_id'];
$product = wc_get_product($productId);
$taxonomy = 'pa_color';
$value = $product->get_attribute($taxonomy);
if ($value) {
$label = get_taxonomy($taxonomy)->labels->singular_name;
$cart_item .= "<small>$value</small>";
}
return $cart_item;
}
How can I make it for this custom field, displaying the value only?
You don't need to include a product custom field as custom cart item data, as it's directly accessible from the product object (or the product ID).
Note: On a cart item variable $cart_item, the WC_Product Object is included and available using $cart_item['data'].
Try the following to add a custom field after the item name in cart and checkout pages:
// Display in cart and checkout pages
add_filter( 'woocommerce_cart_item_name', 'customizing_cart_item_name', 10, 3 );
function customizing_cart_item_name( $product_name, $cart_item, $cart_item_key ) {
$product = $cart_item['data']; // Get the WC_Product Object
if ( $value = $product->get_meta('description') ) {
$product_name .= '<small>'.$value.'</small>';
}
return $product_name;
}
To display it on orders and email notifications use:
// Display in orders and email notifications
add_filter( 'woocommerce_order_item_name', 'customizing_order_item_name', 10, 2 );
function customizing_order_item_name( $product_name, $item ) {
$product = $item->get_product(); // Get the WC_Product Object
if ( $value = $product->get_meta('description') ) {
$product_name .= '<small>'.$value.'</small>';
}
return $product_name;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Set a custom calculated item price in Woocommerce mini-cart / Cart

Currently i have some custom calculation of product price based on different situation. When customer added a product in to cart then the custom price is set in session data , cart_item_data['my-price'] and i implemented using add_filter( 'woocommerce_add_cart_item') function and everything seems to working now .
Now the price in view cart page, checkout page is correct with my cart_item_data['my-price'].
But the only problem i am facing is the price is not updated in woocommerce mini cart that is appeared in the menu ,How can i change this ?
When i google i see a filter
add_filter('woocommerce_cart_item_price');
but i can't understand how to use this i do the following
add_filter('woocommerce_cart_item_price','modify_cart_product_price',10,3);
function modify_cart_product_price( $price, $cart_item, $cart_item_key){
if($cart_item['my-price']!==0){
$price =$cart_item['my-price'];
}
return $price;
//exit;
}
Here individual price is getting correct , but total price is wrong
Updated (october 2021)
For testing this successfully (and as I don't know how you make calculations), I have added a custom hidden field in product add to cart form with the following:
// The hidden product custom field
add_action( 'woocommerce_before_add_to_cart_button', 'add_gift_wrap_field' );
function add_gift_wrap_field() {
global $product;
// The fake calculated price
?>
<input type="hidden" id="my-price" name="my-price" value="115">
<?php
}
When product is added to cart, this my-price custom field is also submitted (posted). To set this value in cart object I use the following function:
add_filter( 'woocommerce_add_cart_item', 'custom_cart_item_prices', 20, 2 );
function custom_cart_item_prices( $cart_item_data, $cart_item_key ) {
// Get and set your price calculation
if( isset( $_POST['my-price'] ) ){
$cart_item_data['my-price'] = $_POST['my-price'];
// Every add to cart action is set as a unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
}
return $cart_item_data;
}
Now to apply (set) the new calculated price my-price to the cart item, I use this last function:
// For mini cart *(cart item displayed price)*
add_action( 'woocommerce_cart_item_price', 'filter_cart_item_price', 10, 2 );
function filter_cart_item_price( $price, $cart_item ) {
if ( ! is_checkout() && isset($cart_item['my-price']) ) {
$args = array( 'price' => floatval( $cart_item['my-price'] ) );
if ( WC()->cart->display_prices_including_tax() ) {
$product_price = wc_get_price_including_tax( $cart_item['data'], $args );
} else {
$product_price = wc_get_price_excluding_tax( $cart_item['data'], $args );
}
return wc_price( $product_price );
}
return $price;
}
add_action( 'woocommerce_before_calculate_totals', 'set_calculated_cart_item_price', 20, 1 );
function set_calculated_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ){
if( isset( $cart_item['my-price'] ) && ! empty( $cart_item['my-price'] ) || $cart_item['my-price'] != 0 ){
// Set the calculated item price (if there is one)
$cart_item['data']->set_price( $cart_item['my-price'] );
}
}
}
All code goes in function.php file of your active child theme (or active theme).
Tested and works

Categories