We use this code to display the used coupons on a order. This is working fine! But now we want to show this information also in the order quick view.
I found this hook here: woocommerce_admin_order_preview_end
So i tried to change the hook from the code below with this hook. But then the quick view function does not work at all. When we click on the "eye" to open the quick view - nothing happend. Do we have to adjust the code more or what is here the problem?
add_action( 'woocommerce_admin_order_data_after_billing_address', 'custom_checkout_field_display_admin_order_meta', 10, 1 );
/**
* Add used coupons to the order edit page
*
*/
function custom_checkout_field_display_admin_order_meta($order){
if( $order->get_used_coupons() ) {
$coupons_count = count( $order->get_used_coupons() );
echo '<h4>' . __('Coupons used') . ' (' . $coupons_count . ')</h4>';
echo '<p><strong>' . __('Coupons used') . ':</strong> ';
$i = 1;
foreach( $order->get_used_coupons() as $coupon) {
echo $coupon;
if( $i < $coupons_count )
echo ', ';
$i++;
}
echo '</p>';
}
}
Try to use the following to display coupon used in admin order quick view (preview):
// Add custom order data to make it accessible in Order preview template
add_filter( 'woocommerce_admin_order_preview_get_order_details', 'admin_order_preview_add_custom_data', 10, 2 );
function admin_order_preview_add_custom_data( $data, $order ) {
// Replace '_custom_meta_key' by the correct postmeta key
if( $coupons = $order->get_used_coupons() ) {
$data['coupons_count'] = count($coupons); // <= Store the count in the data array.
$data['coupons_codes'] = implode(', ', $coupons); // <= Store the count in the data array.
}
return $data;
}
// Display The data in Order preview
add_action( 'woocommerce_admin_order_preview_end', 'custom_display_order_data_in_admin' );
function custom_display_order_data_in_admin(){
// Call the stored value and display it
echo '<div><strong>' . __('Coupons used') . ' ({{data.coupons_count}})<strong>: {{data.coupons_codes}}</div><br>';
}
Code goes in functions.php file of the active child theme (or active theme). Untested it should works.
Based on: Display custom data on Woocommerce admin order preview
Related
I am using the following code to show custom product meta in the order items table on the WooCommerce admin order details page:
add_action('woocommerce_admin_order_item_headers', 'tempiconsegna_admin_order_item_headers');
function tempiconsegna_admin_order_item_headers() {
$column_name = 'Tempi Consegna';
echo '<th>' . $column_name . '</th>';
}
add_action('woocommerce_admin_order_item_values', 'tempiconsegna_admin_order_item_values', 10, 3);
function tempiconsegna_admin_order_item_values($_product, $item, $item_id = null) {
$value = get_post_meta($_product->post->ID, 'prefix-tempiconsegna', 1);
echo '<td>' . $value . '</td>';
}
It displays "prefix-tempiconsegna" which are custom metas like:
Available in 3 days
Available now
etc..
My problem is that if I change the availability in the product, it changes also in previous orders.
How do i make this displaying the value at the moment of the order without changing when I update the availability of the product?
Your current code contains 2 errors:
Attempt to read property "post" on null
Attempt to read property "ID" on null
To answer your question: that's because you're using get_post_meta() and the productID, so if you adjust the data for the product it will also change the data where it is displayed, in your case the current and previous orders.
To prevent this, you have to add the data per order line item, this can be done via:
function action_woocommerce_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
// The WC_Product instance Object
$product = $item->get_product();
// Get value
$value = $product->get_meta( 'prefix-tempiconsegna' );
// NOT empty
if ( ! empty ( $value ) ) {
$item->update_meta_data( 'prefix-tempiconsegna', $value );
}
}
add_action( 'woocommerce_checkout_create_order_line_item', 'action_woocommerce_checkout_create_order_line_item', 10, 4 );
Then to display this in WooCommerce admin order details page, use:
// Add header
function action_woocommerce_admin_order_item_headers( $order ) {
// Set the column name
$column_name = __( 'Tempi Consegna', 'woocommerce' );
// Display the column name
echo '<th class="my-class">' . $column_name . '</th>';
}
add_action( 'woocommerce_admin_order_item_headers', 'action_woocommerce_admin_order_item_headers', 10, 1 );
//Add content
function action_woocommerce_admin_order_item_values( $product, $item, $item_id ) {
// Only for "line_item" items type, to avoid errors
if ( ! $item->is_type('line_item') ) return;
// Get value
$value = $item->get_meta( 'prefix-tempiconsegna' );
// NOT empty
if ( ! empty ( $value ) ) {
echo '<td>' . $value . '</td>';
} else {
echo '<td>Meta not found!</td>';
}
}
add_action( 'woocommerce_admin_order_item_values', 'action_woocommerce_admin_order_item_values', 10, 3 );
To display custom data , I use this hook 'woocommerce_checkout_create_order_line_item'. He works good. But it displays data in three places - in the admin panel (in order), in the order details and in the personal account. I need the data to be displayed only in the admin panel. how to do it?
My code
add_action( 'woocommerce_checkout_create_order_line_item', 'wdm_add_custom_order_line_item_meta', 10, 4 );
function wdm_add_custom_order_line_item_meta( $item, $cart_item_key, $values, $order )
{
if ( array_key_exists( 'file', $values ) ) {
$product_id = $item->get_product_id();
$permfile = $values['file'];
$basePath = plugin_base_url();
$fileid = $permfile;
....
$item->add_meta_data('File','<button > <a href="'.$fileid.'" download>' . Download. '</a></button>');
}
}
Use the following to display a custom download button on admin order items only (code is commented):
// Save custom order item meta
add_action( 'woocommerce_checkout_create_order_line_item', 'save_custom_order_item_meta', 10, 4 );
function save_custom_order_item_meta( $item, $cart_item_key, $values, $order ) {
if ( isset($values['file']) && ! empty($values['file']) ) {
// Save it in an array to hide meta data from admin order items
$item->add_meta_data('file', array( $values['file'] ) );
}
}
// Get custom order item meta and display a linked download button
add_action( 'woocommerce_after_order_itemmeta', 'display_admin_order_item_custom_button', 10, 3 );
function display_admin_order_item_custom_button( $item_id, $item, $product ){
// Only "line" items and backend order pages
if( ! ( is_admin() && $item->is_type('line_item') ) )
return;
$file_url = $item->get_meta('file'); // Get custom item meta data (array)
if( ! empty($file_url) ) {
// Display a custom download button using custom meta for the link
echo '<a href="' . reset($file_url) . '" class="button download" download>' . __("Download", "woocommerce") . '</a>';
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
The custom download button is only displayed in admin order items.
In Woocommerce, I have a checkout page (review order) with custom data.
I need to find a hook to register some custom data ($totaleiva_1 and $totalefinitocarrello) in the order and then I have to send them in email new order.
I'm not able to make it for instance. Any advice or help please?
Edit - That is my code:
$totaleiva_1 = 0;
$items = $woocommerce->cart->get_cart();
foreach($items as $item ) {
$totaleiva_1 += $totalForSebeneArray[$item ['data']->get_id()];
}
$totaleiva_1 = number_format($totaleiva_1, 2, '.', '');
$totalefinitocarrello = $totaleiva_1 + $total; echo "€";
echo $totalefinitocarrello;
You will need to add and display 2 hidden fields with the 2 desired values (to be able to get and save them as custom order meta data on submission).
Also your code is a bit outdated and can be simplified.
Here is your revisited code:
$totaleiva_1 = 0;
// Loop through cart items
foreach (WC()->cart->get_cart() as $cart_item ) {
$totale_iva_1 += $totalForSebeneArray[$cart_item['data']->get_id()];
}
$totale_finito_carrello = wc_price( $totale_iva_1 + $total );
echo $totale_finito_carrello;
// Display 2 hidden input fields
echo '<input type="hidden" id="totaleiva1" name="totaleiva1" value="'.$totale_iva_1.'">
<input type="hidden" id="tfcarrello" name="tfcarrello" value="'.$totale_finito_carrello.'">';
Then you will save that data as custom order meta data using:
add_action('woocommerce_checkout_create_order', 'save_order_custom_meta_data', 10, 2 );
function save_order_custom_meta_data( $order, $data ) {
if( isset($_POST['totaleiva1']) && ! empty($_POST['totaleiva1']) ) {
$order->update_meta_data( '_totale_iva_1', esc_attr( $_POST['totaleiva1'] ) );
}
if( isset($_POST['tfcarrello']) && ! empty($_POST['tfcarrello']) ) {
$order->update_meta_data( '_totale_fin_carrello', esc_attr( $_POST['tfcarrello'] ) );
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Now to get that data and use it anywhere:
1) from the order ID variable, use:
$totaleiva_1 = get_post_meta( $order_id, '_totale_iva_1', true );
$totalefinitocarrello = get_post_meta( $order_id, '_totale_fin_carrello', true );
2 from the WC_Order Object:
$totaleiva_1 = $order->get_meta('_totale_iva_1');
$totalefinitocarrello = $order->get_meta('_totale_fin_carrello');
To display those in Woocommerce new order notification, ou will use:
add_action( 'woocommerce_email_order_details', 'email_order_details_action_callback', 5, 4 );
function email_order_details_action_callback( $order, $sent_to_admin, $plain_text, $email ){
if( $email->id === 'new_order' ) {
if ( $tiva1 = $order->get_meta('_totale_iva_1') ) {
echo '<p>'. __("Totale IVA") . ': ' . $tiva1 . '</p>';
}
if ( $tfcarr = $order->get_meta('_totale_fin_carrello') ) {
echo '<p>'. __("Totale finito carrello") . ': ' . $tfcarr . '</p>';
}
}
}
Display the fields in Admin order pages:
add_action( 'woocommerce_admin_order_data_after_billing_address', 'admin_order_after_billing_address_callback', 10, 1 );
function admin_order_after_billing_address_callback( $order ){
if ( $tiva1 = $order->get_meta('_totale_iva_1') ) {
echo '<p>'. __("Totale IVA") . ': ' . $tiva1 . '</p>';
}
if ( $tfcarr = $order->get_meta('_totale_fin_carrello') ) {
echo '<p>'. __("Totale finito carrello") . ': ' . $tfcarr . '</p>';
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Now I think that all your IVA custom calculations can be handled by Woocommerce using available settings possibilities, as you are making things Much more complicated everywhere.
In WooCommerce on this website, I have 2 Local Pickup shipping methods:
AM pickup: shipping_method_0_local_pickup31
PM pickup: shipping_method_0_local_pickup32
Unfortunately this shipping method does not show up on Admin Order edit pages
Is is possible to use:
add_action('woocommerce_admin_order_data_after_shipping_address','cwn_add_pickup_to_order_item_meta', 1, 2);
function cwn_add_pickup_to_order_item_meta($shipping_method) {
echo "<h4>Pickup Time</h4>";
echo '<p><strong>' . __('AM pickup') . ':</strong><br> ' . get_post_meta($shipping_method->id, '_shipping_method_0_local_pickup31', true) . '</p>';
echo '<p><strong>' . __('PM pickup') . ':</strong><br> ' . get_post_meta($shipping_method->id, '_shipping_method_0_local_pickup32', true) . '</p>';
}
There is 2 similar ways to get the Shipping methods data in the WC_Order object.
1) Using WC_Abstract_Order get_shipping_methods() method.
2) Using WC_Abstract_Order get_items( 'shipping' ) method.
This will output an array of WC_Order_Item_Shipping objects. So you will need a foreach loop to use WC_Order_Item_Shipping methods to get the data, this way (Where $order is an instance of the WC_Order object):
foreach($order->get_items( 'shipping' ) as $shipping_method ){
$method_id = $shipping_method->get_method_id().'<br>';
$shipping_method_name = $shipping_method->get_name().'<br>';
$shipping_method_title = $shipping_method->get_method_title().'<br>';
$shipping_method_total = $shipping_method->get_total().'<br>';
$shipping_method_total_tax = $shipping_method->get_total_tax().'<br>';
}
//Or:
foreach($order->get_shipping_methods() as $shipping_method ){
$method_id = $shipping_method->get_method_id().'<br>';
$shipping_method_name = $shipping_method->get_name().'<br>';
$shipping_method_title = $shipping_method->get_method_title().'<br>';
$shipping_method_total = $shipping_method->get_total().'<br>';
$shipping_method_total_tax = $shipping_method->get_total_tax().'<br>';
}
In your code, the $shipping_method hooked function argument is wrong as it should be $order (an instance of WC_Order object.
So now you can use it in your hooked function, this way for example:
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'cwn_add_pickup_to_order_item_meta', 10, 1 );
function cwn_add_pickup_to_order_item_meta( $order ){
echo '<div>';
foreach($order->get_shipping_methods() as $shipping_method ){
echo '<p><strong>Shipping Method ID:</strong> '. $shipping_method->get_method_id().'<br>
<strong>Shipping Method name:</strong> '. $shipping_method->get_name().'<br>
<strong>Shipping Method title:</strong> '. $shipping_method->get_method_title().'<br>
<strong>Shipping Method Total:</strong> '. $shipping_method->get_total().'<br>
<strong>Shipping Method Total tax:</strong> '. $shipping_method->get_total_tax().'</p><br>';
}
echo '</div>';
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file
Tested and works on WooCommerce 3+
I was looking for a way to execute a command when finalizing a purchase and the shipping method selected was different from "LOCAL PICKUP".
Your last code gave me the light I needed.
My code worked.
Follow my code to help whoever needs it:
function showpopup($order_id){
$order = wc_get_order($order_id);
$order->get_shipping_methods();
if( ! $order->has_shipping_method('local_pickup') ) {
echo '
<script>
function myFunction() {
alert("Retirada no local NÃO SELECIONADA!");
}
myFunction()
</script>
';
}
}
add_action( 'woocommerce_thankyou', 'showpopup', 10, 1 );
Thank you.
On WooCommerce I have a custom field days_manufacture for each product with different (integer) values.
Also I Have this code that displays a message on cart page with the highest value of "days of manufacture":
add_action('woocommerce_before_cart', 'days_of_manufacture');
function days_of_manufacture() {
$day_txt = ' ' . __('day', 'your_theme_domain_slug' );
$days_txt = ' ' . __('days', 'your_theme_domain_slug' );
$text = __('Your Order will be produced in: ', 'your_theme_domain_slug' );
$max_days = 0;
foreach( WC()->cart->get_cart() as $cart_item )
if($cart_item['days_manufacture'] > $max_days)
$max_days = $cart_item['days_manufacture'];
if($max_days != 0) {
if ($max_days == 1)
$days_txt = $day_txt;
$output = $text . $max_days . $days_txt;
echo "<div class='woocommerce-info'>$output</div>";
}
}
Now I would like to display this message in emails.
How can I achieve this?
Thanks
You can do it, changing a little bit the function of this answer to your previous question and I additionally hook this function to woocommerce_email_before_order_table hook for the orders notification emails.
So you will replace that existing function by this one. And you replace also the inserted function in both templates (see below).
This function can handle displaying your custom dynamic message in the templates (as before) and in your email notifications.
Here is the code:
add_action('woocommerce_email_before_order_table', 'days_of_manufacture_view_order_and_email', 99);
function days_of_manufacture_view_order_and_email($order, $type='email') {
$day_txt = ' ' . __('day', 'your_theme_domain_slug' );
$days_txt = ' ' . __('days', 'your_theme_domain_slug' );
$max_days = 0;
// Your customized style for the email template (to adapt for your needs)
$style = 'border:solid 2px #ededed; padding:10px; font-weight:bold;';
// Your customized text goes in here
$text = __('Your Order will be produced in: ', 'your_theme_domain_slug' );
foreach( $order->get_items() as $item )
if(get_post_meta($item['product_id'], 'days_manufacture', true) > $max_days )
$max_days = get_post_meta($item['product_id'], 'days_manufacture', true);
if($max_days != 0) {
if ($max_days == 1)
$days_txt = $day_txt;
$output = $text . $max_days . $days_txt;
// displayed on the email notifications
if($type == 'email')
echo "<div class='woocommerce-info' style='$style'>$output</div>"; // <== Customize the styles if needed
// displayed on the woocommerce templates
else
echo "<div class='woocommerce-info' style='display:block !important;'>$output</div>"; // displayed on the templates
}
}
This code goes in function.php file of your active child theme (or theme) or also in any plugin file.
The templates changes
Now in both templates within your active child theme (or theme) woocommerce templates folder:
your_theme/woocommerce/myaccount/view-order.php
your_theme/woocommerce/checkout/thankyou.php
You will change this line:
<?php days_of_manufacture_order_view($order); // <== inserted Here ?>
By this line:
<?php days_of_manufacture_view_and_email($order, 'template'); // <== inserted Here ?>
Now the custom notice is displayed on emails too and still works on Thankyou view order page and on
My account > Orders > view order` pages too.
References:
WooCommerce - Custom notice on in Thankyou and “My account” view order pages
Template Structure + Overriding Templates via a Theme
Woocommerce template myaccount > view-order.php
Woocommerce template checkout > thankyou.php