I have a different kind of scenario then the typical custom fields (I suppose). I am not getting custom values (fields) from user in the form rather I have an implementation which adds:
ColorName
Size
City
These are from a custom product flow which adds custom attributes to the cart, here is how I am doing that:
add_action('wp_ajax_wdm_add_user_custom_data_options', 'wdm_add_user_custom_data_options_callback');
add_action('wp_ajax_nopriv_wdm_add_user_custom_data_options', 'wdm_add_user_custom_data_options_callback');
function wdm_add_user_custom_data_options_callback()
{
// print_r($_POST);
$productIDM = $_POST['product_id'];
// case swith
switch ($productIDM) {
case "Ace Dura Silk":
$productID = 3254;
break;
case "Ace Matt Finish":
$productID = 3232;
break;
case "Ace Plastic Emulsion":
$productID = 3276;
break;
case "Ace Weather Defender":
$productID = 2991;
break;
case "Overall Plasticoat":
$productID = 3112;
break;
}
$colorname = $_POST['colorname'];
$cityname = $_POST['cityname'];
$size = $_POST['size'];
$price = $_POST['price'];
global $woocommerce;
$woocommerce->cart->add_to_cart( $productID, 1 );
// die();
// echo 'I am in...';
$result = array(
'status' => true
);
echo json_encode($result);
}
add_filter('woocommerce_add_cart_item_data','wdm_add_item_data',1,10);
function wdm_add_item_data($cart_item_data, $product_id) {
global $woocommerce;
$new_value = array();
$new_value['_custom_options'] = $_POST['custom_options'];
if(empty($cart_item_data)) {
return $new_value;
} else {
return array_merge($cart_item_data, $new_value);
}
}
add_filter('woocommerce_get_cart_item_from_session', 'wdm_get_cart_items_from_session', 1, 3 );
function wdm_get_cart_items_from_session($item,$values,$key) {
if (array_key_exists( '_custom_options', $values ) ) {
$item['_custom_options'] = $values['_custom_options'];
}
return $item;
}
add_filter('woocommerce_cart_item_name','add_usr_custom_session',1,3);
function add_usr_custom_session($product_name, $values, $cart_item_key ) {
$return_string = $product_name . "<div class='cart_subitems_custom'><br /><small>".$values['_custom_options']['colorname']."</small><br /><small>".$values['_custom_options']['cityname']."</small><br /><small>".$values['_custom_options']['size']."</small></div>" ; //. "<br />" . print_r($values['_custom_options']);
return $return_string;
}
add_action('woocommerce_add_order_item_meta','wdm_add_values_to_order_item_meta',1,2);
function wdm_add_values_to_order_item_meta($item_id, $values) {
global $woocommerce,$wpdb;
wc_add_order_item_meta($item_id,'_colorname',$values['_custom_options']['colorname']);
wc_add_order_item_meta($item_id,'_cityname',$values['_custom_options']['cityname']);
wc_add_order_item_meta($item_id,'_size',$values['_custom_options']['size']);
}
add_action( 'woocommerce_before_calculate_totals', 'update_custom_price', 1, 1 );
function update_custom_price( $cart_object ) {
foreach ( $cart_object->cart_contents as $cart_item_key => $value ) {
// Version 2.x
//$value['data']->price = $value['_custom_options']['custom_price'];
// Version 3.x / 4.x
if($value['_custom_options']['price'] == null){
echo"";
}else{
$value['data']->set_price($value['_custom_options']['price']);
}
}
}
I am getting these custom values almost everywhere except Email Notification.
Here is what normal product order edit shows:
Here is how I am getting the custom product in order edit page:
I have tried all the solution I can possibly find (filter & action hooks) but nothing works for me.
I have tried first answer from this:
add_action( 'woocommerce_checkout_create_order_line_item', 'custom_checkout_create_order_line_item', 20, 4 );
function custom_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
if( isset( $values['colorname'] ) )
$item->add_meta_data( __('DCM Shade'), $values['_colorname'] );
}
Also the common method I found everywhere:
function custom_woocommerce_email_order_meta_fields( $fields, $sent_to_admin, $order ) {
// Get meta
$color = $order->get_meta( 'colorname', true );
// NOT empty
if( ! empty( $color ) ) {
$fields['colorname'] = array(
'label' => __( 'Shade' ),
'value' => $color,
);
}
// Get (other) meta
$shipping_email = $order->get_meta( '_cityname', true );
// NOT empty
if ( ! empty( $shipping_email ) ) {
$fields['_cityname'] = array(
'label' => __( 'City' ),
'value' => $shipping_email,
);
}
return $fields;
}
add_filter( 'woocommerce_email_order_meta_fields', 'custom_woocommerce_email_order_meta_fields', 10, 3 );
But I can't get the custom fields.
What am I doing wrong can please anyone please guide me.
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column',11);
function custom_shop_order_column($columns)
{
$reordered_columns = array();
// Woocommerce version 3.3+ compatibility
$location_after = version_compare( WC_VERSION, '3.3', '<' ) ? 'order_notes' : 'order_status';
// Inserting the new column in a specific location
foreach( $columns as $key => $column){
$reordered_columns[$key] = $column;
if( $key == $location_after ){
$reordered_columns['pvdl']= __('PVF/DL', 'woocommerce');
}
}
return $reordered_columns;
}
add_action( 'manage_shop_order_posts_custom_column' , 'custom_orders_list_column_content', 10, 2 );
function custom_orders_list_column_content( $column, $post_id )
{
if('pvdl' == $column){
//echo 'Working on it';
$order = wc_get_order($post_id);
$email = $order->get_billing_email();
//var_dump($email);
mailchecker($email);
}
}
function mailchecker($test_mail){
$life = array();
array_push($life, $test_mail);
var_dump($life);
}
I was trying to push the emails to an empty array but it only shows the current order email. I know I am doing something dumb here but I am stuck. Any kind soul wanna help me with this?
You Should try this:
add_action( 'admin_init' , 'custom_orders_list_column_content', 20, 3 ); // change accordingly
function custom_orders_list_column_content()
{
$billing_email = $skip_duplicate = array();
$customer_orders = get_posts( array(
'post_type' => 'shop_order',
'post_status' =>'wc-completed', // change accordingly
'posts_per_page' => '-1'
) );
foreach( $customer_orders as $order){
$order_id = $order->ID;
if($order_id){
$order = wc_get_order( $order_id );
$bemail = $order->get_billing_email();
if(!in_array($bemail, $skip_duplicate)){
$billing_email[] = $bemail;
array_push($skip_duplicate,$bemail);
}
}
}
echo "<pre>";print_r($billing_email); exit;
}
You can change "post_status" and "add_action" events accordingly.
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)
I'm trying to add meta data to each product when an order has been created by using the woocommerce_checkout_create_order_line_item.
However, I can't seem to access the ID of the order.
I've used print_r($order) and can see the order details in there but I can't see the ID of the order within the object. Is this because it hasn't been generated yet?
add_action('woocommerce_checkout_create_order_line_item', array($this, 'ticket_meta_to_line_item'), 20, 4 );
function ticket_meta_to_line_item( $item, $cart_item_key, $values, $order )
{
$_p = $item->get_product();
$key = 'Draw #';
$order_id = $order->id;
error_log( print_r( $order, true ) );
if ( false !== ( $value = $_p->get_meta( $key, true ) ) )
{
$numbers = $this->add_tickets_to_order_meta($order_id, $order->get_user_id(), $_p->id);
error_log( print_r( $numbers, true ) );
$item->add_meta_data( $key , 1 , true );
}
}
If you wondering to add meta data, then there is no need to find the Order_ID, from below code you can easily do so.
function _woocommerce_add_order_item_meta_new_ver($item,$cart_key,$values) {
//HERE product_meta is just a random key I have used here, you have to use your key here
if (isset ( $values ['product_meta'] )) {
foreach ( $values ['product_meta'] as $key => $val ) {
$order_val = stripslashes( $val );
if($val) {
if($key == 'your_cart_item_key') {
$item->add_meta_data('Your Key',$order_val);
}
}
}
}
}
//This will add "Your Key" in your order_item_meta, just make sure you have used the same key "your_cart_item_key" in your cart_item_meta key too.
You can access order id using below code.
$order_id = $order->get_order_number();
Tested and works well
I've noticed a strange behaviour of one of my functions. Just take a look. Using first function I'm displaying some custom fields data in the backend:
add_filter( 'manage_edit-shop_order_columns', 'MY_COLUMNS_FUNCTION', 10 );
function MY_COLUMNS_FUNCTION( $columns ) {
$new_columns = ( is_array( $columns ) ) ? $columns : array();
unset( $new_columns['order_actions'] );
//edit this for you column(s)
//all of your columns will be added before the actions column
$new_columns['product_name'] = 'Product';
$new_columns['authors_income'] = 'Author';
$new_columns['order_actions'] = $columns['order_actions'];
return $new_columns;
}
add_action( 'manage_shop_order_posts_custom_column', 'MY_COLUMNS_VALUES_FUNCTION', 2 );
function MY_COLUMNS_VALUES_FUNCTION( $column ) {
global $post;
$order = new WC_Order( $post->ID );
$items = $order->get_items();
//start editing, I was saving my fields for the orders as custom post meta
//if you did the same, follow this code
if ( $column == 'authors_income' ) {
foreach ( $items as $item ) {
echo $item['PLN-dla-autora'];
echo ' zł';
}
}
if ( $column == 'product_name' ) {
foreach ( $items as $item ) {
echo $item['name'];
}
}
}
add_filter( "manage_edit-shop_order_sortable_columns", 'MY_COLUMNS_SORT_FUNCTION' );
function MY_COLUMNS_SORT_FUNCTION( $columns ) {
$custom = array(
//start editing
'authors_income' => 'PLN-dla-autora',
'product_name' => 'name'
//stop editing
);
return wp_parse_args( $custom, $columns );
Everything works there like a charm. Then I have second function, which somehow does the same, yet it will print the data into the CSV file. Unfortunatelly, this code doesnt work (it display only column header, no data included). I dont see any major differences between those functions so why is that?
function wc_csv_export_modify_column_headers( $column_headers ) {
$new_headers = array(
'author_income' => 'PLN dla autora',
// add other column headers here in the format column_key => Column Name
);
return array_merge( $column_headers, $new_headers );
}
add_filter( 'wc_customer_order_csv_export_order_headers', 'wc_csv_export_modify_column_headers' );
// set the data for each for custom columns
function wc_csv_export_modify_row_data( $order_data, $order ) {
$custom_data = array(
'author_income' => get_post_meta( $order->id, 'PLN dla autora', true ),
// add other row data here in the format column_key => data
);
return array_merge( $order_data, $custom_data );
}
add_filter( 'wc_customer_order_csv_export_order_row', 'wc_csv_export_modify_row_data', 10, 2 );