Add a new custom field to WooCommerce checkout and display on admin order pages and email notifications
You're using
delivery_date
,city_custom
&City
mixed up, this gives you different values, so that is your problem
// Display a custom checkout select field after Billing form
add_action( 'woocommerce_after_checkout_billing_form', 'my_custom_checkout_field', 10, 1 );
function my_custom_checkout_field( $checkout ) {
echo '<div id="my_custom_checkout_field">
' . __('City') . '';
woocommerce_form_field( 'city_custom', array(
'type' => 'select',
'options' => array(
'Colombo 01' => __('Colombo 01', 'woocommerce' ),
'Colombo 02' => __('Colombo 02', 'woocommerce' ),
'Colombo 03' => __('Colombo 03', 'woocommerce' ),
'Colombo 04' => __('Colombo 04', 'woocommerce' ),
'Colombo 06' => __('Colombo 06', 'woocommerce' ),
'Colombo 07' => __('Colombo 07', 'woocommerce' ),
'Colombo 08' => __('Colombo 08', 'woocommerce' ),
'Colombo 09' => __('Colombo 09', 'woocommerce' ),
'Colombo 10' => __('Colombo 10', 'woocommerce' ),
'Colombo 11' => __('Colombo 11', 'woocommerce' ),
'Colombo 01' => __('Colombo 01', 'woocommerce' ),
'Dehiwela' => __('Dehiwela', 'woocommerce' ),
'Attidiya' => __('Attidiya', 'woocommerce' ),
'Mount Lavinia' => __('Mount Lavinia', 'woocommerce' ),
'Ratmalana' => __('Ratmalana', 'woocommerce' ),
'Maligawatte' => __('Maligawatte', 'woocommerce' ),
'Kotikawatta' => __('Kotikawatta', 'woocommerce' ),
'Rajagiriya' => __('Rajagiriya', 'woocommerce' ),
'Peliyagoda' => __('Peliyagoda', 'woocommerce' ),
'Kelaniya' => __('Kelaniya', 'woocommerce' ),
'Kiribathgoda' => __('Kiribathgoda', 'woocommerce' ),
'Wattala' => __('Wattala', 'woocommerce' )),
'class' => array('my-field-class form-row-wide'),
'placeholder' => __('Select City'),
), $checkout->get_value( 'city_custom' ));
echo '</div>';
}
// Save the dropdown custom field selected value as order custom meta data:
add_action( 'woocommerce_checkout_create_order', 'my_custom_checkout_field_update_order_meta', 10, 2 );
function my_custom_checkout_field_update_order_meta( $order, $data ) {
if ( isset($_POST['city_custom']) && ! empty($_POST['city_custom']) ) {
$order->update_meta_data( 'city', sanitize_text_field( $_POST['city_custom'] ) );
}
}
// Display the custom field value on admin order pages after billing adress:
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>'.__('City').':</strong> ' . $order->get_meta('city') . '</p>';
}
// Display the custom field value on email notifications:
add_action( 'woocommerce_email_after_order_table', 'custom_woocommerce_email_order_meta_fields', 10, 4 );
function custom_woocommerce_email_order_meta_fields( $order, $sent_to_admin, $plain_text, $email ) {
echo '<p><strong>'.__('City').':</strong> ' . $order->get_meta('city') . '</p>';
}
Save and display custom checkout field in WooCommerce
I have also revisited a bit your code. To save your custom checkout field value as custom order meta data and display it on orders and email notifications, use the following:
// Checkout: Display a custom checkout field (dropdown)
add_action( 'woocommerce_before_order_notes', 'wps_add_select_checkout_field' );
function wps_add_select_checkout_field( $checkout ) {
echo '<h2>'.__('Select a Good Cause').'</h2>';
$posts = get_posts( array(
'post_type' => 'good_cause',
'posts_per_page' => -1,
) );
$options = array(); // Initializing
foreach ( $posts as $value ) {
$options[$value->ID] = $value->post_title;
}
woocommerce_form_field( 'daypart', array(
'type' => 'select',
'class' => array( 'wps-drop' ),
'label' => __( 'Delivery options' ),
'options' => $options,
), $checkout->get_value( 'daypart' ));
}
// Save chosen custom field option as custom order meta data
add_action( 'woocommerce_checkout_create_order', 'action_checkout_create_order' );
function action_checkout_create_order( $order ) {
$key_field = 'daypart';
if( isset($_POST[$key_field]) && $_POST[$key_field] > 0 ) {
$post = get_post( intval($_POST[$key_field]) ); // Get the post object from the post ID
$order->update_meta_data( $key_field, $post->post_title); // Save the post title
$order->update_meta_data( $key_field.'_id', $post->ID); // Save post ID (optional if needed)
}
}
// Display on admin orders
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_chosen_delivery_on_admin_orders' );
function display_chosen_delivery_on_admin_orders( $order ){
if( $daypart = $order->get_meta( 'daypart' ) ) {
$daypart_id = $order->get_meta( 'daypart_id' );
$daypart_id = empty($daypart_id) ? '' : ' ('. $daypart_id .')';
// Display the delivery option (post title + post id)
echo '<p><strong>' . __("Delivery") . ':</strong> ' . $daypart . $daypart_id . '</p>';
}
}
// Display on customer orders and email notifications
add_filter( 'woocommerce_get_order_item_totals', 'display_delivery_on_order_item_totals', 10, 3 );
function display_delivery_on_order_item_totals( $total_rows, $order, $tax_display ){
if( $daypart = $order->get_meta( 'daypart' ) ) {
$new_total_rows = [];
// Loop through order total rows
foreach( $total_rows as $key => $values ) {
// Inserting before payment method
if( $key === 'payment_method' ) {
$new_total_rows[$field_id] = array(
'label' => __("Delivery", "woocommerce") . ':',
'value' => $daypart,
);
}
$new_total_rows[$key] = $values;
}
return $new_total_rows;
}
return $total_rows;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Display custom field between billing address in WooCommerce admin order edit pages
The output is a string, which uses <br/>
to separate the order billing address details.
So there are 2 possible views:
company_name<br/>Firstname Lastname<br/>street<br/>1<br/>1000 Location
Firstname Lastname<br/>street<br/>1<br/>1000 Location
There are several possibilities that you can apply to answer your question, but the easiest is to edit the string via the woocommerce_order_get_formatted_billing_address
filter hook.
Note: we are going to check whether there is actually a billing company,
and adjust our result based on that.
Note: adjust $order->get_meta( '_your_meta_key' );
to your needs.
So you get:
function str_replace_first( $search, $replace, $subject ) {
$pos = strpos( $subject, $search );
if ( $pos !== false ) {
return substr_replace( $subject, $replace, $pos, strlen( $search ) );
}
return $subject;
}
/**
* Filter orders formatterd billing address.
*
* @since 3.8.0
* @param string $address Formatted billing address string.
* @param array $raw_address Raw billing address.
* @param WC_Order $order Order data. @since 3.9.0
*/
function filter_woocommerce_order_get_formatted_billing_address( $address, $raw_address, $order ) {
// Get meta
$value = $order->get_meta( '_your_meta_key' );
// When empty, return
if ( empty ( $value ) ) return $address;
// Get billing company
$billing_company = $order->get_billing_company();
// Not empty
if ( ! empty ( $billing_company ) ) {
$address = str_replace_first( '<br/>', '<br/>' . $value . '<br/>', $address );
} else {
$address = $value . '<br/>' . $address;
}
return $address;
}
add_filter( 'woocommerce_order_get_formatted_billing_address', 'filter_woocommerce_order_get_formatted_billing_address', 10, 3 );
Result:
company_name<br/>meta_value<br/>Firstname Lastname<br/>street<br/>1<br/>1000 Location
meta_value<br/>Firstname Lastname<br/>street<br/>1<br/>1000 Location
Used in this answer: https://stackoverflow.com/a/2606638/11987538
Add and display custom cart item data in WooCommerce orders and emails
There are some mistakes in your last function… Instead replace it with the following:
/**
* Set custom field as visible order item meta data (displayed on orders and email notifications)
*/
add_action( 'woocommerce_checkout_create_order_line_item', 'hpplrs_add_custom_data_to_order', 10, 4 );
function hpplrs_add_custom_data_to_order( $item, $cart_item_key, $values, $order ) {
if( isset($values['title_field']) && ! empty($values['title_field']) ) {
$item->add_meta_data( __( 'Size', 'hpplrs' ), $values['title_field'] );
}
}
Tested and works. Now your custom field will be displayed on orders and email notifications.
Displaying a second custom field on WooCommerce email notifications
You're missing the correct meta_key
Use it like this instead:
function custom_woocommerce_email_order_meta_fields( $fields, $sent_to_admin, $order ) {
// Get meta
$shipping_phone = $order->get_meta( '_shipping_phone', true );
// NOT empty
if( ! empty( $shipping_phone ) ) {
$fields['_shipping_phone'] = array(
'label' => __( 'Shipping Phone' ),
'value' => $shipping_phone,
);
}
// Get (other) meta
$shipping_email = $order->get_meta( '_shipping_email', true );
// NOT empty
if ( ! empty( $shipping_email ) ) {
$fields['_shipping_email'] = array(
'label' => __( 'Shipping Email' ),
'value' => $shipping_email,
);
}
return $fields;
}
add_filter( 'woocommerce_email_order_meta_fields', 'custom_woocommerce_email_order_meta_fields', 10, 3 );
Display a WooCommerce custom checkout field value on email notification
Updated - There are some small mistakes like:
- Since Woocommerce 3, to get the order ID from the Order object use:
$order->get_id()
- On your last function, there is a missing parameter variable from the hooked function, So you can't get the correct WC_Order Object
$order
variable required in your code. - The correct post meta key is
Optional advices:
- It's better to use
woocommerce_checkout_create_order
action hook introduce in Woocommerce 3, instead of oldwoocommerce_checkout_update_order_meta
action hook. - You can use
WC_Data
get_meta()
method with theWC_Order
object instead ofget_post_meta()
Here is your complete revisited code:
// Display a custom checkout select field after Order notes
add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field', 10, 1 );
function my_custom_checkout_field( $checkout ) {
echo '<div id="my_custom_checkout_field">
<h2>' . __('Bezorg moment') . '</h2>';
woocommerce_form_field( 'delivery_date', array(
'type' => 'select',
'options' => array(
'17:30-18:00' => __('17:30 - 18:00', 'woocommerce' ),
'18:00-18:30' => __('18:00 - 18:30', 'woocommerce' )),
'class' => array('my-field-class form-row-wide'),
'label' => __('Bezorgtijd'),
'placeholder' => __('Zo snel mogelijk'),
), $checkout->get_value( 'delivery_date' ));
echo '</div>';
}
// Save the dropdown custom field selected value as order custom meta data:
add_action( 'woocommerce_checkout_create_order', 'my_custom_checkout_field_update_order_meta', 10, 2 );
function my_custom_checkout_field_update_order_meta( $order, $data ) {
if ( isset($_POST['delivery_date']) && ! empty($_POST['delivery_date']) ) {
$order->update_meta_data( 'Bezorg moment', sanitize_text_field( $_POST['delivery_date'] ) );
}
}
// Display the custom field value on admin order pages after billing adress:
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>'.__('Bezorg moment').':</strong> ' . $order->get_meta('Bezorg moment') . '</p>';
}
// Display the custom field value on email notifications:
add_action( 'woocommerce_email_after_order_table', 'custom_woocommerce_email_order_meta_fields', 10, 4 );
function custom_woocommerce_email_order_meta_fields( $order, $sent_to_admin, $plain_text, $email ) {
echo '<p><strong>'.__('Bezorg moment').':</strong> ' . $order->get_meta('Bezorg moment') . '</p>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
If you want to target "New Order" email notification only use this instead:
// Display the custom field value on "New Order" notification:
add_action( 'woocommerce_email_after_order_table', 'custom_woocommerce_email_order_meta_fields', 10, 4 );
function custom_woocommerce_email_order_meta_fields( $order, $sent_to_admin, $plain_text, $email ) {
if( 'new_order' === $email->id )
echo '<p><strong>'.__('delivery_date').':</strong> ' . $order->get_meta('Bezorg moment') . '</p>';
}
Related Topics
Preg_Match() Unknown Modifier '[' Help
PHP Sessions with Disabled Cookies, Does It Work
Get Nearest Places on Google Maps, Using MySQL Spatial Data
How to Get Unique Value in Multidimensional Array
Many Hash Iterations: Append Salt Every Time
How to Get First X Chars from a String, Without Cutting Off the Last Word
PHP Unexpected Result of Float to Int Type Cast
MySQL Retrieve Variable from Stored Procedure in PHP Pdo
How to Pass Data Between Pages in PHP
How to Pass Jquery Variables to PHP Variable
PHP Upload, Extract and Progressbar
How to Display String That Contains HTML in Twig Template
Php: How to Resolve a Relative Url