Display custom checkout field value on admin order detail section in Woocommerce - wordpress

Hello I'm trying to display the custom checkout field in the admin order details page. My Custom field is Delivery Option and it allows the user to pick the to pick a value from checkbox. I use the code below following the similar topics about this, but it seems something is wrong with my code.
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_additional_field', 20 );
function checkout_shipping_additional_field()
{
$domain = 'wocommerce';
$default = 'option 1';
echo '<tr class="additional-shipping-fields"><th>' . __('Delivery Time', $domain) . '</th><td>';
// Add a custom checkbox field
woocommerce_form_field( 'custom_radio_field', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'options' => array(
'option 1' => __('10:04 : 13:04 ', $domain),
),
'default' => $default,
), $default );
echo '</td></tr>';
}
//update order meta
add_action('woocommerce_checkout_update_order_meta', 'gon_update_order_meta_business_address');
function gon_update_order_meta_business_address( $order_id ) {
if ($_POST['custom_radio_field']) update_post_meta( $order_id, 'Business Address?',
esc_attr($_POST['custom_radio_field']));
}
// Display field value on the admin order edit page
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'custom_checkout_field_display_admin_order_meta', 10, 1 );
function custom_checkout_field_display_admin_order_meta( $order ){
$delivery_time = get_post_meta( $order->get_id(), 'Delivery Time', true );
if( ! empty( $delivery_time ) )
echo '<p><strong>'.__('Delivery Time', 'woocommerce').': </strong> ' . $delivery_time . '</p>';
}

There is some mistakes, so I have revisited your code. I have also replaced some hooks. Try the following:
// HERE set your the options array for your select field.
function delivery_time_options(){
$domain = 'woocommerce';
return array(
'1' => __('10:04 : 13:04 ', $domain),
'2' => __('14:04 : 16:04 ', $domain), // <== Added for testing
);
}
// Display a custom select field after shipping total line
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_additional_field', 20 );
function checkout_shipping_additional_field(){
$domain = 'woocommerce';
echo '<tr class="additional-shipping-fields"><th>' . __('Delivery Time', $domain) . '</th><td>';
// Add a custom select field
woocommerce_form_field( 'delivery_time', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'options' => delivery_time_options(),
), '' );
echo '</td></tr>';
}
// Save custom field as order meta data
add_action('woocommerce_checkout_create_order', 'save_custom_field_order_meta', 22, 2 );
function save_custom_field_order_meta( $order, $data ) {
if ( isset($_POST['delivery_time']) ) {
$options = delivery_time_options(); // Get select options array
$option_key = esc_attr($_POST['delivery_time']); // The selected key
$order->update_meta_data( '_delivery_time', $options[$option_key] ); // Save
}
}
// Display a custom field value on the admin order edit page
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_custom_meta_data_in_backend_orders', 10, 1 );
function display_custom_meta_data_in_backend_orders( $order ){
$domain = 'woocommerce';
$delivery_time = $order->get_meta('_delivery_time');
if( ! empty( $delivery_time ) )
echo '<p><strong>'.__('Delivery Time', $domain).': </strong> ' . $delivery_time . '</p>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Based on #LoicTheAztec answer, if you want multiple fields without re-writing the functions for every field (DRY), you can use this class (by adding it to your functions.php):
/**
* Add a custom field to the woocommerce checkout page
* https://stackoverflow.com/q/52098807/
*/
class WOO_Add_Checkout_Field
{
public function __construct($options)
{
$this->field_name = $options['field_name'];
$this->label = $options['label'];
$this->placeholder = $options['placeholder'];
$this->required = $options['required'];
if ($this->field_name && $this->label && $this->placeholder) {
add_action('woocommerce_after_order_notes', [$this, 'customise_checkout_field']);
add_action('woocommerce_checkout_update_order_meta', [$this, 'custom_checkout_field_update_order_meta'], 10, 1);
add_action('woocommerce_admin_order_data_after_billing_address', [$this, 'display_custom_field_on_order_edit_pages'], 10, 1);
} else {
die("Error in WOO_Add_Checkout_Field \$options: \n\n" . var_dump($options));
}
}
public function customise_checkout_field($checkout)
{
echo '<div id="customise_checkout_field">';
// echo '<h2>' . __('Heading') . '</h2>';
woocommerce_form_field($this->field_name, array(
'type' => 'text',
'class' => array(
'my-field-class form-row-wide'
),
'label' => $this->label,
'placeholder' => $this->placeholder,
'required' => $this->required,
), $checkout->get_value($this->field_name));
echo '</div>';
}
public function custom_checkout_field_update_order_meta($order_id)
{
if (!empty($_POST[$this->field_name]))
update_post_meta($order_id, $this->field_name, $_POST[$this->field_name]);
else
update_post_meta($order_id, $this->field_name, 0);
}
public function display_custom_field_on_order_edit_pages($order)
{
$field = $order->get_meta($this->field_name);
if (!empty($field)) {
echo '<p><strong style="display:block" title="' . $this->placeholder . '">' . $this->label . ': </strong><span>';
echo $field;
echo '</span></p>';
}
}
}
And use it as many times as you'd like:
$my_custom_field_1 = new WOO_Add_Checkout_Field([
'field_name' => 'my_custom_field_1',
'label' => __('My First Field'),
'placeholder' => __('Please write something in field 1...'),
'required' => false,
]);
$my_custom_field_2 = new WOO_Add_Checkout_Field([
'field_name' => 'my_custom_field_2',
'label' => __('My Second Field'),
'placeholder' => __('Please write something in field 2...'),
'required' => false,
]);
$my_custom_field_3 = new WOO_Add_Checkout_Field([
'field_name' => 'my_custom_field_3',
'label' => __('My Third Field'),
'placeholder' => __('Please write something in field 3...'),
'required' => false,
]);
// and so on...
Please note:
The custom field will show up in admin area ONLY if it was not sent empty
You can customize this code how you like

Related

Add custom field to product inventory tab and display value on single product page where meta ends

I'm using the following code in my theme functions.php file to add a additional data field to the product inventory tab:
// Add Custom Field to woocommerce inventory tab for product
add_action('woocommerce_product_options_inventory_product_data', function() {
woocommerce_wp_text_input([
'id' => '_number_in_package',
'label' => __('Number of Pages', 'txtdomain'),
'type' => 'number',
]);
});
add_action('woocommerce_process_product_meta', function($post_id) {
$product = wc_get_product($post_id);
$num_package = isset($_POST['_number_in_package']) ? $_POST['_number_in_package'] : '';
$product->update_meta_data('_number_in_package', sanitize_text_field($num_package));
$product->save();
});
add_action('woocommerce_product_meta_start', function() {
global $post;
$product = wc_get_product($post->ID);
$num_package = $product->get_meta('_number_in_package');
if (!empty($num_package)) {
printf('<div class="custom-sku">%s: %s</div>', __('Number of Pages', 'txtdomain'), $num_package);
}
});
add_filter('woocommerce_product_data_tabs', function($tabs) {
$tabs['additional_info'] = [
'label' => __('Additional info', 'txtdomain'),
'target' => 'additional_product_data',
'class' => ['hide_if_external'],
'priority' => 25
];
return $tabs;
});
However, on the single product page, the custom field is added before category and ISBN. I want to place the custom field at the end after the product ISBN. Any advice?
Some comments/suggestions regarding your code attempt
To save fields you can use the woocommerce_admin_process_product_object hook, opposite the outdated woocommerce_process_product_meta hook
WooCommerce contains by default no ISBN field, but it looks like the woocommerce_product_meta_end hook will answer your question
So you get:
// Add custom field
function action_woocommerce_product_options_inventory_product_data() {
woocommerce_wp_text_input( array(
'id' => '_number_in_package',
'label' => __( 'Number of Pages', 'woocommerce' ),
'description' => __( 'This is a custom field, you can write here anything you want.', 'woocommerce' ),
'desc_tip' => 'true',
'type' => 'number'
) );
}
add_action( 'woocommerce_product_options_inventory_product_data', 'action_woocommerce_product_options_inventory_product_data' );
// Save custom field
function action_woocommerce_admin_process_product_object( $product ) {
// Isset
if ( isset( $_POST['_number_in_package'] ) ) {
// Update
$product->update_meta_data( '_number_in_package', sanitize_text_field( $_POST['_number_in_package'] ) );
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
// Display on single product page
function action_woocommerce_product_meta_end() {
global $product;
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get meta
$number = $product->get_meta( '_number_in_package' );
// NOT empty
if ( ! empty ( $number ) ) {
echo '<p>' . $number . '</p>';
}
}
}
add_action( 'woocommerce_product_meta_end', 'action_woocommerce_product_meta_end', 10 );

How to add custom field in shipping method using woocommerce wordpress

How to add custom field in shipping method using woocommerce wordpress
Please see my screenshot
Please try this code.
if ( ! function_exists( 'dimative_shipping_instance_form_fields_filters' ) ) {
/**
* Shipping Instance form add extra fields.
*
* #param array $settings Settings.
* #return array
*/
function dimative_shipping_instance_form_add_extra_fields( $settings ) {
$settings['shipping_extra_field_title'] = array(
'title' => esc_html__( 'Shipping method title', 'zincheco' ),
'type' => 'text',
'placeholder' => esc_html__( 'Please add shipping method title', 'zincheco' ),
'description' => '',
);
$settings['shipping_extra_field_description'] = array(
'title' => esc_html__( 'Shipping method description', 'zincheco' ),
'type' => 'textarea',
'placeholder' => esc_html__( 'Please add your shipping method description', 'zincheco' ),
'description' => '',
);
return $settings;
}
/**
* Shipping instance form fields.
*/
function dimative_shipping_instance_form_fields_filters() {
$shipping_methods = WC()->shipping->get_shipping_methods();
foreach ( $shipping_methods as $shipping_method ) {
add_filter( 'woocommerce_shipping_instance_form_fields_' . $shipping_method->id, 'dimative_shipping_instance_form_add_extra_fields' );
}
}
add_action( 'woocommerce_init', 'dimative_shipping_instance_form_fields_filters' );
}
In case if someone is looking how to get the value using #Өлзийбат-Нансалцог code example. I was able to retrieve it this way:
//Get Shipping rate object
//$method->id is the ID of the shipping method.
//In my case I used that in cart-shipping.php template
$WC_Shipping_Rate = new WC_Shipping_Rate($method->id);
// Returned value is flat_rate:1
$shipping_rate_id = $WC_Shipping_Rate->get_id();
//Replacing : with underscore to have the id in format of flat_rate_1
$shipping_rate_id = str_replace(':', '_', $shipping_rate_id);
//Get the description field value
//Since the value is stored inside options table use get_option() method
get_option('woocommerce_'.$shipping_rate_id.'_settings')['shipping_extra_field_description']
Here is the code for getting the value.
if ( ! function_exists( 'dimative_shipping_method_description' ) ) {
/**
* Function will print shipping method description.
*
* #param object $method Shipping method object.
* #param int $index Shipping method index.
* #return void
*/
function dimative_shipping_method_description( $method, $index ) {
$dimative_method_fields = get_option( 'woocommerce_' . $method->method_id . '_' . $method->instance_id . '_settings' );
$dimative_method_allowed_html = array(
'p' => array(
'class' => array(),
),
'strong' => array(),
'b' => array(),
'a' => array(
'href' => array(),
),
'span' => array(
'class' => array(),
),
);
// Shipping method custom description.
if ( $dimative_method_fields['shipping_extra_field_description'] ) {
?>
<div class="method-description"><?php echo wp_kses( $dimative_method_fields['shipping_extra_field_description'], $dimative_method_allowed_html ); ?></div>
<?php
}
}
add_action( 'woocommerce_after_shipping_rate', 'dimative_shipping_method_description', 1, 2 );
}

Woocommerce - Add custom checkout field to customer new account email

I am trying to display the "billing_gender" custom field I have added to my checkout form to the customer new account notification email.
The field is correctly saved to the database but it is shown empty in the new account email.
Other user meta fields (phone, ...) work but not my custom checkout field.
I guess it is saved to late in the user meta information but I really can't figure it out :
Here is my code :
functions.php
add_filter( 'woocommerce_checkout_fields' , 'divi_override_checkout_fields' );
function divi_override_checkout_fields( $fields ) {
unset($fields['billing']['billing_company']);
unset($fields['billing']['billing_address_1']);
unset($fields['billing']['billing_address_2']);
unset($fields['billing']['billing_city']);
unset($fields['billing']['billing_postcode']);
unset($fields['billing']['billing_state']);
unset($fields['billing']['billing_country']);
// Custom gender field
$fields['billing']['billing_gender'] = array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'label' => __( 'Title', 'divi-ultimate'),
'required' => true,
'priority' => 3,
'options' => array(
'' => __( 'Select title', 'divi-ultimate' ),
'male' => __( 'Mr', 'divi-ultimate' ),
'female' => __( 'Mrs', 'divi-ultimate' )
),
);
return $fields;
}
// Gender select default value
add_filter( 'default_checkout_billing_gender', 'checkout_billing_gender',10,2 );
function checkout_billing_gender($value) {
if ( is_user_logged_in()){
$current_user = wp_get_current_user();
$value = get_user_meta( $current_user->ID, 'billing_gender', true );
}
return $value;
}
//* Update the order meta with fields values
add_action('woocommerce_checkout_update_order_meta', 'divi_select_checkout_field_update_order_meta', 10, 2);
function divi_select_checkout_field_update_order_meta( $order_id ) {
if ($_POST['delivery-shop']) update_post_meta( $order_id, 'delivery-shop', esc_attr($_POST['delivery-shop']));
if ($_POST['billing_gender']) update_post_meta( $order_id, 'billing_gender', esc_attr($_POST['billing_gender']));
}
//* Update the user meta with gender value
add_action( 'woocommerce_checkout_update_user_meta', 'divi_save_extra_user_fields', 10, 2 );
function divi_save_extra_user_fields($customer_id) {
if (isset($_POST['billing_gender'])) {
update_user_meta( $customer_id, 'billing_gender', esc_attr($_POST['billing_gender']) );
}
}
What am I doing wrong ?
Cheers.
Here is the customer-new-account.php file :
$user = get_user_by('login', $user_login );
if (!empty($user)) {
$gender = get_user_meta($user->ID, 'billing_gender', true);
$lastname = $user->last_name;
$user_email = $user->user_email;
}
if( !empty($gender) && !empty($lastname) ) {
printf( esc_html__( 'Dear ' . $gender . ' %s,', 'woocommerce' ), esc_html( $lastname ) );
}
else {
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $email ) );
} ?>

Manage custom checkout fields in woocommerce

Hi I have a question regardin custom checkout fields in woocommerce.
I created a custom field in the checkout form and everything was working perfectly. The field contains a customer card number. I also managed to save the field value (once entered the first time) in the wp-usermeta, so that it doesn't come along only with the order, but it is saved together with teh customer details.
Now I would like to do the following. Once a registered customer returning to the shop goes to the checkout form, the new field (if not empyt) shows up automatically, instead of asking the customers to insert their card number everytime.
The original functions that I added to my child theme fucntions.php for showing the custom field in the checkout page was:
/**
* Add the field to the checkout
*/
add_action ('woocommerce_after_order_notes', 'checkout_w55_card_number' );
function checkout_w55_card_number( $checkout ) {
echo '<div id="checkout_w55_card_number"><h2>' . __('N. tessera W55') . '</h2>';
woocommerce_form_field( 'w55_card_number', array(
'type' => 'text',
'class' => array('w55-card-number-class form-row-wide'),
'label' => __('Inserisci n. tessera W55'),
'placeholder' => __('Inserisci numero'),
), $checkout->get_value( 'w55_card_number' ));
echo '</div>';
}
I thus tried to re-arrange it in this way, but it doesn't work
add_action ('woocommerce_after_order_notes', 'checkout_w55_card_number' );
function checkout_w55_card_number( $checkout ) {
//extracts the value of the w55_card_number field
$w55_card = get_user_meta($user_id, 'w55_card_number', true);
//condition is the w55_card_number field is empty or not
if ( !empty($w55_card) ) : echo $w55_card; else :
echo '<div id="checkout_w55_card_number"><h2>' . __('N. tessera W55') . '</h2>';
woocommerce_form_field( 'w55_card_number', array(
'type' => 'text',
'class' => array('w55-card-number-class form-row-wide'),
'label' => __('Inserisci n. tessera W55'),
'placeholder' => __('Inserisci numero'),
), $checkout->get_value( 'w55_card_number' ));
echo '</div>';
endif;
}
Any suggestion?
Your user_id variable was not defined. You need to do the following:
add_action ('woocommerce_after_order_notes', 'checkout_w55_card_number' );
function checkout_w55_card_number( $checkout ) {
$user_id = get_current_user_id();
$w55_card = '';
if ($user_id) {
//extracts the value of the w55_card_number field
$w55_card = get_user_meta($user_id, 'w55_card_number', true);
}
//condition is the w55_card_number field is empty or not
if ( !empty($w55_card) ) : echo $w55_card;
else :
echo '<div id="checkout_w55_card_number"><h2>' . __('N. tessera W55') . '</h2>';
woocommerce_form_field( 'w55_card_number', array(
'type' => 'text',
'class' => array('w55-card-number-class form-row-wide'),
'label' => __('Inserisci n. tessera W55'),
'placeholder' => __('Inserisci numero'),
), $checkout->get_value( 'w55_card_number' ));
echo '</div>';
endif;
}

get_post_meta not showing the value of custom field when called

I've had the following code to add a custom order field in the woocommerce checkout:
function delivery_time_slots_array () {
return array(
'' => _('Choose a time slot'),
'5pm - 6pm' => __('5pm - 6pm', 'woocommerce'),
'6pm - 7pm' => __('6pm - 7pm', 'woocommerce'),
'7pm - 8pm' => __('7pm - 8pm', 'woocommerce'),
'8pm - 9pm' => __('8pm - 9pm', 'woocommerce')
);
}
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
$fields['order']['order_delivery_time'] = array(
'type' => 'select',
'label' => __('Delivery time (choose an hour slot between 5pm & 9pm)', 'woocommerce'),
'class' => array('form-row-wide'),
'required' => true,
'options' => delivery_time_slots_array()
);
Then, followed by the below code to update the order meta with field value:
add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta', 10, 2 );
function custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['order_delivery_time'] ) ) {
update_post_meta( $order_id, 'Delivery time', sanitize_text_field($_POST['order_delivery_time']) );
}
}
This all displays correctly and returns the value within the Orders section of woocommerce. However, I can't then access this data to return/display it on the thank-you page. I'm using the following code at present:
<li class="delivery_slot">
<?php _e( 'Delivery Slot', 'woocommerce' ); ?>
<strong><?php
$delivery_slots = delivery_time_slots_array();
$delivery_slot = get_post_meta($order_id, 'Delivery time', true);
if( isset($delivery_slots[$delivery_slot]) )
echo $delivery_slots[$delivery_slot];
?></strong>
I've reviewed 2 hours of posts here & on Google including the below example (which my code mirrors), but cannot get the value to display:
How to get the value instead of order_id with get_post_meta()
If you attach it to any of the hooks in the order-details.php template then the $order object will be available in your callback function
function so_34215698_display_order_meta( $order ){
$delivery_slots = delivery_time_slots_array()
$delivery_slot = get_post_meta($order->id, 'Delivery time', true);
if( isset($delivery_slots[$delivery_slot]) )
echo $delivery_slots[$delivery_slot];
}
add_action( 'woocommerce_order_details_after_order_table', 'so_34215698_display_order_meta' );

Resources