Based on "Add a custom checkbox in WooCommerce checkout which value shows in admin edit order", I am trying to display custom radio buttons fields only if customer state is NewYork to let customer pick a delivery time in checkout page by choosing a delivery time option. Then admin could see the chosen delivery time in admin order edit pages.
This image will explain everything:
Here is my code attempt (with one checkbox for testing):
$user_state = get_user_meta( get_current_user_id(), 'billing_state')
if($user_state=='NY'){
add_action( 'woocommerce_review_order_before_submit', 'my_custom_checkout_field' );
function my_custom_checkout_field() {
echo '<div id="my_custom_checkout_field">';
woocommerce_form_field( 'my_field_name', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('My custom checkbox'),
'required'
), WC()->checkout->get_value( 'my_field_name' ) );
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', 10, 1 );
function custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['my_field_name'] ) )
update_post_meta( $order_id, 'my_field_name', $_POST['my_field_name'] );
}
// Display the custom field result on the order edit page (backend) when checkbox has been checked
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
$my_field_name = get_post_meta( $order->get_id(), 'my_field_name', true );
if( $my_field_name == 1 )
echo '<p><strong>My custom field: </strong> <span style="color:red;">Is enabled</span></p>';
}}
But the custom field value isn't displayed. Any help is appreciated.
First you need to include your state condition (New York) inside the function that display your custom radio buttons on checkout page:
if( WC()->customer->get_shipping_state() == 'NY' ) {
// Do something for customers from "New York"
}
To make this possible Ajax and WC_Session is required, because checkout page is Ajax refreshed and it will not keep the customer choice.
So I have revisited all your existing code:
// Custom setting function: Here define your delivery options for "New york"
function get_newyork_delivery_options(){
return array(
'9am-2pm' => __('9 AM - 2 PM'),
'2pm-6pm' => __('2 PM - 6 PM'),
'6pm-9pm' => __('6 PM - 9 PM'),
);
}
// Display delivery custom radio buttons field in checkout for "New york" state
add_action( 'woocommerce_review_order_after_shipping', 'display_delivery_choice_field', 20 );
function display_delivery_choice_field(){
// Only for "New York" state
if( WC()->customer->get_shipping_state() == 'NY' ) :
$choice = WC()->session->get('delivery_choice');
// Display the radio buttons
echo '<tr class="delivery-options">
<th>' . __("Delivery time") . '<br><em>(' . __("for New York") . ')</em></th>
<td><span class="woocommerce-input-wrapper">';
foreach ( get_newyork_delivery_options() as $key => $label ) {
$checked = $choice == $key ? 'checked="checked"' : '';
$field_id = 'delivery_time' . $key;
echo '<label for="' . $field_id . '" class="radio " style="display:block">
<input type="radio" class="input-radio " id="' . $field_id . '" name="delivery_time" value="' . $key . '" ' . $checked . '> ' . $label;
echo '</label>';
}
echo '</span></td>
<tr>';
endif;
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_delivery_script' );
function checkout_delivery_script() {
// Only on Checkout
if( is_checkout() && ! is_wc_endpoint_url() ) :
if( WC()->session->__isset('delivery_choice') )
WC()->session->__unset('delivery_choice')
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on('change', 'input[name="delivery_time"]', function(){
var delivery = $(this).val();
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'delivery_choice',
'delivery_choice': delivery,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_delivery_choice', 'get_delivery_choice' );
add_action( 'wp_ajax_nopriv_delivery_choice', 'get_delivery_choice' );
function get_delivery_choice() {
if ( isset($_POST['delivery_choice']) ) {
WC()->session->set('delivery_choice', esc_attr( $_POST['delivery_choice'] ) );
echo WC()->session->get('delivery_choice');
}
die();
}
// Save the chosen delivery time as order meta data
add_action('woocommerce_checkout_create_order', 'custom_checkout_field_added_as_order_meta', 10, 2 );
function custom_checkout_field_added_as_order_meta( $order, $data ) {
if ( isset( $_POST['delivery_option'] ) )
$order->add_meta_data( '_delivery_time', esc_attr( $_POST['delivery_time'] ) );
}
// Display the chosen delivery time on order totals lines everywhere (except admin)
add_action('woocommerce_get_order_item_totals', 'display_bacs_option_on_order_totals', 10, 3 );
function display_bacs_option_on_order_totals( $total_rows, $order, $tax_display ) {
if ( $delivery_time = $order->get_meta('_delivery_time') ) {
$sorted_total_rows = [];
foreach ( $total_rows as $key_row => $total_row ) {
$sorted_total_rows[$key_row] = $total_row;
if( $key_row === 'shipping' ) {
$sorted_total_rows['delivery_time'] = [
'label' => __( "Delivery time", "woocommerce"),
'value' => esc_html( get_newyork_delivery_options()[$delivery_time] ),
];
}
}
$total_rows = $sorted_total_rows;
}
return $total_rows;
}
// Display the chosen delivery option on admin order edit page for new york state
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
if( $key = $order->get_meta( '_delivery_time' ) ) {
$label = get_newyork_delivery_options()[$key];
echo '<p><strong>Delivery <em>(New York)</em>: </strong> <span style="color:green;">' . $label . '</span></p>';
}
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
Related
In Woocommerce checkout page, I'am trying to add a check box on checkout page
I have referred to these articles
woocommerce custom checkout field to add fee to order ajax
Checkbox field that add / remove a custom fee in WooCommerce
Add a checkout checkbox field that enable a percentage fee in Woocommerce
add_action( 'woocommerce_review_order_before_order_total', 'checkout_shipping_form_packing_addition', 20 );
function checkout_shipping_form_packing_addition( ){
echo '<tr class="packing-select"><th>';
woocommerce_form_field( 'add_gift_box', array(
'type' => 'checkbox',
'class' => array('add_gift_box form-row-wide'),
'label' => __('Hỗ trợ cài đặt'),
'placeholder' => __(''),
));
echo '</th><td>';}
add_action( 'wp_footer', 'woocommerce_add_gift_box' );
function woocommerce_add_gift_box() {
if (is_checkout()) {
?>
<script type="text/javascript">
jQuery( document ).ready(function( $ ) {
$('#add_gift_box').click(function(){
jQuery('body').trigger('update_checkout');
});
});
</script>
<?php
}}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
function woo_add_cart_fee( $cart ){
if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
return;
}
if ( isset( $_POST['post_data'] ) ) {
parse_str( $_POST['post_data'], $post_data );
} else {
$post_data = $_POST; // fallback for final checkout (non-ajax)
}
if (isset($post_data['add_gift_box'])) {
$sl = WC()->cart->get_cart_contents_count();
$extracost = 50000 * $sl; // not sure why you used intval($_POST['state']) ?
WC()->cart->add_fee( 'Hỗ trợ cài đặt x '.$sl.'', $extracost );
}}
add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 );
function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'add_gift_box' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
It does not work as I would like. What I am doing wrong?
Any help is appreciated.
You really need to use Wordpress Ajax with WC_sessions to make it work like in "Add a checkout checkbox field that enable a percentage fee in Woocommerce" answer thread.
Here is your revisited code:
// Display the custom checkbow field in checkout
add_action( 'woocommerce_review_order_before_order_total', 'fee_installment_checkbox_field', 20 );
function fee_installment_checkbox_field(){
echo '<tr class="packing-select"><th>';
woocommerce_form_field( 'installment_fee', array(
'type' => 'checkbox',
'class' => array('installment-fee form-row-wide'),
'label' => __('Support installation'),
'placeholder' => __(''),
), WC()->session->get('installment_fee') ? '1' : '' );
echo '</th><td>';
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_fee_script' );
function checkout_fee_script() {
// Only on Checkout
if( is_checkout() && ! is_wc_endpoint_url() ) :
if( WC()->session->__isset('installment_fee') )
WC()->session->__unset('installment_fee')
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on('change', 'input[name=installment_fee]', function(){
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'installment_fee',
'installment_fee': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_installment_fee', 'get_installment_fee' );
add_action( 'wp_ajax_nopriv_installment_fee', 'get_installment_fee' );
function get_installment_fee() {
if ( isset($_POST['installment_fee']) ) {
WC()->session->set('installment_fee', ($_POST['installment_fee'] ? true : false) );
}
die();
}
// Add a custom calculated fee conditionally
add_action( 'woocommerce_cart_calculate_fees', 'set_installment_fee' );
function set_installment_fee( $cart ){
if ( is_admin() && ! defined('DOING_AJAX') || ! is_checkout() )
return;
if ( did_action('woocommerce_cart_calculate_fees') >= 2 )
return;
if ( 1 == WC()->session->get('installment_fee') ) {
$items_count = WC()->cart->get_cart_contents_count();
$fee_label = sprintf( __( "Support installation %s %s" ), '×', $items_count );
$fee_amount = 50000 * $items_count;
WC()->cart->add_fee( $fee_label, $fee_amount );
}
}
add_filter( 'woocommerce_form_field' , 'remove_optional_txt_from_installment_checkbox', 10, 4 );
function remove_optional_txt_from_installment_checkbox( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'installment_fee' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works on Woocommerce version 3.6.5 with Storefront theme.
Based on Display a checkbox that add a fee in Woocommerce checkout page answer code I am trying to change usage to Cart page, rather than checkout page per clients request.
So far I managed to display custom fee check box on cart page and trigger Ajax.
However Cart totals are not updated.
If someone can help on code or point me in right direction?
// Display the custom checkbox field in cart
add_action( 'woocommerce_cart_totals_before_order_total', 'fee_installment_checkbox_field', 20 );
function fee_installment_checkbox_field(){
echo '<tr class="packing-select"><th>Priority Dispatch</th><td>';
woocommerce_form_field( 'priority_fee', array(
'type' => 'checkbox',
'class' => array('installment-fee form-row-wide'),
'label' => __(' $20.00'),
'placeholder' => __(''),
), WC()->session->get('priority_fee') ? '1' : '' );
echo '<div class="tooltip">?
<span class="tooltiptext">By selecting this option... </span>
</div></td>';
}
// jQuery - Ajax script
add_action( 'wp_footer', 'woo_add_cart_fee' );
function woo_add_cart_fee() {
// Only on Checkout
if( ! is_wc_endpoint_url() ) :
if( WC()->session->__isset('priority_fee') )
WC()->session->__unset('priority_fee')
?>
<script type="text/javascript">
jQuery( function($){
//if (typeof wc_add_to_cart_params === 'undefined')
// return false;
$('tr.packing-select').on('change', 'input[name=priority_fee]', function(){
console.log('tests');
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
//url: wc_add_to_cart_params.ajax_url,
data: {
'action': 'priority_fee',
'priority_fee': fee,
},
success: function (response) {
$('body').trigger('added_to_cart');
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_priority_fee', 'get_priority_fee' );
add_action( 'wp_ajax_nopriv_priority_fee', 'get_priority_fee' );
function get_priority_fee() {
if ( isset($_POST['priority_fee']) ) {
WC()->session->set('priority_fee', ($_POST['priority_fee'] ? true : false) );
}
die();
}
// Add a custom calculated fee conditionally
add_action( 'woocommerce_cart_calculate_fees', 'set_priority_fee' );
function set_priority_fee( $cart ){
if ( is_admin() && ! defined('DOING_AJAX') )
return;
if ( did_action('woocommerce_cart_calculate_fees') >= 2 )
return;
if ( 1 == WC()->session->get('priority_fee') ) {
$items_count = WC()->cart->get_cart_contents_count();
$fee_label = sprintf( __( "PRIORITY DISPATCH %s %s" ), '×', $items_count );
$fee_amount = 20;
WC()->cart->add_fee( $fee_label, $fee_amount );
}
}
add_filter( 'woocommerce_form_field' , 'remove_optional_txt_from_installment_checkbox', 10, 4 );
function remove_optional_txt_from_installment_checkbox( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'priority_fee' === $key ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
Additionally is this the way this should be done, or is there an easier way to do it?
There are some mistakes in your code. Also, on cart page, jQuery events and Ajax behavior are a bit different, so it requires some changes:
// Display the checkout field in cart page totals section
add_action( 'woocommerce_cart_totals_before_order_total', 'display_priority_fee_checkbox_field', 20 );
function display_priority_fee_checkbox_field(){
echo '<tr class="installment-section">
<th>'.__("Priority Dispatch").'</th><td>';
woocommerce_form_field( 'priority_fee', array(
'type' => 'checkbox',
'class' => array('form-row-wide'),
'label' => __(' $20.00'),
), WC()->session->get('priority_fee') ? '1' : '' );
echo '<div class="tooltip">?
<span class="tooltiptext">'.__("By selecting this option... ").'</span>
</div></td>';
}
// Remove "(optional)" text from the field
add_filter( 'woocommerce_form_field' , 'remove_optional_txt_from_priority_fee_checkbox', 10, 4 );
function remove_optional_txt_from_priority_fee_checkbox( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'priority_fee' === $key ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// jQuery :: Ajax script
add_action( 'wp_footer', 'priority_fee_js_script' );
function priority_fee_js_script() {
// On Order received page, remove the wc session variable if it exist
if ( is_wc_endpoint_url('order-received')
&& WC()->session->__isset('priority_fee') ) :
WC()->session->__unset('priority_fee');
// On Cart page: jQuert script
elseif ( is_cart() ) :
?>
<script type="text/javascript">
jQuery( function($){
if (typeof woocommerce_params === 'undefined')
return false;
var c = 'input[name=priority_fee]';
$(document.body).on( 'click change', c, function(){
console.log('click');
var fee = $(c).is(':checked') ? '1' : '';
$.ajax({
type: 'POST',
url: woocommerce_params.ajax_url,
data: {
'action': 'priority_fee',
'priority_fee': fee,
},
success: function (response) {
setTimeout(function(){
$(document.body).trigger('added_to_cart');
}, 500);
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_priority_fee', 'priority_fee_ajax_receiver' );
add_action( 'wp_ajax_nopriv_priority_fee', 'priority_fee_ajax_receiver' );
function priority_fee_ajax_receiver() {
if ( isset($_POST['priority_fee']) ) {
$priority_fee = $_POST['priority_fee'] ? true : false;
// Set to a WC Session variable
WC()->session->set('priority_fee', $priority_fee );
echo $priority_fee ? '1' : '0';
die();
}
}
// Add a custom calculated fee conditionally
add_action( 'woocommerce_cart_calculate_fees', 'set_priority_fee' );
function set_priority_fee( $cart ){
if ( is_admin() && ! defined('DOING_AJAX') )
return;
if ( WC()->session->get('priority_fee') ) {
$item_count = $cart->get_cart_contents_count();
$fee_label = sprintf( __( "PRIORITY DISPATCH %s" ), '× ' . $item_count );
$fee_amount = 20 * $item_count;
$cart->add_fee( $fee_label, $fee_amount );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
I have added a new custom datepicker field on the WooCommerce checkout page.
I am using Enabling a date-picker in Woocommerce checkout fields. All it's OK On checkout page.
But now I really don't know how can I save and add this new field on the order notes. Any help is appreciated.
Section 1
The following will display a custom datepicker field on checkout, it will validate the field and save It.
The chosen date will be displayed on admin order, customer order and emails
To include this date on customer note, use the code from "section 2" at the end.
The code:
// Register main datepicker jQuery plugin script
add_action( 'wp_enqueue_scripts', 'enabling_date_picker' );
function enabling_date_picker() {
// Only on front-end and checkout page
if( is_admin() || ! is_checkout() ) return;
// Load the datepicker jQuery-ui plugin script
wp_enqueue_script('jquery-ui-datepicker');
wp_enqueue_style('jquery-ui');
}
// Add custom checkout datepicker field
add_action( 'woocommerce_before_order_notes', 'checkout_display_datepicker_custom_field' );
function checkout_display_datepicker_custom_field( $checkout ) {
$field_id = 'my_datepicker';
echo '<div id="datepicker-wrapper">';
woocommerce_form_field( $field_id, array(
'type' => 'text',
'class'=> array( 'form-row-wide'),
'label' => __('Choose a date'),
'required' => true, // Or false
), '' );
echo '<br></div>';
// Jquery: Enable the Datepicker
?>
<script language="javascript">
jQuery( function($){
var a = '#<?php echo $field_id ?>';
$(a).datepicker({
dateFormat: 'dd-mm-yy', // ISO formatting date
});
});
</script>
<?php
}
// Field validation
add_action( 'woocommerce_after_checkout_validation', 'checkout_datepicker_custom_field_validation', 10, 2 );
function checkout_datepicker_custom_field_validation( $data, $errors ) {
$field_id = 'my_datepicker';
if ( isset($_POST[$field_id]) && empty($_POST[$field_id]) ) {
$errors->add( 'validation', __('You must choose a date on datepicker field.', 'woocommerce') );
}
}
// Save field
add_action( 'woocommerce_checkout_create_order', 'save_datepicker_custom_field_value', 10, 2 );
function save_datepicker_custom_field_value( $order, $data ){
$field_id = 'my_datepicker';
$meta_key = '_'.$field_id;
if ( isset($_POST[$field_id]) && ! empty($_POST[$field_id]) ) {
$order->update_meta_data( $meta_key, esc_attr($_POST[$field_id]) );
}
}
// Display custom field value in admin order pages
add_action( 'woocommerce_admin_order_data_after_billing_address', 'admin_display_date_custom_field_value', 10, 1 );
function admin_display_date_custom_field_value( $order ) {
$meta_key = '_my_datepicker';
$meta_value = $order->get_meta( $meta_key ); // Get carrier company
if( ! empty($meta_value) ) {
// Display
echo '<p><strong>' . __("Date", "woocommerce") . '</strong>: ' . $meta_value . '</p>';
}
}
// Display custom field value after shipping line everywhere (orders and emails)
add_filter( 'woocommerce_get_order_item_totals', 'display_date_custom_field_value_on_order_item_totals', 10, 3 );
function display_date_custom_field_value_on_order_item_totals( $total_rows, $order, $tax_display ){
$field_id = 'my_datepicker';
$meta_key = '_my_datepicker';
$meta_value = $order->get_meta( $meta_key ); // Get carrier company
if( ! empty($meta_value) ) {
$new_total_rows = [];
// Loop through order total rows
foreach( $total_rows as $key => $values ) {
$new_total_rows[$key] = $values;
// Inserting the carrier company under shipping method
if( $key === 'shipping' ) {
$new_total_rows[$field_id] = array(
'label' => __("Date", "woocommerce") . ':',
'value' => $meta_value,
);
}
}
return $new_total_rows;
}
return $total_rows;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Section 2
To add this field to Customer order notes you will use the following instead:
// Register main datepicker jQuery plugin script
add_action( 'wp_enqueue_scripts', 'enabling_date_picker' );
function enabling_date_picker() {
// Only on front-end and checkout page
if( is_admin() || ! is_checkout() ) return;
// Load the datepicker jQuery-ui plugin script
wp_enqueue_script('jquery-ui-datepicker');
wp_enqueue_style('jquery-ui');
}
// Add custom checkout datepicker field
add_action( 'woocommerce_before_order_notes', 'checkout_display_datepicker_custom_field' );
function checkout_display_datepicker_custom_field( $checkout ) {
$field_id = 'my_datepicker';
echo '<div id="datepicker-wrapper">';
woocommerce_form_field( $field_id, array(
'type' => 'text',
'class'=> array( 'form-row-wide'),
'label' => __('Choose a date'),
'required' => true, // Or false
), '' );
echo '<br></div>';
// Jquery: Enable the Datepicker
?>
<script language="javascript">
jQuery( function($){
var a = '#<?php echo $field_id ?>';
$(a).datepicker({
dateFormat: 'dd-mm-yy', // ISO formatting date
});
});
</script>
<?php
}
// Field validation
add_action( 'woocommerce_after_checkout_validation', 'checkout_datepicker_custom_field_validation', 10, 2 );
function checkout_datepicker_custom_field_validation( $data, $errors ) {
$field_id = 'my_datepicker';
if ( isset($_POST[$field_id]) && empty($_POST[$field_id]) ) {
$errors->add( 'validation', __('You must choose a date on datepicker field.', 'woocommerce') );
}
}
// Save field
add_action( 'woocommerce_checkout_create_order', 'save_datepicker_custom_field_value', 10, 2 );
function save_datepicker_custom_field_value( $order, $data ){
$field_id = 'my_datepicker';
$meta_key = '_'.$field_id;
if ( isset($_POST[$field_id]) && ! empty($_POST[$field_id]) ) {
$date = esc_attr($_POST[$field_id]);
$order->update_meta_data( $meta_key, $date ); // Save date as order meta data
$note = sprintf(__("Chosen date: %s.", "woocommerce"), $date );
$note = isset($data['order_comments']) && ! empty($data['order_comments']) ? $data['order_comments'] . '. ' . $note : $note;
// Save date on customer order note
$order->set_customer_note( $note );
}
}
// Display custom field value in admin order pages
add_action( 'woocommerce_admin_order_data_after_billing_address', 'admin_display_date_custom_field_value', 10, 1 );
function admin_display_date_custom_field_value( $order ) {
$meta_key = '_my_datepicker';
$meta_value = $order->get_meta( $meta_key ); // Get carrier company
if( ! empty($meta_value) ) {
// Display
echo '<p><strong>' . __("Chosen date", "woocommerce") . '</strong>: ' . $meta_value . '</p>';
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
I have the below custom metakey which is an optin checkbox during checkout:
//1. ADD OPT IN OPTION IN CHECKOUT AND SAVE IN THE ORDER
// Add checkbox optin before T&Cs
add_action( 'woocommerce_checkout_before_terms_and_conditions', 'marketing_opting_field' );
function marketing_opting_field() {
echo '<div id="marketing_opting_field">';
woocommerce_form_field( 'marketing_opting', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Yes, sign me up'),
'default' => 1,
), WC()->checkout->get_value( 'marketing_opting' ) );
echo '</div>';
}
// Save the optin field in the order meta, when checkbox has been checked
add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta', 10, 1 );
function custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['marketing_opting'] ) )
update_post_meta( $order_id, 'marketing_opting', $_POST['marketing_opting'] );
}
// Display the result of the checked optin in the order under billing address
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
$marketing_opting = get_post_meta( $order->get_id(), 'marketing_opting', true );
if( $marketing_opting == 1 )
echo '<p><strong>Has opted in for marketing purposes.</p>';
}
// 2. SHOW CUSTOM COLUMN FOR THE OPTIN OPTION
// Adding custom column title
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 12, 1 );
function custom_shop_order_column($columns)
{
$action_column = $columns['order_actions'];
unset($columns['order_actions']);
//add the new column "Opt in"
$columns['order_marketing'] = '<p align="center">Opted in?</p>'; // title
$columns['order_actions'] = $action_column;
return $columns;
}
// Add the data for each order
add_action( 'manage_shop_order_posts_custom_column' , 'custom_order_list_column_content', 10, 2 );
function custom_order_list_column_content( $column, $post_id ){
$marketing_opting = get_post_meta( $post_id, 'marketing_opting', true );
if( $marketing_opting == 1)
switch($column){
case 'order_marketing' : echo '<p align="center"><span class="dashicons dashicons-yes"></span><span style="color: #F21891; font-weight: 600;">Signed Up</span></p>';
break;
}
}
So above is working and shows below the column, but I would like to have a filter in the admin bar and a search for Signed Up gives the desired result:
The search is not working, because the value of the checkbox for checked is 1 and does not resognise other words. I have added below, but it's not giving the result:
add_filter( 'woocommerce_shop_order_search_fields', 'marketing_search_fields', 10, 1 );
function marketing_search_fields( $meta_keys ){
$meta_keys[] = 'marketing_opting';
return $meta_keys;
}
The admin bar filter; the only related posts I could find are all about order statuses and not a custom metakey. I am not sure how to add this correctly, I started with the below, but there are obvious errors, and I am stuck.
add_filter( 'views_edit-shop_order' , 'marketing_opt_in_filter', 10, 1);
function marketing_opt_in_filter( $views ) {
$marketing_opting = get_post_meta( $post_id, 'marketing_opting', true );
if( $marketing_opting == 1)
$query_string = admin_url( 'edit.php?post_type=shop_order' ) ;
$query_string = add_query_arg( 'marketing_opting' , 'yes' , $query_string ) ;
$views[ 'marketing_opting' ] = 'Opted In (%s)' ;
return $views ;
}
I have revisited your existing code a bit and added a dropdown filter for the "marketing optin" custom field:
//1. ADD OPT IN OPTION IN CHECKOUT AND SAVE IN THE ORDER
// Add checkbox optin before T&Cs
add_action( 'woocommerce_checkout_before_terms_and_conditions', 'marketing_opting_field' );
function marketing_opting_field() {
echo '<div id="marketing_opting_field">';
woocommerce_form_field( 'marketing_opting', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Yes, sign me up'),
'default' => 1,
), WC()->checkout->get_value( 'marketing_opting' ) );
echo '</div>';
}
// Save the optin field as custom order meta, when checkbox has been checked
add_action( 'woocommerce_checkout_create_order', 'action_checkout_update_order_meta', 10, 2 );
function action_checkout_update_order_meta( $order, $data ) {
if( isset($_POST['marketing_opting']) )
$order->update_meta_data( '_marketing_opting', empty($_POST['marketing_opting']) ? 'no' : 'yes' );
}
// Save the optin field as custom user meta, when checkbox has been checked
add_action( 'woocommerce_checkout_update_customer', 'action_checkout_update_customer_meta', 10, 2 );
function action_checkout_update_customer_meta( $customer, $data ) {
if( isset($_POST['marketing_opting']) )
$customer->update_meta_data( 'marketing_opting', empty($_POST['marketing_opting']) ? 'no' : 'yes' );
}
// Display the result of the checked optin in the order under billing address
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
if( $order->get_meta( '_marketing_opting' ) === 'yes' )
echo '<p><strong>Has opted in for marketing purposes.</p>';
}
// 2. SHOW CUSTOM COLUMN FOR THE OPTIN OPTION
// Adding custom column title
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 12, 1 );
function custom_shop_order_column($columns)
{
$action_column = $columns['order_actions'];
unset($columns['order_actions']);
//add the new column "Opt in"
$columns['order_marketing'] = '<div align="center">' .__("Opted in?") . '</div>'; // title
$columns['order_actions'] = $action_column;
return $columns;
}
// Add the data for each order
add_action( 'manage_shop_order_posts_custom_column' , 'custom_order_list_column_content', 10, 2 );
function custom_order_list_column_content( $column, $post_id ){
global $post, $the_order;
if ($column ==='order_marketing') {
$value = $the_order->get_meta( '_marketing_opting' );
$label = $value === 'yes' ? __('Signed Up') : ucfirst($value);
$color = $value === 'yes' ? 'color:#00cc00;' : 'color:#bbbbbb;';
echo '<p align="center" style="'.$color.'"><span class="dashicons dashicons-'.$value.'"></span><span style="font-weight:600;">'.$label.'</span></p>';
}
}
// 3. Make marketing optin meta searchable from search field (can't work very well for 'yes' or 'no' values!)
// Make a custom meta field searchable from the admin order list search field
add_filter( 'woocommerce_shop_order_search_fields', 'marketing_search_fields', 10, 1 );
function marketing_search_fields( $meta_keys ){
$meta_keys[] = '_marketing_opting';
return $meta_keys;
}
// 4. Add a dropdown filter to get orders by marketing optin meta value
// Add a dropdown to filter orders by Marketing optin
add_action( 'restrict_manage_posts', 'display_admin_shop_order_marketing_opting_filter' );
function display_admin_shop_order_marketing_opting_filter(){
global $pagenow, $post_type;
if( 'shop_order' === $post_type && 'edit.php' === $pagenow ) {
$domain = 'woocommerce';
$current = isset($_GET['filter_shop_order_marketing'])? $_GET['filter_shop_order_marketing'] : '';
echo '<select name="filter_shop_order_marketing">
<option value="">' . __('Filter Marketing optin', $domain) . '</option>';
$options = ['yes' => __('Signed Up'), 'no' => __('No')];
foreach ( $options as $key => $label ) {
printf( '<option value="%s"%s>%s</option>', $key,
$key === $current ? '" selected="selected"' : '', $label );
}
echo '</select>';
}
}
// Process the filter dropdown for orders by Marketing optin
add_filter( 'request', 'process_admin_shop_order_marketing_opting_filter', 99 );
function process_admin_shop_order_marketing_opting_filter( $vars ) {
global $pagenow, $typenow;
if ( $pagenow == 'edit.php' && isset( $_GET['filter_shop_order_marketing'] )
&& $_GET['filter_shop_order_marketing'] != '' && 'shop_order' === $typenow ) {
$vars['meta_key'] = '_marketing_opting';
$vars['meta_value'] = wc_clean( $_GET['filter_shop_order_marketing'] );
}
return $vars;
}
Note: I have change the order meta_key to _marketing_opting starting with an underscore as most other existing metakeys...
Also I have added a function that register that "marketing optin" value in user meta data, as it will be used by checkout on WC()->checkout->get_value( 'marketing_opting' ) for customers that have already made an order.
Field validation (optional)
If you make this checkout field required, you will need field validation… Then add the following:
// Custom Checkout field validation
add_action('woocommerce_checkout_process', 'custom_checkout_field_validation');
function custom_checkout_field_validation() {
if ( isset($_POST['marketing_opting']) ) {
wc_add_notice( '<strong>'. __("Please select a value", "woocommerce") . '</strong> | '.$_POST['marketing_opting'], 'error' );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
In Woocommerce checkout page, I'am trying to add a check box on checkout page
I have referred to these articles
woocommerce custom checkout field to add fee to order ajax
Checkbox field that add / remove a custom fee in WooCommerce
Add a checkout checkbox field that enable a percentage fee in Woocommerce
add_action( 'woocommerce_review_order_before_order_total', 'checkout_shipping_form_packing_addition', 20 );
function checkout_shipping_form_packing_addition( ){
echo '<tr class="packing-select"><th>';
woocommerce_form_field( 'add_gift_box', array(
'type' => 'checkbox',
'class' => array('add_gift_box form-row-wide'),
'label' => __('Hỗ trợ cài đặt'),
'placeholder' => __(''),
));
echo '</th><td>';}
add_action( 'wp_footer', 'woocommerce_add_gift_box' );
function woocommerce_add_gift_box() {
if (is_checkout()) {
?>
<script type="text/javascript">
jQuery( document ).ready(function( $ ) {
$('#add_gift_box').click(function(){
jQuery('body').trigger('update_checkout');
});
});
</script>
<?php
}}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
function woo_add_cart_fee( $cart ){
if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
return;
}
if ( isset( $_POST['post_data'] ) ) {
parse_str( $_POST['post_data'], $post_data );
} else {
$post_data = $_POST; // fallback for final checkout (non-ajax)
}
if (isset($post_data['add_gift_box'])) {
$sl = WC()->cart->get_cart_contents_count();
$extracost = 50000 * $sl; // not sure why you used intval($_POST['state']) ?
WC()->cart->add_fee( 'Hỗ trợ cài đặt x '.$sl.'', $extracost );
}}
add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 );
function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'add_gift_box' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
It does not work as I would like. What I am doing wrong?
Any help is appreciated.
You really need to use Wordpress Ajax with WC_sessions to make it work like in "Add a checkout checkbox field that enable a percentage fee in Woocommerce" answer thread.
Here is your revisited code:
// Display the custom checkbow field in checkout
add_action( 'woocommerce_review_order_before_order_total', 'fee_installment_checkbox_field', 20 );
function fee_installment_checkbox_field(){
echo '<tr class="packing-select"><th>';
woocommerce_form_field( 'installment_fee', array(
'type' => 'checkbox',
'class' => array('installment-fee form-row-wide'),
'label' => __('Support installation'),
'placeholder' => __(''),
), WC()->session->get('installment_fee') ? '1' : '' );
echo '</th><td>';
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_fee_script' );
function checkout_fee_script() {
// Only on Checkout
if( is_checkout() && ! is_wc_endpoint_url() ) :
if( WC()->session->__isset('installment_fee') )
WC()->session->__unset('installment_fee')
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on('change', 'input[name=installment_fee]', function(){
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'installment_fee',
'installment_fee': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_installment_fee', 'get_installment_fee' );
add_action( 'wp_ajax_nopriv_installment_fee', 'get_installment_fee' );
function get_installment_fee() {
if ( isset($_POST['installment_fee']) ) {
WC()->session->set('installment_fee', ($_POST['installment_fee'] ? true : false) );
}
die();
}
// Add a custom calculated fee conditionally
add_action( 'woocommerce_cart_calculate_fees', 'set_installment_fee' );
function set_installment_fee( $cart ){
if ( is_admin() && ! defined('DOING_AJAX') || ! is_checkout() )
return;
if ( did_action('woocommerce_cart_calculate_fees') >= 2 )
return;
if ( 1 == WC()->session->get('installment_fee') ) {
$items_count = WC()->cart->get_cart_contents_count();
$fee_label = sprintf( __( "Support installation %s %s" ), '×', $items_count );
$fee_amount = 50000 * $items_count;
WC()->cart->add_fee( $fee_label, $fee_amount );
}
}
add_filter( 'woocommerce_form_field' , 'remove_optional_txt_from_installment_checkbox', 10, 4 );
function remove_optional_txt_from_installment_checkbox( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'installment_fee' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works on Woocommerce version 3.6.5 with Storefront theme.