The bounty expires in 4 days. Answers to this question are eligible for a +100 reputation bounty.
eMikkelsen wants to draw more attention to this question:
Help me adjust the above code so that the field is not only conditional in terms of when to show but also in terms of when it is required. It must be required when the COD payment is chosen but otherwise not.
I want to make a WooCommerce Checkout Field that only shows up when a specific payment (Cash On Delivery) is chosen. This field should only show up and only be required when cash on delivery is chosen. I have managed to make the field and have it show up conditionally, but I cannot figure out how to make it required only when COD is chosen.
/* Only show EAN when COD chosen */
// Conditional Show hide checkout fields based on chosen payment methods
add_action( 'wp_footer', 'conditionally_show_hide_billing_custom_field' );
function conditionally_show_hide_billing_custom_field(){
// Only on checkout page
if ( is_checkout() && ! is_wc_endpoint_url() ) :
?>
<script>
jQuery(function($){
var a = 'input[name="payment_method"]',
b = a + ':checked',
c = '#billing_options_field'; // The checkout field <p> container selector
// Function that shows or hide checkout fields
function showHide( selector = '', action = 'show' ){
if( action == 'show' )
$(selector).show( 200, function(){
$(this).addClass("validate-required");
});
else
$(selector).hide( 200, function(){
$(this).removeClass("validate-required");
});
$(selector).removeClass("woocommerce-validated");
$(selector).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
}
// Initialising: Hide if choosen payment method is "cod"
if( $(b).val() !== 'cod' )
showHide( c, 'hide' );
else
showHide( c );
// Live event (When payment method is changed): Show or Hide based on "cod"
$( 'form.checkout' ).on( 'change', a, function() {
if( $(b).val() !== 'cod' )
showHide( c, 'hide' );
else
showHide( c );
});
});
</script>
<?php
endif;
}
/* Add extra field and make it required */
add_filter('woocommerce_billing_fields', 'custom_woocommerce_billing_fields');
function custom_woocommerce_billing_fields($fields)
{
$fields['billing_options'] = array(
'label' => __('– EAN-nummer – ', 'woocommerce'), // Add custom field label
'placeholder' => _x('EAN nummer', 'placeholder', 'woocommerce'), // Add custom field placeholder
'required' => true, // if field is required or not
'clear' => false, // add clear or not
'type' => 'text', // add field type
'class' => array('my-css') // add class name
);
return $fields;
}
add_action('woocommerce_after_checkout_validation', 'woocommerce_after_checkout_validation_alter', 10, 2);
function woocommerce_after_checkout_validation_alter($data, $errors){
if('cod' !== $data['payment_method']){
if($errors->get_error_data('billing_options_required')){ // This will contain the error
$errors->remove('billing_options_required');
}
}
return $data;
}
Remove the validation error from the error object if the payment method selected is not COD. The error object will be like the below.
WP_Error Object
(
[errors] => Array
(
[billing_options_required] => Array
(
[0] => <strong>Billing – EAN-nummer – </strong> is a required field.
)
)
[error_data] => Array
(
[billing_options_required] => Array
(
[id] => billing_options
)
)
[additional_data:protected] => Array
(
)
)
Related
I am using Update fee dynamically based on radio buttons in Woocommerce checkout answer code solution that worked very well for me to add checkbox fields with a different price for each one, and the price changes are reflected in the checkout.
But I need some help: When I select a type of packaging with additional tax, it appears in the backend in the order area, but only shows the price, and I would like to show the title as well.
The checkbox options have:
'options' => array (
'bag' => __ ('In a bag' .wc_price (3.00), $ domain),
'box' => __ ('In a gift box' .wc_price (9.00), $ domain),
),
How to make it show the name on the order?
Also if it's possible to change the checkboxes to select field instead?
I have made some changes to the original code that will:
Display a custom select field (instead of radio buttons input fields)
Display a custom error notice if customer has not selected a packing option
Display the selected packing type everywhere (on orders and email notifications)
The code:
// Add a custom select fields for packing option fee
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_form_packing_addition', 20 );
function checkout_shipping_form_packing_addition( ) {
$domain = 'woocommerce';
echo '<tr class="packing-select"><th>' . __('Packing options', $domain) . '</th><td>';
$chosen = WC()->session->get('chosen_packing');
// Add a custom checkbox field
woocommerce_form_field( 'chosen_packing', array(
'type' => 'select',
'class' => array( 'form-row-wide packing' ),
'options' => array(
'' => __("Choose a packing option ...", $domain),
'bag' => sprintf( __("In a bag (%s)", $domain), strip_tags( wc_price(3.00) ) ),
'box' => sprintf( __("In a gift box (%s)", $domain), strip_tags( wc_price(9.00) ) ),
),
'required' => true,
), $chosen );
echo '</td></tr>';
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_shipping_packing_script' );
function checkout_shipping_packing_script() {
// Only checkout page
if ( is_checkout() && ! is_wc_endpoint_url() ) :
WC()->session->__unset('chosen_packing');
?>
<script type="text/javascript">
jQuery( function($){
$('form.checkout').on('change', 'select#chosen_packing', function(){
var p = $(this).val();
console.log(p);
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'woo_get_ajax_data',
'packing': p,
},
success: function (result) {
$('body').trigger('update_checkout');
console.log('response: '+result); // just for testing | TO BE REMOVED
},
error: function(error){
console.log(error); // just for testing | TO BE REMOVED
}
});
});
});
</script>
<?php
endif;
}
// Php Ajax (Receiving request and saving to WC session)
add_action( 'wp_ajax_woo_get_ajax_data', 'woo_get_ajax_data' );
add_action( 'wp_ajax_nopriv_woo_get_ajax_data', 'woo_get_ajax_data' );
function woo_get_ajax_data() {
if ( isset($_POST['packing']) ){
$packing = sanitize_key( $_POST['packing'] );
WC()->session->set('chosen_packing', $packing );
echo json_encode( $packing );
}
die(); // Alway at the end (to avoid server error 500)
}
// Add a custom dynamic packaging fee
add_action( 'woocommerce_cart_calculate_fees', 'add_packaging_fee', 20, 1 );
function add_packaging_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$domain = "woocommerce";
$packing_fee = WC()->session->get( 'chosen_packing' ); // Dynamic packing fee
if ( $packing_fee === 'bag' ) {
$label = __("Bag packing fee", $domain);
$cost = 3.00;
} elseif ( $packing_fee === 'box' ) {
$label = __("Gift box packing fee", $domain);
$cost = 9.00;
}
if ( isset($cost) )
$cart->add_fee( $label, $cost );
}
// Field validation, as this packing field is required
add_action('woocommerce_checkout_process', 'packing_field_checkout_process');
function packing_field_checkout_process() {
// Check if set, if its not set add an error.
if ( isset($_POST['chosen_packing']) && empty($_POST['chosen_packing']) )
wc_add_notice( __( "Please choose a packing option...", "woocommerce" ), 'error' );
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
The error message when customer hasn't chosen a packing option:
I'm creating a plugin that will calculate custom shipping variants with API. I have a jQuery script that calculates postal and fias codes based on an entered address.
$("#billing_address_1").suggestions({
serviceUrl: "https://suggestions.dadata.ru/suggestions/api/4_1/rs",
token: php_vars.dadata_suggest_token,
type: "ADDRESS",
count: 5,
onSelect: function (suggestion) {
$("#billing_city").val(suggestion.data.city);
$("#billing_state").val(suggestion.data.region);
$("#billing_postcode").val(suggestion.data.postal_code);
if (suggestion.data.settlement_fias_id)
$("#billing_fias_code").val(suggestion.data.settlement_fias_id);
else if (suggestion.data.city_fias_id)
$("#billing_fias_code").val(suggestion.data.city_fias_id);
else
$("#billing_fias_code").val('');
}
});
To store the fias code, I created custom field.
add_filter( 'woocommerce_checkout_fields' , array( $this, 'custom_checkout_fields' ));
add_action( 'woocommerce_checkout_update_order_meta', array( $this, 'shipping_apartment_update_order_meta') );
function custom_checkout_fields( $fields ) {
$fields['shipping']['shipping_fias_code'] = array(
'type' => 'text',
'label' => __('FIAS', 'woocommerce'),
'placeholder' => _x('Код', 'placeholder', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide'),
'clear' => true
);
$fields['billing']['billing_fias_code'] = array(
'type' => 'text',
'label' => __('FIAS', 'woocommerce'),
'placeholder' => _x('Код', 'placeholder', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide'),
'clear' => true
);
return $fields;
}
function shipping_apartment_update_order_meta( $order_id ) {
if ( ! empty( $_POST['shipping_fias_code'] ) ) {
update_post_meta( $order_id, 'shipping_fias_code', sanitize_text_field( $_POST['shipping_fias_code'] ) );
}
if ( ! empty( $_POST['billing_fias_code'] ) ) {
update_post_meta( $order_id, 'billing_fias_code', sanitize_text_field( $_POST['billing_fias_code'] ) );
}
}
The calculate_shipping() method in WC_Shipping_Method in woocommerce calculates shipping options using the $ package variable, which has an 'destination' array field with information about the shipping address. The postal code is passed into this array by default. But I also need to pass my custom field inside $package.
As I understand it, the field that I created will save the information added there via the jQuery script, only after the form is posted. But other fields included in $package['destination'] are saved immediately after adding information to them.
How do I add data from a custom field in the checkout form to the $package['destination'] variable?
I can't test (or modify) your jQuery code, so you will have to handle it yourself, maybe making some changes to it. I have revisited completely all your code (except your jQuery code) and everything works as you expect.
So $package['destination'] will have an additional entry for 'fias_code'.
The commented code:
// Add billing and shipping fields
add_filter( 'woocommerce_billing_fields' , 'custom_billing_fields' );
add_filter( 'woocommerce_shipping_fields' , 'custom_shipping_fields' );
function custom_shipping_fields( $fields ) {
$fields['shipping_fias_code'] = array(
'type' => 'text',
'label' => __('FIAS', 'woocommerce'),
'placeholder' => _x('Код', 'placeholder', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide'),
'clear' => true
);
return $fields;
}
function custom_billing_fields( $fields ) {
$fields['billing_fias_code'] = array(
'type' => 'text',
'label' => __('FIAS', 'woocommerce'),
'placeholder' => _x('Код', 'placeholder', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide'),
'clear' => true
);
return $fields;
}
// Ajax sender
add_action( 'wp_footer', 'checkout_send_fias_code_via_ajax_js' );
function checkout_send_fias_code_via_ajax_js() {
if ( is_checkout() && ! is_wc_endpoint_url() ) :
?><script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
// Function that send the Ajax request
function sendAjaxRequest( value, fieldset = 'billing' ) {
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'fias_code',
'fias_code': value,
'fieldset' : fieldset
},
success: function (result) {
$(document.body).trigger('update_checkout'); // Update checkout processes
console.log( result ); // For testing (output data sent)
}
});
}
// Billing fias code change & input events
$(document.body).on( 'change input', 'input[name=billing_fias_code]', function() {
sendAjaxRequest( $(this).val() );
});
// Shipping fias code change & input events
$(document.body).on( 'change input', 'input[name=shipping_fias_code]', function() {
sendAjaxRequest( $(this).val(), 'shipping' );
});
});
</script>
<?php
endif;
}
// The Wordpress Ajax PHP receiver (set data to a WC_Session variable)
add_action( 'wp_ajax_fias_code', 'set_fias_code_to_wc_session' );
add_action( 'wp_ajax_nopriv_fias_code', 'set_fias_code_to_wc_session' );
function set_fias_code_to_wc_session() {
$field_key = 'fias_code';
if ( isset($_POST[$field_key]) && isset($_POST['fieldset']) ){
// Get data from custom session variable
$values = (array) WC()->session->get($field_key);
// Initializing when empty
if( ! empty($values) ) {
$values = array(
'billing' => WC()->customer->get_meta('billing_'.$field_key),
'shipping' => WC()->customer->get_meta('shipping_'.$field_key)
);
}
// Sanitizing data sent
$fieldset = esc_attr($_POST['fieldset']);
$fias_code = sanitize_text_field($_POST[$field_key]);
// Set / udpate custom WC_Session variable
$values[$fieldset] = $fias_code;
WC()->session->set($field_key, wc_clean($values));
// Send back to javascript the data received as an array (json encoded)
echo json_encode(array($fieldset.'_'.$field_key => $fias_code));
wp_die(); // always use die() or wp_die() at the end to avoird errors
}
}
// Update checkout fields 'fias_code' values from custom WC_session variable
add_filter('woocommerce_checkout_get_value', 'update_fias_code_checkout_fields_values', 10, 2 );
function update_fias_code_checkout_fields_values( $value, $input ) {
$field_key = 'fias_code';
// Get data from custom session variable
$values = (array) WC()->session->get($field_key);
if ( ! empty($values) ) {
if ( 'billing_'.$field_key === $input ) {
$value = $values['billing'];
}
if ( 'shipping_'.$field_key === $input ) {
$value = $values['shipping'];
}
}
return $value;
}
// Add 'fias_code' data to destination shipping packages
add_filter( 'woocommerce_cart_shipping_packages', 'add_fias_code_to_destination_shipping_package' );
function add_fias_code_to_destination_shipping_package( $packages ) {
$customer = WC()->customer; // The WC_Customer Object
// Get 'fias_code' data from customer meta data
$main_key = 'fias_code';
$meta_value = $customer->get_meta('shipping_'.$main_key);
$meta_value = empty($meta_value) ? $customer->get_meta('billing_'.$main_key) : $meta_value;
// Get data from custom session variable
$values = (array) WC()->session->get($main_key);
if ( ! empty($values) ) {
$session_value = $values['shipping'];
if ( $session_value === $meta_value ) {
$session_value = $values['billing'];
if ( $session_value !== $meta_value ) {
$meta_value = $values['billing'];
}
} else {
$meta_value = $session_value;
}
}
// Loop through shipping packages
foreach ( $packages as $key => $package ) {
// Set to destination package the "fias_code"
$packages[$key]['destination'][$main_key] = $meta_value;
}
return $packages;
}
// Remove custom WC_Session variable once order has been created (before thankyou)
add_action( 'woocommerce_checkout_order_created', 'remove_fias_code_custom_wc_session_variable' );
function remove_fias_code_custom_wc_session_variable() {
// Remove the custom WC_Session variable
WC()->session->__unset('fias_code');
}
This code goes in functions.php file of the active child theme (or active theme). Tested and works.
Important notes:
Displaying and save fias_code checkout fields:
I am using woocommerce_billing_fields and woocommerce_shipping_fields filter hooks instead of woocommerce_checkout_fields as that way the data is saved itself as order meta data and user meta data. So your last function is not required anymore.
The order meta keys start with an underscore like all billing and shipping order metadata.
The fields will be displayed on My account edit addresses… So if you want to avoid that you will need to add a condition to both related hooks.
Regarding my jQuery code:
You should better copy it to an external file and register/enqueue it in a clean WordPress way, restricting output to checkout page only. Then you will remove the related action hook and the hooked function…
Regarding action and filter hooks: You will have to change all add_action() and add_filter() for your plugin like:
add_filter( 'woocommerce_billing_fields' , array($this, 'custom_billing_fields') );
add_filter( 'woocommerce_shipping_fields' , array($this, 'custom_shipping_fields') );
add_action( 'wp_footer', array($this, 'checkout_send_fias_code_via_ajax_js') );
add_action( 'wp_ajax_fias_code', array($this, 'set_fias_code_to_wc_session') );
add_action( 'wp_ajax_nopriv_fias_code', array($this, 'set_fias_code_to_wc_session') );
add_filter('woocommerce_checkout_get_value', array($this, 'update_fias_code_checkout_fields_values'), 10, 2 );
add_filter( 'woocommerce_cart_shipping_packages', array($this, 'add_fias_code_to_destination_shipping_package') );
add_action( 'woocommerce_checkout_order_created', array($this, 'remove_fias_code_custom_wc_session_variable') );
I have added two custom input fields in the shipping method section by changing the template /genesis-sample/woocommerce/checkout/review-order.php
I have also managed to get them conditionally required. Only when the specific radio button is checked, the input fields appear and become required. I am using jQuery code to make the fields appear and disappear. All of this is working fine. The code is here:
if ( isset($_POST['shipping_method_0_legacy_local_pickup']) && $_POST['shipping_method_0_legacy_local_pickup'] == 1 ) {
$cheq = 'true';
}
else {
$cheq = 'false';
}
woocommerce_form_field( 'fieldtester1' , array(
'type' => 'text',
'class' => array('wccs-field-class wccs-form-row-wide blahblah1'),
'label' => 'Enter Your Carrier Name',
'required' => $cheq,
'placeholder' => 'Carrier Name',
), $checkout->get_value( 'fieldtester1' ));
woocommerce_form_field( 'fieldtester2' , array(
'type' => 'text',
'class' => array('wccs-field-class wccs-form-row-wide blahblah2'),
'label' => 'Enter Your Carrier Account #',
'required' => $cheq,
'placeholder' => 'Carrier Number',
), $checkout->get_value( 'fieldtester2' ));
But here's the problem, even with the required attribute set as true for the two fields, the validation doesn't happen if the field is empty when the Place Order button is pressed. Ideally, the order should not go through and an error message should be generated. I have already added following code in functions.php to force validation of the input field but it doesn't do a thing. The code is here:
add_action('woocommerce_checkout_process', 'carrier_checkout_process');
function carrier_checkout_process() {
if ( isset($_POST['shipping_method_0_legacy_local_pickup']) && $_POST['shipping_method_0_legacy_local_pickup'] == 1 ) {
if( empty( $_POST['fieldtester1'] ) ) {
wc_add_notice( ( "Please don't forget to enter your shipping carrier details." ), "error" );
}
}
}
So, here's what I am looking for:
can anyone help me in forcing the validation for two input fields I
have added?
After the validation, I would also like to add these two fields in the new order email, and order details in the Wordpress dashboard.
If you are wondering why I am not using a woocommerce checkout field hook to add the input fields in the first place...I am not adding the fields to the checkout form so the hooks aren't of any help. The fields are added in the shipping method section. Another reason was, I wanted to update the required attribute every time a user would switch the shipping method. Using Jquery to change the required attribute wasn't working for whatever reason, believe me I tried for two days. Anyways, that part is already working. The only issues are getting the fields to validate and add them to the order emails and order details. I have looked around everywhere and the closest help I got was this post where LoicTheAztec gave a detailed solution
This can be done without jQuery using a special hook that will display your two "Carrier" custom fields below legacy_local_pickup shipping method when it's selected. If customer change to a different shipping method, those fields will be removed.
So you should need to remove your customized template and all related code before.
Now the validation works perfectly and when "Carrier" custom fields are filled, they are saved in order meta data.
// Add custom fields to a specific selected shipping method
add_action( 'woocommerce_after_shipping_rate', 'carrier_custom_fields', 20, 2 );
function carrier_custom_fields( $method, $index ) {
if( ! is_checkout()) return; // Only on checkout page
$customer_carrier_method = 'legacy_local_pickup';
if( $method->id != $customer_carrier_method ) return; // Only display for "local_pickup"
$chosen_method_id = WC()->session->chosen_shipping_methods[ $index ];
// If the chosen shipping method is 'legacy_local_pickup' we display
if($chosen_method_id == $customer_carrier_method ):
echo '<div class="custom-carrier">';
woocommerce_form_field( 'carrier_name' , array(
'type' => 'text',
'class' => array('form-row-wide carrier-name'),
'label' => 'Carrier Information:',
'required' => true,
'placeholder' => 'Carrier Name',
), WC()->checkout->get_value( 'carrier_name' ));
woocommerce_form_field( 'carrier_number' , array(
'type' => 'text',
'class' => array('form-row-wide carrier-number'),
'required' => true,
'placeholder' => 'Carrier Number',
), WC()->checkout->get_value( 'carrier_number' ));
echo '</div>';
endif;
}
// Check custom fields validation
add_action('woocommerce_checkout_process', 'carrier_checkout_process');
function carrier_checkout_process() {
if( isset( $_POST['carrier_name'] ) && empty( $_POST['carrier_name'] ) )
wc_add_notice( ( "Please don't forget to enter the shipping carrier name." ), "error" );
if( isset( $_POST['carrier_number'] ) && empty( $_POST['carrier_number'] ) )
wc_add_notice( ( "Please don't forget to enter the shipping carrier account number." ), "error" );
}
// Save custom fields to order meta data
add_action( 'woocommerce_checkout_update_order_meta', 'carrier_update_order_meta', 30, 1 );
function carrier_update_order_meta( $order_id ) {
if( isset( $_POST['carrier_name'] ))
update_post_meta( $order_id, '_carrier_name', sanitize_text_field( $_POST['carrier_name'] ) );
if( isset( $_POST['carrier_number'] ))
update_post_meta( $order_id, '_carrier_number', sanitize_text_field( $_POST['carrier_number'] ) );
}
This code goes on functions.php file of your active child theme (or theme). Tested and works.
Not displayed:
Displayed when "Local Pickup" is selected:
My WooCommerce store has 2 different products.
In check out page, if customer buy a normal product, he only fill normal billing fields.
But if this customer buy a second product, the customer must be tick a checkbox that will make appear an additional field.
Anyone could help me solve this problem?
You will have to set in the function your 2 product IDS and to put the correct texts for your custom checkout fields. The code below will conditionally display a checkbox when both products are in cart. When customer will tick the checkbox an additional text field will appear:
// Add fields to the checkout
add_action( 'woocommerce_after_order_notes', 'custom_checkout_fields' );
function custom_checkout_fields( $checkout ) {
// Set HERE below your different product IDs
$product_1_id = 37; // Normal product
$product_2_id = 67; // Specific product (second product)
$has_id_1 = $has_id_2 = false;
// Check if products are in cart
foreach( WC()->cart->get_cart() as $cart_item ){
if( $cart_item['product_id'] == $product_1_id ) $has_id_1 = true;
if( $cart_item['product_id'] == $product_2_id ) $has_id_2 = true;
}
// Display conditionally Custom checkout Fields (when both products are in cart)
if( $has_id_1 && $has_id_2 ){
echo '<div id="custom_checkout_fields">';
// The Check box
woocommerce_form_field( 'my_checkbox', array(
'type' => 'checkbox',
'class' => array('my-field-class form-row-wide'),
'label' => __('Fill in this field'),
'placeholder' => __('Enter something'),
), $checkout->get_value( 'my_checkbox' ));
// The hidden field
woocommerce_form_field( 'my_text_field', array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'label' => __('Fill in this field'),
'placeholder' => __('Enter something'),
), $checkout->get_value( 'my_text_field' ));
echo '</div>';
$required = esc_attr__( 'required', 'woocommerce' );
// The jQuery Script
?>
<script>
jQuery(function($){
// Initialising variables
var textField = 'p#my_text_field_field',
checkboxField = 'input[name^="my_checkbox"]',
required = '<abbr class="required" title="<?php echo $required; ?>">*</abbr>'; // Required html
// Initialising at start (Hidding the text field)
$(textField).hide(function(){
$(this).removeClass("validate-required");
$(this).removeClass("woocommerce-validated");
$(this).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
if( $(textField+' > label > abbr').html() != undefined )
$(textField+' label > .required').remove();
});
// When Checkbox is checked / unchecked (Live event)
$( checkboxField ).click( function() {
if( $(this).prop('checked') == true )
$(textField).show(function(){
$(this).addClass("validate-required");
$(this).removeClass("woocommerce-validated");
$(this).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
if( $(textField+' > label > abbr').html() == undefined )
$(textField+' label').append(required);
});
else
$(textField).hide(function(){
$(this).removeClass("validate-required");
$(this).removeClass("woocommerce-validated");
$(this).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
if( $(textField+' > label > abbr').html() != undefined )
$(textField+' label > .required').remove();
});
});
});
</script>
<?php
}
}
// 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_text_field'] ) ) {
update_post_meta( $order_id, __('My Field'), sanitize_text_field( $_POST['my_text_field'] ) );
}
}
Code goes in function.php file of your active child theme (active theme or in any plugin file).
Tested and Works in WooCommerce 3+
Related official developer documentation: Customizing checkout fields using actions and filters
I am working with the Local Pickup Plus plugin for woocommerce and it is almost everything that I need, except for the fact that the customer has to manually select every product in the cart as either shipping or local pickup.
I was wondering if there was an easy way to force the customer to have all items shipped or all items picked up
I ended up solving this by writing my own function to only do what I was specifically looking for. This function adds the option to select from a drop down which store to pickup from and then updates the shipping accordingly.
/**
* Add store location select dropdown in checkout page
**/
add_filter( 'woocommerce_checkout_fields' , 'custom_store_pickup_field');
function custom_store_pickup_field( $fields ) {
$fields['billing']['store_pickup'] = array(
'type' => 'select',
'options' => array(
'option_0'=> 'Please Select a Delivery Option',
'option_1' => 'Delivery',
'option_2' => 'Gym1',
'option_3' => 'Gym2'
),
'label' => __('Delivery or Store Pickup', 'woocommerce'),
'required' => true,
'class' => array('store-pickup form-row-wide'),
'id' => 'store_pickup_val',
'clear' => true
);
return $fields;
}
//* Process the checkout
add_action('woocommerce_checkout_process', 'wps_select_checkout_field_process');
function wps_select_checkout_field_process() {
global $woocommerce;
// Check if set, if its not set add an error.
if ($_POST['store_pickup'] == "option_0")
wc_add_notice( '<strong>Please select a day part under Delivery options</strong>', 'error' );
}
add_action( 'woocommerce_after_checkout_form', 'gym_opening_hours', 6);
function gym_opening_hours() {
?>
<script type="text/javascript">
jQuery('#store_pickup_val').change(function(){
jQuery('body').trigger('update_checkout');
jQuery( ".gym-collection" ).remove();
if (this.value == 'option_1') {
jQuery('#shipping_method_0_flat_rate1').prop('checked', true);
}
if (this.value == 'option_2') {
jQuery( "<p>Order can be collected between 4pm - 7pm on Tuesdays</p>" ).addClass("gym-collection").insertAfter( "#store_pickup_val" );
jQuery('#shipping_method_0_local_pickup3').prop('checked', true);
}
if (this.value == 'option_3') {
jQuery( "<p>Order can be collected between 4pm - 7pm on Tuesdays</p>" ).addClass("gym-collection").insertAfter( "#store_pickup_val" );
jQuery('#shipping_method_0_local_pickup3').prop('checked', true);
}
else {
}
});
</script>
<?php
}
# add this in your plugin file and that's it, the calculate_shipping method of your shipping plugin class will be called again
function action_woocommerce_checkout_update_order_review($array, $int)
{
WC()->cart->calculate_shipping();
return;
}
add_action('woocommerce_checkout_update_order_review', 'action_woocommerce_checkout_update_order_review', 10, 2);
?>
<?php