Looking for some help,
The aim is to capture several bits of data when a customer checks-out and for these to be stored as custom order item meta data.
Im looking to capture
Start-date
Start time
End date
End time
For each order, currently using WooCommerce booking and this data goes straight to the reservation area and doesn't appear as custom order item meta data.
Ive found a list of the hooks and filters whilst trying to create code myself, however I think im missing some bits along the way:
https://docs.woocommerce.com/document/bookings-action-and-filter-reference/
https://docs.woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/
https://wordpress.stackexchange.com/questions/215219/how-to-display-custom-field-in-woocommerce-orders-in-admin-panel
Ive tried to create this code to add these items to the custom order item meta data but without much success.
function my_custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $fields['woocommerce_bookings_after_booking_base_cost'] ) ) {
update_post_meta( $order_id, 'woocommerce_bookings_after_booking_base_cost', sanitize_text_field( $_POST['woocommerce_bookings_after_booking_base_cost'] ) );
}
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'.__('woocommerce_bookings_after_booking_base_cost').':</strong> <br/>' . get_post_meta( $order->get_id(), 'woocommerce_bookings_after_booking_base_cost', true ) . '</p>';
}
Im hoping someone has had this issue before and can share their knowledge or someone could point me in the right direction or help me with the coding, happy to admit I'm not the very best at coding but if someone could help break it down to me a little of where and what Im doing wrong, maybe what I'm doing correct as well, so I can understand how to improve.
Any help?
I also found this code, but it doesn't set the custom order meta data,
WOE_Bookings{
function __construct() {
add_filter('woe_get_order_product_fields',array($this,'add_product_fields') );
add_filter('woe_get_order_product_item',array($this,'fetch_booking') );
//set global filters
add_filter('woe_get_order_product_value_booking_status', array($this,'get_booking_field_status'), 10, 5 );
add_filter('woe_get_order_product_value_booking_start_date', array($this,'get_booking_field_start_date'), 10, 5 );
add_filter('woe_get_order_product_value_booking_start_time', array($this,'get_booking_field_start_time'), 10, 5 );
add_filter('woe_get_order_product_value_booking_end_date', array($this,'get_booking_field_end_date'), 10, 5 );
add_filter('woe_get_order_product_value_booking_end_time', array($this,'get_booking_field_end_time'), 10, 5 );
add_filter('woe_get_order_product_value_booking_resource', array($this,'get_booking_field_resource'), 10, 5 );
add_filter('woe_get_order_product_value_booking_persons_total', array($this,'get_booking_field_persons_total'), 10, 5 );
// add function for person types
if( class_exists("WC_Product_Booking_Data_Store_CPT") AND method_exists("WC_Product_Booking_Data_Store_CPT", "get_person_types_ids") ) {
$person_types_ids = WC_Product_Booking_Data_Store_CPT::get_person_types_ids();
foreach($person_types_ids as $type_id) {
add_filter('woe_get_order_product_value_booking_person_type_'.$type_id, function($value,$order, $item, $product, $item_meta) use ($type_id){
if (!$this->booking)
return $value;
$counters = $this->booking->get_person_counts();
return isset($counters[$type_id]) ? $counters[$type_id] : 0;
}, 10, 5 );
}
}
}
function add_product_fields($fields) {
$fields['booking_status'] = array('label'=>'Booking Status','colname'=>'Booking Status','checked'=>1);
$fields['booking_start_date'] = array('label'=>'Booking Start Date','colname'=>'Booking Start Date','checked'=>1);
$fields['booking_start_time'] = array('label'=>'Booking Start Time','colname'=>'Booking Start Time','checked'=>1);
$fields['booking_end_date'] = array('label'=>'Booking End Date','colname'=>'Booking End Date','checked'=>1);
$fields['booking_end_time'] = array('label'=>'Booking End Time','colname'=>'Booking End Time','checked'=>1);
$fields['booking_resource'] = array('label'=>'Booking Resource','colname'=>'Booking Resource','checked'=>1);
$fields['booking_persons_total'] = array('label'=>'Booking # of Persons','colname'=>'Booking Persons Total','checked'=>1,'segment'=>'cart');
// add person types as columns
if( class_exists("WC_Product_Booking_Data_Store_CPT") AND method_exists("WC_Product_Booking_Data_Store_CPT", "get_person_types_ids") ) {
$person_types_ids = WC_Product_Booking_Data_Store_CPT::get_person_types_ids();
foreach($person_types_ids as $type_id) {
$post = get_post($type_id);
if( $post )
$fields['booking_person_type_'.$type_id] = array('label'=>'Booking Persons - ' .$post->post_title,'colname'=>'Booking Persons - ' .$post->post_title,'checked'=>1);
}
}
return $fields;
}
// booking for item
function fetch_booking($item) {
global $wpdb;
$this->booking = false;
$booking_id = $wpdb->get_var( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key= '_booking_order_item_id' AND meta_value=" . intval( $item->get_id() ) );
if( $booking_id ) {
$this->booking = new WC_Booking($booking_id);
}
return $item;
}
function get_booking_field_status($value,$order, $item, $product, $item_meta) {
return $this->booking ? $this->booking->get_status() : $value;
}
function get_booking_field_start_date($value,$order, $item, $product, $item_meta) {
return $this->booking ? date_i18n( wc_date_format(), $this->booking->start) : $value;
}
function get_booking_field_start_time($value,$order, $item, $product, $item_meta) {
return $this->booking ? date_i18n( wc_time_format(), $this->booking->start) : $value;
}
function get_booking_field_end_date($value,$order, $item, $product, $item_meta) {
return $this->booking ? date_i18n( wc_date_format(), $this->booking->end) : $value;
}
function get_booking_field_end_time($value,$order, $item, $product, $item_meta) {
return $this->booking ? date_i18n( wc_time_format(), $this->booking->end) : $value;
}
function get_booking_field_resource($value,$order, $item, $product, $item_meta) {
if (!$this->booking)
return $value;
$resource = $this->booking->get_resource();
return $resource ? $resource->get_name() : $value;
}
function get_booking_field_persons_total($value,$order, $item, $product,$item_meta) {
return $this->booking ? $this->booking->get_persons_total() : $value;
}
}
new WOE_Bookings();
add_action( 'woocommerce_add_order_item_meta', 'add_order_item_meta' , 10, 2);
function add_order_item_meta ( $item_id, $values ) {
if ( isset( $values [ 'booking_start_date' ] ) ) {
$custom_data = $values [ 'booking_start_date' ];
wc_add_order_item_meta( $item_id, ‘date',
$custom_data['booking_start_date'] );
}
}
You don't need to add any custom meta data to the order, as you can retrieve it easily (as you are expecting).
You will see in the following code example that displays the start date, the start time, the End date and the End time in admin single orders below shipping address:
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_some_booking_data_to_admin_orders', 10, 1 );
function display_some_booking_data_to_admin_orders( $order ){
// Retreive the booking Ids that belong to an order
$bookings_ids = get_posts( array(
'posts_per_page' => -1,
'post_type' => 'wc_booking', // booking post type
'post_parent' => $order->get_id(),
'post_status' => 'all',
'fields' => 'ids',
) );
if( ! empty($bookings_ids) ) {
echo '<div class="booking-items">';
// Loop through Bookings for the current order
foreach ( $bookings_ids as $booking_id ) {
// Get an instance of the WC_Booking Object
$booking = new WC_Booking( $booking_id );
// Get the related instance of the order Item Object
$item = $order->get_item($booking->order_item_id);
$name = $item->get_name(); // Get product name
// Start date and time
$start_datetime = $booking->get_start_date();
$start_dt_array = explode(', ', $start_datetime);
$start_date = reset($start_dt_array); // Start date
$start_time = end($start_dt_array); // Start time
// End date and time
$end_datetime = $booking->get_end_date();
$end_dt_array = explode(', ', $end_datetime);
$end_date = reset($end_dt_array); // End date
$end_time = end($end_dt_array); // End time
echo '<table style="border:solid 1px #eee; margin-bottom:12px;">
<thead style="background-color: #eee;">
<tr><td><strong>' . __("Booking") . ':</strong></td><td> ' . $name . ' <em><small>(' . $booking_id . ')</small></em></td></tr>
</thead>
<tbody>
<tr><td><strong>' . __("Start date") . ':</strong></td><td>' . $start_datetime . '</td></tr>
<tr><td><strong>' . __("End date") . ':</strong></td><td>' . $end_datetime . '</td></tr>
</tbody>
</table>';
}
echo '</div>';
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Addition for Exporting order data
Save booking data as custom order meta data (only handle one booking):
add_action( 'woocommerce_checkout_create_order', 'display_some_booking_data_to_admin_orders', 10, 1 );
function display_some_booking_data_to_admin_orders( $order ){
$cart_items = WC()->cart->get_cart(); // Get cart items
$cart_item = reset($cart_item); // First cart item
if( isset($cart_item['booking']) && ! empty($cart_item['booking']) ) {
$booking_id = $cart_item['booking']['_booking_id'];
$order->update_meta_data( '_booking_id', $booking_id ); // Save booking Id
// Get an instance of the WC_Booking Object
$booking = new WC_Booking( $cart_item['booking']['_booking_id'] );
// Start date and time
$start_datetime = $booking->get_start_date();
$start_dt_array = explode(', ', $start_datetime);
$order->update_meta_data( 'booking_start_datetime', $start_datetime ); // Save start date and time
$order->update_meta_data( 'booking_start_date', reset($start_dt_array) ); // Save start date
$order->update_meta_data( 'booking_start_time', end($start_dt_array) ); // Save start time
// End date and time
$end_datetime = $booking->get_end_date();
$end_dt_array = explode(', ', $end_datetime);
$order->update_meta_data( 'booking_end_datetime', $end_datetime ); // Save end date and time
$order->update_meta_data( 'booking_end_date', reset($end_dt_array) ); // Save end date
$order->update_meta_data( 'booking_end_time', end($end_dt_array) ); // Save end time
// Cost and quantiity
$order->update_meta_data( 'booking_cost', $cart_item['booking']['_cost'] ); // Save cost
$order->update_meta_data( 'booking_qty', $cart_item['booking']['_qty'] ); // Save quantity
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
This will allow you to export the booking data with your plugin.
Please, use this solution to filter by start date
https://wordpress.org/support/topic/filter-by-bookings-start-date/#post-12908495
if you still need help - please, submit ticket to https://algolplus.freshdesk.com/
thanks, Alex
(support of Advanced Order Export For WooCommerce)
Related
I am using JetAppoitment (crocoblock) to make services bookable.
I would like to add the appoitment date to the orders from the front-end side.
Here is the code I used :
add_filter( 'woocommerce_account_orders_columns', 'add_account_orders_column', 10, 1 );
function add_account_orders_column( $columns ){
$columns['custom-column'] = __( 'Date de livraison', 'woocommerce' );
return $columns;
}
add_action( 'woocommerce_my_account_my_orders_column_custom-column',
'add_account_orders_column_rows' );
function add_account_orders_column_rows( $order ) {
// Example with a custom field
if ( $value = $order->get_meta( '_appointment_date' ) ) {
echo esc_html( $value );
}
}
The first part of the code worked good, the extra column is here :
https://i.stack.imgur.com/kSLiq.png
The problem is I have no data...
Any idea to how to fix it?
Thanks
add_action('woocommerce_my_account_my_orders_column_custom-column',
'add_account_orders_column_rows');
function add_account_orders_column_rows($order) {
// Example with a custom field
if ($value = get_post_meta($order->get_id(), '_appointment_date')) {
echo esc_html($value);
}
}
I added 4 new meta data fields to each order. I can update these fields myself for each order from within the admin panel but there are 200 orders and it will take awhile.
I need automatically populate these meta fields for each order. Future orders will automatically be populated but I need to update all orders at this time.
I wrote the following code but it doesn't do anything:
add_action( 'woocommerce_loaded', 'update_existing_orders_with_new_meta' );
function update_existing_orders_with_new_meta(){
$order_ids = wc_get_order( $order_id );
// Loop through product Ids
foreach ( $order_ids as $order_id ) {
if ( $order_id->payment_method == 'cheque' ) {
$order_id->update_meta_data('ji_payment_status', '');
$order_id->update_meta_data('ji_payment_method', '');
$order_id->update_meta_data('ji_payment_date', '');
$order_id->update_meta_data('ji_payment_notes', '');
} else {
$order_id->update_meta_data('ji_payment_status', '1');
$order_id->update_meta_data('ji_payment_method', 'Credit Card');
$order_id->update_meta_data('ji_payment_date', date('F j, Y'));
$order_id->update_meta_data('ji_payment_notes', '');
}
}
}
Can someone walk me through how to do that?
You're using $order_ids = wc_get_order( $order_id ); while no $order_id has been set.
If it actually concerns 200 orders, you can use the following. When the action is completed, 'done' will appear in the footer. Then the code can be removed.
// Run once, delete afterwards
function set_meta_for_orders () {
// Get ALL orders (could be extended with multiple conditions)
// More info: https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query
$orders = wc_get_orders( array(
'limit' => 200, // Get 200 most recent orders
));
// NOT empty
if ( ! empty ( $orders ) ) {
// Loop
foreach ( $orders as $order ) {
// Payment method = cheque
if ( $order->get_payment_method() == 'cheque' ) {
$order->update_meta_data( 'ji_payment_status', '' );
$order->update_meta_data( 'ji_payment_method', '' );
$order->update_meta_data( 'ji_payment_date', '' );
$order->update_meta_data( 'ji_payment_notes', '' );
} else {
$order->update_meta_data( 'ji_payment_status', '1' );
$order->update_meta_data( 'ji_payment_method', 'Credit Card' );
$order->update_meta_data( 'ji_payment_date', date( 'F j, Y' ) );
$order->update_meta_data( 'ji_payment_notes', '' );
}
// Save
$order->save();
}
// Output
echo 'Done!';
}
}
// Call function
add_action( 'wp_footer', 'set_meta_for_orders' );
Note: this will work for some limited orders. When it concerns many orders, other solutions such as custom SQL are recommended.
I am trying to add a column in WooCommerce admin order list where the value from the Pickup Date from the plugin Local Pickup Plus should be displayed. This gives a better overview of pickup dates.
Bonus: If possible, it would be great if the column could be clicked so that it sorts all pickup dates (first pickup date shows first etc.)
So far I got the following code which successfully added a column, now the column should be populated with pickup date data.
add_filter( 'manage_edit-shop_order_columns', 'bbloomer_add_new_order_admin_list_column' );
function bbloomer_add_new_order_admin_list_column( $columns ) {
$columns['pickup_date'] = 'Afhentningsdato';
return $columns;
}
add_action( 'manage_shop_order_posts_custom_column', 'bbloomer_add_new_order_admin_list_column_content' );
function bbloomer_add_new_order_admin_list_column_content( $column ) {
global $post;
if ( 'pickup_date' === $column ) {
// Add pickup date for each order here
}
}
This should suffice, explanation via comment tags added to the code
Appointment start & end values are set to timestamps so date function is used to format to a local time/date
// Add a Header
function filter_manage_edit_shop_order_columns( $columns ) {
// Add new column
$columns['pickup_date'] = 'Afhentningsdato';
return $columns;
}
add_filter( 'manage_edit-shop_order_columns', 'filter_manage_edit_shop_order_columns', 10, 1 );
// Populate the Column
function action_manage_shop_order_posts_custom_column( $column, $post_id ) {
// Compare
if ( $column == 'pickup_date' ) {
// Get order
$order = wc_get_order( $post_id );
// Loop though order shipping methods
foreach( $order->get_items('shipping') as $shipping_item ) {
// Get appoitment start
$pickup_appointment_start = $shipping_item->get_meta( '_pickup_appointment_start' );
$starttime = date( 'H:i', $pickup_appointment_start );
$startdate = date( 'd-m-Y', $pickup_appointment_start );
// Get appointment end
$pickup_appointment_end = $shipping_item->get_meta( '_pickup_appointment_end' );
$endtime = date( 'H:i', $pickup_appointment_end );
$enddate = date( 'd-m-Y', $pickup_appointment_end );
echo '<p>ST = ' . $starttime . '</p>';
echo '<p>SD = ' . $startdate . '</p>';
echo '<p>ET = ' . $endtime . '</p>';
echo '<p>ED = ' . $enddate . '</p>';
}
}
}
add_action( 'manage_shop_order_posts_custom_column' , 'action_manage_shop_order_posts_custom_column', 10, 2 );
On the checkout page of my WooCommerce based site, users will have a list of shipping methods to choose from depending on what they are purchasing
This is the list I want to capture:
Things like
“Free Shipping” for orders over a certain price
“Freight Shipping” for certain items, and so on.
My goal, is to display ALL available methods for each specific order, and display it on the “Edit Order / Order Details” page in the Admin view.
A small feature that would help us be able to quickly identify what option people are choosing more often, depending on the choices that they have available.
This is what I have so far:
add_action( 'woocommerce_checkout_update_order_meta', 'save_available_shipping_methods' );
function save_available_shipping_methods( $order_id ) {
$shippingmethods = WC()->cart->get_shipping_methods();
update_post_meta( $order_id, '_shipping_methods', $shippingmethods );
}
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'get_available_shipping_methods', 10, 1 );
function get_available_shipping_methods($order){
$order = wc_get_order( $order_id );
if ( $order ) {
echo '<p><strong>'.__('Available Shipping Methods: ').'</strong> ' . get_post_meta($order->get_shipping_methods(), '_shipping_field_value', true ) . '</p>';
}
}
I'll attach a picture as well to maybe make things a little easier to follow.
This is where I would like to put it. The current hook places the field underneath the shipping address
In the woocommerce_checkout_update_order_meta hook, the available shipping packages are stored via update_post_meta
Comments with explanation added in the code
function action_woocommerce_checkout_update_order_meta( $order_id ) {
// Get shipping packages
$packages = WC()->shipping()->get_packages();
// Set array
$rate_labels = array();
// Loop trough packages
foreach ( $packages as $key => $package ) {
// Loop through package rates
foreach( $package['rates'] as $rate_id => $rate ) {
// Push to array
$rate_labels[] = $rate->get_label();
}
}
// NOT empty
if ( ! empty ( $rate_labels ) ) {
// Update post meta
update_post_meta( $order_id, '_available_shipping_methods', $rate_labels );
}
}
add_action( 'woocommerce_checkout_update_order_meta', 'action_woocommerce_checkout_update_order_meta', 10, 1 );
// Display on the order edit page (backend)
function action_woocommerce_admin_order_data_after_shipping_address( $order ) {
// Get meta
$rate_labels = $order->get_meta( '_available_shipping_methods' );
// True
if ( $rate_labels ) {
// Loop trough rate labels
foreach( $rate_labels as $rate_label ) {
// Output
echo '<p>' . $rate_label . '</p>';
}
}
}
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'action_woocommerce_admin_order_data_after_shipping_address', 10, 1 );
In case anyone is wondering, this is the final result. It will loop through each order to find the available shipping methods at the time, along with how much it was quoted for.
// Capture the available shipping methods, and costs:
function action_woocommerce_checkout_update_order_meta( $order_id ) {
// Get shipping packages
$packages = WC()->shipping()->get_packages();
// Set array
$rate_labels = array();
$rate_costs = array();
// Loop trough packages
foreach ( $packages as $key => $package ) {
// Loop through package rates
foreach( $package['rates'] as $rate_id => $rate ) {
// Push to array
$rate_labels[] = $rate->get_label();
$rate_costs[] = $rate->get_cost();
}
}
// NOT empty
if ( ! empty ( $rate_labels ) ) {
// Update post meta
update_post_meta( $order_id, '_available_shipping_methods', $rate_labels );
update_post_meta( $order_id, '_available_shipping_method_cost', $rate_costs );
}
}
add_action( 'woocommerce_checkout_update_order_meta', 'action_woocommerce_checkout_update_order_meta', 10, 1 );
// Make it display on the edit order page:
function action_woocommerce_admin_order_data_after_shipping_address( $order ) {
// Get meta
$rate_labels = $order->get_meta( '_available_shipping_methods' );
$rate_costs = $order->get_meta( '_available_shipping_method_cost' );
$methods = array ( $rate_labels, $rate_costs );
// True
if ( $rate_labels ) {
// Loop
echo '<p><strong>Shipping Methods: </strong>';
foreach(array_combine($rate_labels, $rate_costs) as $rate_label => $rate_cost) {
echo '<p>' . $rate_label . ' - $' . $rate_cost . '</p>';
}
}
}
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'action_woocommerce_admin_order_data_after_shipping_address', 10, 1 );
I have implemented a custom HTML Form and asking for some data which my customers will pass to place order successfully. Without these details my order has no importance.
For HTML form, I am referencing some custom PHP script which is below and which processes POST data from the Form and creates Cart with these data programmatically. Thanks #LoicTheAztec to help me achieve this.
The script.php file code:
<?php
require_once("../wp-load.php");
$customer_name = $_POST["customer_name"];
$customer_email = $_POST["customer_email"];
$customer_sex = $_POST["customer_sex"];
$customer_age = $_POST["customer_age"];
$product_id = $_POST["product_id"];
$custom_data = array(); // Initializing
if( isset($_POST['customer_name']) && ! empty($_POST['customer_name']) )
$custom_data['custom_data']['name'] = $_POST['customer_name'];
if( isset($_POST['customer_email']) && ! empty($_POST['customer_email']) )
$custom_data['custom_data']['email'] = $_POST['customer_email'];
if( isset($_POST['customer_sex']) && ! empty($_POST['customer_sex']) )
$custom_data['custom_data']['sex'] = $_POST['customer_sex'];
if( isset($_POST['customer_age']) && ! empty($_POST['customer_age']) )
$custom_data['custom_data']['age'] = $_POST['customer_age'];
global $woocommerce;
if (WC()->cart->add_to_cart( $product_id, '1', '0', array(), $custom_data )) {
var_dump($product_id);
} else {
var_dump($customer_name);
}
header("Location: ./checkout");
?>
As you see we have programmatically created a cart item using WC_Cart add_to_cart() method. So, all custom data is being saved to Cart as custom cart item data.
And now, we have also placed a code block into functions.php to print these data on Checkout page.
add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' );
function my_custom_checkout_field( $checkout ) {
//var_dump($checkout);
global $woocommerce;
echo '<div id="my_custom_checkout_field"><h2>' . __('Child Info') . '</h2>';
foreach ( $woocommerce->cart->get_cart() as $cart_item ) {
if( isset($cart_item['custom_data']) ) {
$custom_data = $cart_item['custom_data'];
echo("<div>Name: <strong>" . $custom_data['name'] . "</strong></div>");
echo("<div>Email: <strong>" . $custom_data['email'] . "</strong></div>");
echo("<div>Gender: <strong>" . $custom_data['sex'] . "</strong></div>");
echo("<div>Age: <strong>" . $custom_data['age'] . "</strong></div>");
}
}
echo '</div>';
}
Now, I am trying to add these data printed on Checkout page to the Order page as well. As my order can't be completed without these data, user need to fill up these data and when he creates order, these data needs to be passed to the Order Summary page as well. And admin also needs to be able to see these data so he can process the order.
I hope this description clears everything and thanks again #LoicTheAztec to make me able to do this. Thank you very much.
Update 2 - Two steps
1) Saving data:
We will save this custom customer data as "Hidden" order "item" meta data and then as order meta data too as this is related to subscriptions with a unique order item:
// Utility function: array of custom customer key/label pairs
function custom_data_keys_labels(){
return array(
'name' => __('Customer name'), 'email' => __('Customer email'),
'sex' => __('Customer gender'), 'age' => __('Customer age'),
);
}
// Add/save custom field value as custom HIDDEN order item meta data
add_action( 'woocommerce_checkout_create_order_line_item', 'custom_field_update_order_item_meta', 20, 4 );
function custom_field_update_order_item_meta( $item, $cart_item_key, $values, $order ) {
if ( ! isset( $values['custom_data'] ) )
return;
$custom_data = $values['custom_data'];
$meta_data = array();
$labels_keys = custom_data_keys_labels();
foreach( $labels_keys as $key => $label ){
if ( isset( $custom_data[$key] ) )
$meta_data[$key] = $custom_data[$key];
}
if ( sizeof( $meta_data ) > 0 )
$item->update_meta_data( __('_customer_data'), $meta_data );
return $cart_item_data;
}
// Add/save custom fields values as custom order meta data
add_action( 'woocommerce_checkout_create_order', 'my_custom_checkout_field_update_order_meta', 20, 2 );
function my_custom_checkout_field_update_order_meta( $order, $data ) {
$order_items = $order->get_items(); // Order itesm
$item = reset($order_items); // Keep only the first order item
$item_data = $item->get_meta( '_customer_data' ); // Get custom customer data
if( is_array($item_data) && sizeof($item_data) > 0 ){
foreach( $item_data as $key => $value ) {
if ( isset( $item_data[$key] ) )
$order->update_meta_data( '_customer_' . $key, $value );
}
// Mark as data saved
$order->update_meta_data( '_customer_data_set', true );
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
2) Displaying saved custom data:
The code below also use our utility function custom_data_keys_labels()…
// Order pages (frontend and admin) display
add_filter( 'woocommerce_order_details_after_order_table' , 'display_admin_order_meta_cutom_data', 20, 1 ); // Front
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_admin_order_meta_cutom_data', 20, 1 ); // Admin
function display_admin_order_meta_cutom_data( $order ){
$labels_keys = custom_data_keys_labels();
if( $order->get_meta( '_customer_data_set' ) ){
if( is_admin() ){ // Admin
echo '<p>';
foreach( $labels_keys as $key => $label ){
if ( $order->get_meta( '_customer_' . $key ) )
echo '<strong>' . $label . ':</strong> ' . $order->get_meta( '_customer_' . $key ) . '<br>';
}
echo '</p>';
}
else { // Front end: order view and Order received (thankyou)
echo '<table class="woocommerce-table"><tbody>';
foreach( $labels_keys as $key => $label ){
if ( $order->get_meta( '_customer_' . $key ) )
echo '<tr><th>' . $label . ':</th><td>' . $order->get_meta( '_customer_' . $key ) . '</td></tr>';
}
echo '</tbody></table>';
}
}
}
// Email notifications display
add_filter( 'woocommerce_email_order_meta_fields' , 'display_email_cutom_data', 20, 3 );
function display_email_cutom_data ( $fields, $sent_to_admin, $order ) {
$labels_keys = custom_data_keys_labels();
if( $order->get_meta( '_customer_data_set' ) ){
foreach( $labels_keys as $key => $label ){
$fields['customer_' . $key] = array(
'label' => $label,
'value' => $order->get_meta( '_customer_' . $key ),
);
}
}
return $fields;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.