Sanitize custom checkout fields data in WooCommerce - php

Following the WooCommerce checkout fields customization docs:
Customizing checkout fields using actions and filters
I have added a custom field to woocommerce checkout page, through functions.php.
I'm worried if I have to sanitize user input for that custom field?
I think it doesn't need sanitization since it's passed into billing fields as in: $fields['billing'], is that correct?
If not how do I sanitize this custom field?
Creating this custom field is meant to accept text strings(latin) and integers combined no longer than 50 in length.
// Hook in
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
// Our hooked in function - $fields is passed via the filter!
function custom_override_checkout_fields( $fields ) {
//Adding custom text field
$fields['billing']['billing_username'] = array(
'type' => 'text',
'label' => __('Your Username', 'woocommerce'),
'placeholder' => _x('', 'placeholder', 'woocommerce'),
'required' => true,
'class' => array('form-row-first'),
'clear' => true
);
return $fields;
}

If you look to the related Official Documentation linked in your question, you've got this snippet:
/**
* 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['my_field_name'] ) ) {
update_post_meta( $order_id, 'My Field', sanitize_text_field( $_POST['my_field_name'] ) );
}
}
In your case you don't need that as address fields are already processed by Woocommerce.
For custom special fields: The answer is yes (which is not your case)
As you can see in this code they use sanitize_text_field() WordPress function, when saving the submitted data to database with update_post_meta() function…
This is only for custom checkout fields and not for existing checkout fields, that already get their own process…

Related

Get checkout custom field submitted value using WC_Checkout get_value() method in WooCommerce

In WooCommerce checkout page, I have added a custom field using the code below:
add_action( 'woocommerce_before_order_notes', 'bbloomer_add_custom_checkout_field' );
function bbloomer_add_custom_checkout_field( $checkout ) {
$current_user = wp_get_current_user();
$saved_gst_no = $current_user->gst_no;
woocommerce_form_field( 'gst_no', array(
'type' => 'text',
'class' => array( 'form-row-wide' ),
'label' => 'GST Number',
'placeholder' => 'GST Number',
'required' => true
//'default' => $saved_gst_no,
), $checkout->get_value( 'gst_no' ) );
error_log( $checkout->get_value( 'gst_no' ) );
}
On entering any value in GST Number field (custom checkout field), then going to payment screen by clicking "Place order" button and returning to checkout page without completing the transaction, all default woocommerce fields like billing phone, email etc are auto filled from the session.
However, the custom field added via above code is always blank. I tried logging the value of $checkout->get_value( 'gst_no' ) and it is always null.
How to make the $checkout object store custom field values?
Update 2
Because you need to save 'gst_no' custom field value as user data too. The following will save that custom field as user meta data:
add_action( 'woocommerce_checkout_update_customer', 'action_checkout_update_customer', 10, 2 );
function action_checkout_update_customer( $customer, $data ) {
if( isset($_POST['gst_no']) ) {
$customer->update_meta_data( 'gst_no', sanitize_text_field($_POST['gst_no']) );
}
}
Code goes in functions.php file of the active child theme (or active theme). It should work.
Note: For info, the WC_Checkout method get_value() use the user meta data.

How to fill custom checkout field with previously entered value, like default WooCommerce checkout fields?

I have added a custom field using the below code:
add_action( 'woocommerce_before_order_notes', 'bbloomer_add_custom_checkout_field' );
function bbloomer_add_custom_checkout_field( $checkout ) {
$current_user = wp_get_current_user();
$saved_gst_no = $current_user->gst_no;
woocommerce_form_field( 'gst_no', array(
'type' => 'text',
'class' => array( 'form-row-wide' ),
'label' => 'GST Number',
'placeholder' => 'GST Number',
'required' => true
//'default' => $saved_gst_no,
), $checkout->get_value( 'gst_no' ) );
}
On entering any value in GST Number field (custom checkout field), then going to payment screen by clicking "Place order" button and returning to checkout page without completing the transaction, all default woocommerce fields like billing phone, email etc are auto filled from the session.
However, the custom field added via above code is always blank. How to get the previously entered value auto-filled in the custom field for guest users, similar to the way default woocommerce fields are auto-filled?
Updated (replaced wrong WC_Session method set() with get() on the first function)
This will work for guest users too. Replace your code with:
// Display checkout custom field
add_action( 'woocommerce_before_order_notes', 'add_custom_checkout_field' );
function add_custom_checkout_field( $checkout ) {
$key_field = 'gst_no';
woocommerce_form_field( $key_field, array(
'type' => 'text',
'class' => array( 'form-row-wide' ),
'label' => __('GST Number'),
'placeholder' => __('GST Number'),
'required' => true
//'default' => $saved_gst_no,
), $checkout->get_value($key_field) ? $checkout->get_value($key_field) : WC()->session->get($key_field) );
}
// Save checkout custom field value in a WC_Session variable
add_action( 'woocommerce_checkout_create_order', 'action_checkout_create_order', 10, 2 );
function action_checkout_create_order( $order, $data ) {
$key_field = 'gst_no';
if( isset($_POST[$key_field]) ) {
WC()->session->set($key_field, sanitize_text_field($_POST[$key_field]));
}
}
// Save checkout custom field value as user meta data
add_action( 'woocommerce_checkout_update_customer', 'action_checkout_update_customer', 10, 2 );
function action_checkout_update_customer( $customer, $data ) {
$key_field = $key_field;
if( isset($_POST['gst_no']) ) {
$customer->update_meta_data($key_field, sanitize_text_field($_POST[$key_field]));
}
}
Note: Uses a WC_Session variable to store the submitted value for guests, allowing to display it on checkout when returning without completing the transaction.
In my experience, WooCommerce was saving the form data in session variables via AJAX when fields were updated via the update_order_review path. In order to hook into this and stored my custom vars, I used the following:
add_action('woocommerce_checkout_update_order_review', 'custom_woocommerce_checkout_update_order_review');
function custom_woocommerce_checkout_update_order_review($post_data){
// Convert $post_data string to array and clean it
$post_arr = array();
parse_str($post_data, $post_arr);
wc_clean($post_arr);
if(isset($post_arr['gst_no'])) {
WC()->session->set('gst_no', $post_arr['gst_no']);
}
}
Also a deeper way to add the custom checkout fields so that it's available in the $data passed to woocommerce_checkout_update_order_meta:
add_filter('woocommerce_checkout_fields', 'custom_checkout_fields');
function custom_checkout_fields($fields){
$fields['gst_no'] = array(
'type' => 'text',
'default' => WC()->session->get('gst_no')
);
return $fields;
}

Woocommerce, Checkout, Order -> Advanced Custom Field: set value from HTML selector

How do I set the value of a custom field on an order, upon checkout submit, to a selected value in an HTML component?
I've implemented a custom HTML component, inside the checkout form, whose selected value I want to insert in a custom field on my orders. But I can't seem to figure out how to hook these things up.
I've arrived at somthing like:
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
function custom_override_checkout_fields( $fields ) {
$fields['order']['special_delivery'] = 'The value from HTML';
return $fields;
}
But I'm not even sure that's the right way to go.
Any ideas?
Using woocommerce_after_checkout_billing_form allows you to add custom fields to your checkout form. You also need to save the field in the order meta using woocommerce_checkout_update_order_meta.
In the following code there is a custom text field used for saving VAT ID. Feel free to get rid of the "mrank" prefixes. Also rename the field as you need it.
It will show you how to add a field and to save in order meta.
/**
* VAT Number in WooCommerce Checkout
*/
function mrank_vat_field( $checkout ) {
echo '<div id="mrank_vat_field">';
woocommerce_form_field( 'vat_number', array(
'type' => 'text',
'class' => array( 'vat-number-field form-row-wide') ,
'label' => __( 'VAT-ID' ),
'placeholder' => __( 'Enter number' ),
'description' => __( 'Please enter your VAT-ID' ),
'required' => true,
), $checkout->get_value( 'vat_number' ));
echo '</div>';
}
add_action( 'woocommerce_after_checkout_billing_form', 'mrank_vat_field' );
/**
* Save VAT Number in the order meta
*/
function mrank_checkout_vat_number_update_order_meta( $order_id ) {
if ( ! empty( $_POST['vat_number'] ) ) {
update_post_meta( $order_id, '_vat_number', sanitize_text_field( $_POST['vat_number'] ) );
}
}
add_action( 'woocommerce_checkout_update_order_meta', 'mrank_checkout_vat_number_update_order_meta' );

Update user display name from custom checkout field in WooCommerce

In WooCommerce, at checkout, I am able to create or update all the user and billing information while placing an order. However, I want to set/update the user "display name" (alias) as well.
So based on "Capture custom checkout field value in Woocommerce" answer code, I have added the following code to my active theme's functions.php file:
// Display a custom checkout field
add_action( 'woocommerce_before_checkout_billing_form', 'my_custom_checkout_field' );
function my_custom_checkout_field( $checkout ) {
echo '<div id="my_custom_checkout_field">';
woocommerce_form_field( 'display_name', array(
'type' => 'text',
'class' => array('my-custom-field form-row-wide'),
'label' => __('Alias'),
'placeholder' => __('Nickname to show in my account and comments'),
'required' => true,
), $checkout->get_value( 'display_name' ));
echo '</div>';
}
// Save the custom checkout field in the order meta
add_action( 'woocommerce_checkout_update_user_meta', 'save_order_custom_meta_data', 10, 2 );
function save_order_custom_meta_data( ) {
if ( isset($_POST['display_name']) )
$user->update_meta_data('display_name', sanitize_text_field( $_POST['display_name'] ) );
}
But this is not working as I get "Internal Server Error" message.
Any help to solve this will be appreciated.
The problem comes from your second function… The function arguments are missing and $user variable is null and you can't use on it the WC_Data method update_meta_data().
Also the display_name is not user meta data, but simply user data. So you need to use dedicated WordPress function wp_update_user() in order to set/update the user display name.
Replace your 2nd hooked function with the following instead:
// Save/update user data from custom checkout field value
add_action( 'woocommerce_checkout_update_user_meta', 'checkout_update_user_display_name', 10, 2 );
function checkout_update_user_display_name( $customer_id, $data ) {
if ( isset($_POST['display_name']) ) {
$user_id = wp_update_user( array( 'ID' => $customer_id, 'display_name' => sanitize_text_field($_POST['display_name']) ) );
}
}
Code goes in function.php file of your active child theme (or active theme). It should works now.

Enable a custom field placeholder to Woocommerce email subject

In Woocommerce, I have added a custom field to the checkout page using the following code:
add_action( 'woocommerce_checkout_fields', 'woo_add_conditional_checkout_fields' );
function woo_add_conditional_checkout_fields( $fields ) {
foreach( WC()->cart->get_cart() as $cart_item ){
$product_id = $cart_item['product_id'];
$fields['billing']['billing_field_newfield'] = array(
'label' => __('New Field', 'woocommerce'),
'placeholder' => _x('', 'placeholder', 'woocommerce'),
'required' => true,
'class' => array('form-row-wide'),
'clear' => false
);
}
return $fields;
}
Now, I would like to include the value that user enters in this field in the 'New Order' woocommerce email subject using {billing_field_newfield} custom placeholder.
However when I go to Woocommerce > Settings > Emails > New Order and put {billing_field_newfield} in the subject, I just get {billing_field_newfield} in the email and not its actual value.
How to add a custom dynamic placeholder to email subject in Woocommerce?
To add a custom active placeholder {billing_field_newfield} in woocommerce email notifications, you will use the following hooked function.
You will check before that _billing_field_newfield is the correct post meta key used to save the checkout field value to the order (check in wp_postmeta database table for the order post_id).
The code:
add_filter( 'woocommerce_email_format_string' , 'add_custom_email_format_string', 20, 2 );
function add_custom_email_format_string( $string, $email ) {
// The post meta key used to save the value in the order post meta data
$meta_key = '_billing_field_newfield';
// Get the instance of the WC_Order object
$order = $email->object;
// Get the value
$value = $order->get_meta($meta_key) ? $order->get_meta($meta_key) : '';
// Additional subject placeholder
$new_placeholders = array( '{billing_field_newfield}' => $value );
// Return the clean replacement value string for "{billing_field_newfield}" placeholder
return str_replace( array_keys( $additional_placeholders ), array_values( $additional_placeholders ), $string );
}
Code goes in function.php file of your active child theme (or active theme). It will works.
Then in Woocommerce > Settings > Emails > "New Order" notification, you will be able to use the dynamic placeholder {billing_field_newfield}…

Categories