How to save from WooCommerce checkout a custom checkbox field state? - php

I have a problem with the update_post_meta function.
I have a user submitted value, which I pass via $_POST and then saving to post meta.
All is working fine, but when the value is '0' the post meta is not updated.
This is My code:
// Add custom checkout field: woocommerce_review_order_before_submit
add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field_ritiro_sede' );
function my_custom_checkout_field_ritiro_sede() {
echo '<div class="cw_custom_class"><h3>'.__('Ritiro presso sede CER S.r.l. &nbsp').'</h3>';
echo '<div id="my_custom_checkout_field">';
woocommerce_form_field( 'ritiro_sede', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('SI'),
), WC()->checkout->get_value( 'ritiro_sede' ) );
echo '</div>';
}
// Save the custom checkout field in the order meta, when checkbox has been checked
add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta_ritiro_sede', 10, 1 );
function custom_checkout_field_update_order_meta_ritiro_sede( $order_id ) {
if ( ! empty( $_POST['ritiro_sede'] ) )
update_post_meta( $order_id, 'ritiro_sede', $_POST['ritiro_sede'] );
if ( isset( $_POST['ritiro_sede'] ) )
update_post_meta( $order_id, 'ritiro_sede', $_POST['0'] );
}
Does anyone have any idea what might be wrong?

Since WooCommerce 3, here below is the best way to save your custom checkout checkbox field value as order meta data (including when the checkbox is unchecked):
// Save the custom checkout checkbox field as the order meta
add_action( 'woocommerce_checkout_create_order', 'custom_checkout_field_update_order_meta', 10, 2 );
function custom_checkout_field_update_order_meta( $order, $data ) {
$value = isset($_POST['ritiro_sede']) ? '1' : '0'; // Set the correct values
$order->update_meta_data( 'ritiro_sede', $value );
}
Now as user meta data is used by WC_Checkout get_value() method in your first function on:
WC()->checkout->get_value( 'ritiro_sede' )
So if you want the submitted value to be displayed on checkout page for the next purchase, you will need to save that custom checkout field also as user meta data using instead the following:
// Save the custom checkout checkbox field as the order meta and user meta
add_action( 'woocommerce_checkout_create_order', 'custom_checkout_field_update_order_meta', 10, 2 );
function custom_checkout_field_update_order_meta( $order, $data ) {
$value = isset($_POST['ritiro_sede']) ? '1' : '0'; // Set the correct values
// Save as custom order meta data
$order->update_meta_data( 'ritiro_sede', $value );
// Save as custom user meta data
if ( get_current_user_id() > 0 ) {
update_user_meta( get_current_user_id(), 'ritiro_sede', $value );
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.

Related

Add a custom field as a default value in WooCommerce backend and populate previous orders

I know that the first part of my question is possible but haven't found how to add a custom field to all orders in the back end and then populate it with a default value.
I'm looking to create a custom field called "Merchant Identifier" and then populate that with a default name e.g "Company X".
I looked at this code which adds an input value at the checkout and then shows in an order summary, but I only need a field adding as a custom field to every order in the back end.
/**
* Process the checkout
*/
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['billing_phone_new'] )
wc_add_notice( __( 'Phone 2 is compulsory. Please enter a value' ), 'error' );
}
/**
* Update the order meta with field value
*/
add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );
function my_custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['billing_phone_new'] ) ) {
update_post_meta( $order_id, 'billing_phone_new', sanitize_text_field( $_POST['billing_phone_new'] ) );
}
}
/**
* Display field value on the order edit page
*/
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>'.__('Phone 2').':</strong> <br/>' . get_post_meta( $order->get_id(), 'billing_phone_new', true ) . '</p>';
}
Once that custom field appears on all new and old orders I can then add this add this as a column in a scheduled CSV export (that's for later - I just need to achieve the first part).
I'm not sure whether I need to have a hidden field in the checkout first with a default value OR whether I can just add a custom field that shows on all the orders in the back end using a different method.
Anyone able to help?
Thanks
For new orders you can use the following
// Update the order meta with value
function action_woocommerce_checkout_update_order_meta( $order_id ) {
// Meta value
$meta_value = 'Company X';
update_post_meta( $order_id, 'merchant_identifier', $meta_value );
}
add_action( 'woocommerce_checkout_update_order_meta', 'action_woocommerce_checkout_update_order_meta', 10, 1 );
// OPTIONAL (will still work without this code, this is just to show it visually)
// Display field value on the order edit page
function action_woocommerce_admin_order_data_after_billing_address( $order ) {
echo '<p><strong>' . __( 'Merchant Identifier', 'woocommerce') . ':</strong> ' . $order->get_meta( 'merchant_identifier' ) . '</p>';
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'action_woocommerce_admin_order_data_after_billing_address', 10, 1 );
For existing orders you can perform the following function, after it has been executed (view any page - frontend) it may be removed.
// Run once, delete afterwards
function set_meta_for_old_orders () {
// Get ALL orders where meta key not exists
$orders = wc_get_orders( array(
'limit' => -1, // Query all orders
'meta_key' => 'merchant_identifier', // Post meta_key
'meta_compare' => 'NOT EXISTS', // Comparison argument
));
if ( ! empty ( $orders ) ) {
// Meta value
$meta_value = 'Company X';
foreach ( $orders as $order ) {
$order->update_meta_data( 'merchant_identifier', $meta_value );
$order->save();
}
echo 'Done!';
}
}
// Call function
add_action( 'wp_footer', 'set_meta_for_old_orders' );

Save product custom-field as custom order item metadata for WooCommerce admin manual orders

Using Pass custom product meta data to the order in Woocommerce 3 answer code, Is it possible to save and display custom metadata when the product is added manually from backend when creating orders manually from the backend?
That is my code (lightly changed):
// Admin products: Display custom Field
add_action( 'woocommerce_product_options_general_product_data', 'product_options_general_product_data_add_field' );
function product_options_general_product_data_add_field() {
global $post;
echo '<div class="options_group">';
woocommerce_wp_select( array(
'id' => '_cost_centre',
'label' => __( 'Cost Centre', 'woocommerce' ),
'options' => array(
'MFEG' => __( 'MFEG', 'woocommerce' ), // Default displayed option value
'YDIT' => __( 'YDIT', 'woocommerce' ),
)
) );
echo '</div>';
}
// Admin products: Save custom Field
add_action( 'woocommerce_process_product_meta', 'product_options_general_product_data_save_field' );
function product_options_general_product_data_save_field( $post_id ){
if( isset( $_POST['_cost_centre'] ) )
update_post_meta( $post_id, '_cost_centre', esc_attr( $_POST['_cost_centre'] ) );
}
// Order items: Save product "Cost centre" as hidden order item meta data
add_action('woocommerce_checkout_create_order_line_item', 'save_file_type_as_order_item_meta', 20, 4);
function save_file_type_as_order_item_meta($item, $cart_item_key, $values, $order) {
if ( $cost_centre = $values['data']->get_meta('_cost_centre') ) {
$item->update_meta_data( '_cost_centre', $cost_centre ); // Save as order item (visble on admin only)
}
}
This works fine when the order is created by the client from the frontend. But when admin creates an order manually from the backend and adds the product, the custom metadata is not visible.
How to solve this problem for orders created manually, allowing to add product custom field as custom order item data?
Update 3
For manual backend orders, you can try to use woocommerce_before_save_order_item dedicated action hook as follow (code based on your question code):
add_action( 'woocommerce_before_save_order_item', 'action_before_save_order_item_callback' );
function action_before_save_order_item_callback( $item ) {
$cost_centre = $item->get_meta('_cost_centre');
// If custom meta data is not saved as order item
if ( empty($cost_centre) ) {
// Get custom meta data from the product
$cost_centre = get_post_meta( $item->get_product_id(), '_cost_centre', true );
$cost_centre = empty($cost_centre) ? 'MFEG' : $cost_centre;
// Save it as custom order item (if defined)
$item->update_meta_data( '_cost_centre', $cost_centre );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Addition: Make the order item custom meta data visible to customer
If you want this order item meta data to be visible on customer orders and email notifications, you will replace the order item meta key from '_cost_centre' to 'Cost centre' as follow:
add_action( 'woocommerce_before_save_order_item', 'action_before_save_order_item_callback' );
function action_before_save_order_item_callback( $item ) {
$cost_centre = $item->get_meta('_cost_centre');
// If custom meta data is not saved as order item
if ( empty($cost_centre) ) {
// Get custom meta data from the product
$cost_centre = get_post_meta( $item->get_product_id(), 'Cost centre', true );
$cost_centre = empty($cost_centre) ? 'MFEG' : $cost_centre;
// Save it as custom order item (if defined)
$item->update_meta_data( 'Cost centre', $cost_centre );
}
}
This time it will be visible on customer orders and emails.
You will need also to change your last function on your question code to:
// Order items: Save product "Cost centre" as visible order item meta data
add_action('woocommerce_checkout_create_order_line_item', 'save_file_type_as_order_item_meta', 20, 4);
function save_file_type_as_order_item_meta($item, $cart_item_key, $values, $order) {
if ( $cost_centre = $values['data']->get_meta('_cost_centre') ) {
$item->update_meta_data( 'Cost centre', $cost_centre ); // Save as order item (visible everywhere)
}
}
Note: When the order item custom meta key starts with an underscore, it's hidden.

Display custom payment field in Woocommerce Admin, Orders and emails

I need to display my custom checkout fields in admin orders page, thank_you and email notifications.
I am using Validate and save additional checkout field for specific payment gateway in Woocommerce answer code to show, validate and save my custom field.
From Woocommerce display custom field data on admin order details I am trying to display my custom field saved inputted value.
This is the code I have so far:
// Display field value on the order edit page
add_action( 'woocommerce_admin_order_data_after_billing_address',
'show_Ean_nummer_in_admin', 10, 1 );
function show_Ean_nummer_in_admin ( $order ){
// Get "ean" custom field value
$udfyld_ean = get_post_meta( $order_id, '_udfyld_ean', true );
// Display "ean" custom field value
echo '<p>'.__('EAN', 'woocommerce') . $udfyld_ean . '</p>';
}
// Display field value on the order emails
add_action( 'woocommerce_email_order_details', 'ean_in_emails' 50, 1 );
function ean_in_emails( $order, $sent_to_admin, $plain_text, $email ){
// Get "ean" custom field value
$udfyld_ean = get_post_meta( $order_id, '_udfyld_ean', true );
// Display "ean" custom field value
echo '<p>'.__('EAN', 'woocommerce') . $udfyld_ean . '</p>';
}
// Display field value in thank you
add_action( 'woocommerce_thankyou', 'ean_in_thankyou' );
function ean_in_thankyou() {
// Get "ean" custom field value
$udfyld_ean = get_post_meta( $order_id, '_udfyld_ean', true );
// Display "ean" custom field value
echo '<p>'.__('EAN', 'woocommerce') . $udfyld_ean . '</p>';
}
But It's not working. The field does get appended to the database, but does not display anywhere:
How can I display the field properly?
The following code will display your "Udfyld EAN" custom field value in orders and email notifications:
1) To display that in Woocommerce order admin single pages:
// Display field value on the admin order edit page
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'custom_field_admin_display_order_meta', 10, 1 );
function custom_field_admin_display_order_meta( $order ){
$business_address = get_post_meta( $order->get_id(), 'Business Address?', true );
if( $udfyld_ean = $order->get_meta('_udfyld_ean') )
echo '<p><strong>'.__('Udfyld EAN', 'woocommerce').': </strong> ' . $udfyld_ean . '</p>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
2) To display that on Order received, Order view and email notifications you will use:
add_filter( 'woocommerce_get_order_item_totals', 'add_udfyld_ean_row_to_order_totals', 10, 3 );
function add_udfyld_ean_row_to_order_totals( $total_rows, $order, $tax_display ) {;
$new_total_rows = [];
foreach($total_rows as $key => $total ){
$new_total_rows[$key] = $total;
if( $order->get_meta('_udfyld_ean') && 'payment_method' === $key ){
$new_total_rows['udfyld_ean'] = array(
'label' => __('Udfyld EAN', 'woocommerce'),
'value' => esc_html( $order->get_meta('_udfyld_ean') ),
);
}
}
return $new_total_rows;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
You are using following code to fetch the value of _udfyld_ean :
get_post_meta( $order_id, '_udfyld_ean', true );
But the problem is, you have not defined $order_id anywhere. You will need to pass valid value of order ID to get the expected output.

Add cart meta value for a product after an order request is submitted

I have a multi vendor restaurant WooCommerce site. And one person can order max from one restaurant.On a restaurant when adding product to cart I have added an extra meta-field restaurant_id which is the id of that restaurant. In a cart , all the products have same restaurant_id.
i.e : I have two items in cart having product_id : 12 and 13 but they have same restaurant_id : 366.
I need to add this restaurant_id as meta-field in order-complete or order-process action.because i need to show restaurant name on customers account page.
Or any easy way to do that?
I have tried below code as test
add_action( 'woocommerce_checkout_update_order_meta', 'add_field_to_order' );
function add_field_to_order( $order_id ) {
update_post_meta( $order_id, 'new_field', 'new_value' );
}
But it does not add any meta-field and meta-value to order
— Update —
As I understand now, this custom field already exist and you get this restaurant_id value in cart. So you would like to display that in your view order (thank you and my account pages) and may be on emails…
Here is that code:
//
// ADD HIDDEN IMPUT FIELDS TO THE CHECKOUT
//
add_action( 'woocommerce_after_order_notes', 'checkout_custom_hidden_imput_field' );
function checkout_custom_hidden_imput_field( $checkout ) {
foreach(WC()->cart->get_cart() as $item){
$restaurant_id = $item['restaurant_id'];
break;
}
echo '<div id="custom_checkout_fields" class="custom-hidden-checkout-field">
<input type="hidden" id="restaurant_id" name="restaurant_id" value="'.$restaurant_id.'" />
</div>';
}
//
// SAVE THE ORDER META WITH FIELD VALUE
//
add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta' );
function custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['restaurant_id'] ) ) {
add_post_meta( $order_id, '_restaurant_id', $_POST['restaurant_id'] );
}
}
//
// DISPLAY FIELD VALUE ON THE ORDER EDIT PAGE (NOT IN CUSTOM FIELDS METABOX)
//
add_action( 'woocommerce_admin_order_data_after_billing_address', 'custom_checkout_field_display_admin_order_meta', 10, 1 );
function custom_checkout_field_display_admin_order_meta($order){
$restaurant_id = get_post_meta( $order->id, '_restaurant_id', true );
if ( ! empty( $restaurant_id ) ) {
echo '<p><strong>'. __("Restaurant ID", "woocommerce").':</strong> ' . $restaurant_id . '</p>';
}
}
//
// ADD THE INFORMATION AS META DATA SO THAT IT CAN BE SEEN AS PART OF THE ORDER
//
add_action('woocommerce_add_order_item_meta','custom_add_values_to_order_item_meta', 1, 3 );
function custom_add_values_to_order_item_meta( $item_id, $values, $cart_item_key ) {
$restaurant_id = get_post_meta( $order->id, '_restaurant_id', true );
// lets add the meta data to the order!
wc_add_order_item_meta($item_id, '_restaurant_id', $restaurant_id, true);
}
Code goes in any php file of your active child theme (or theme) or also in any plugin php files.
Code is tested and works.
You could utilize the hook woocommerce_order_status_XXX, where XXX is the order status.
For example:
add_action( 'woocommerce_order_status_completed', 'my_order_status_change_function' );
function my_order_status_change_function( $order_id ) {
$order = new WC_Order($order_id);
//your logic for updating order meta, the meta is stored in wp_postmeta.
update_post_meta( $order_id, 'new_field', 'new_value' );
}
To trigger the function when order status is changed to processing,
change the action name to woocommerce_order_status_processing.

Add custom field data to WooCommerce order

I have a custom field on my WooCommerce single product. It sends to the cart fine, it displays on checkout fine, it shows in the order in the dashboard fine.
What I am now trying to do is set the value as a custom field in the order page so I am able to amend the text when I need to. For some reason when I submit the form this step isn't working.
The code that i use in my functions.phpfile:
// Add the field to the product
add_action('woocommerce_before_add_to_cart_button', 'my_custom_checkout_field');
function my_custom_checkout_field() {
echo '<div id="my_custom_checkout_field"><h3>'.__('My Field').'</h3>';
echo '<label>fill in this field</label> <input type="text" name="my_field_name">';
echo '</div>';
}
// Store custom field
function save_my_custom_checkout_field( $cart_item_data, $product_id ) {
if( isset( $_REQUEST['my_field_name'] ) ) {
$cart_item_data[ 'my_field_name' ] = $_REQUEST['my_field_name'];
/* below statement make sure every add to cart action as unique line item */
$cart_item_data['unique_key'] = md5( microtime().rand() );
}
return $cart_item_data;
}
add_action( 'woocommerce_add_cart_item_data', 'save_my_custom_checkout_field', 10, 2 );
// Render meta on cart and checkout
function render_meta_on_cart_and_checkout( $cart_data, $cart_item = null ) {
$custom_items = array();
/* Woo 2.4.2 updates */
if( !empty( $cart_data ) ) {
$custom_items = $cart_data;
}
if( isset( $cart_item['my_field_name'] ) ) {
$custom_items[] = array( "name" => 'My Field', "value" => $cart_item['my_field_name'] );
}
return $custom_items;
}
add_filter( 'woocommerce_get_item_data', 'render_meta_on_cart_and_checkout', 10, 2 );
// Display as order meta
function my_field_order_meta_handler( $item_id, $values, $cart_item_key ) {
if( isset( $values['my_field_name'] ) ) {
wc_add_order_item_meta( $item_id, "my_field_name", $values['my_field_name'] );
}
}
add_action( 'woocommerce_add_order_item_meta', 'my_field_order_meta_handler', 1, 3 );
/** THIS IS WHERE I'M STUCK **/
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
global $woocommerce;
// Check if set, if its not set add an error. This one is only requite for companies
if ($_POST['billing_company'])
if (!$_POST['my_field_name'])
$woocommerce->add_error( __('Please enter your XXX.') );
}
// Update the user meta with field value
add_action('woocommerce_checkout_update_user_meta', 'my_custom_checkout_field_update_user_meta');
function my_custom_checkout_field_update_user_meta( $user_id ) {
if ($user_id && $_POST['my_field_name']) update_user_meta( $user_id, 'my_field_name', esc_attr($_POST['my_field_name']) );
}
// Update the order meta with field value
add_action('woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta');
function my_custom_checkout_field_update_order_meta( $order_id ) {
if ($_POST['my_field_name']) update_post_meta( $order_id, 'My Field', esc_attr($_POST['my_field_name']));
}
Screenshot of what currently happens:
What I would like to happen:
Any help would be greatly appreciated.
Updated: compatibility with Woocommerce version 3+
You have missing the function to display this custom field value on the order edit page:
/**
* Display field value on the order edit page
*/
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 ){
$order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;
echo '<p><strong>'.__('My Field Name').':</strong> ' . get_post_meta( $order_id, 'my_field_name', true ) . '</p>';
}
On the reference link below, you have all original wooThemes functional working code snippets. It's an excellent fully functional tutorial.
Reference: [Customizing checkout fields using actions and filters][1]
Edit: Get a custom label displayed with your custom field value in Order item meta
To get a custom label like "MY field name" with your custom field value (in order items meta) instead of a slug like my_field_name, refer to this treads:
Saving a product custom field and displaying it in cart page
Displaying product custom fields values in the order once processed
Adding user custom field value to order items details
I don't know if this still is relevant, I have tried to do this with code, unfortunately, I got stuck in the way. I have tried this woocommerce checkout field editor plugin, which did well to add custom field data to woocomemrce order.

Categories