woocommerce custom checkout field to add fee to order ajax - php

I'm trying to ad a custom fee to the order total upon checkout.
I've added a checkbox within woocommerce
add_action( 'woocommerce_after_checkout_billing_form', 'add_box_option_to_checkout' );
function add_box_option_to_checkout( $checkout ) {
echo '<div id="message_fields">';
woocommerce_form_field( 'add_gift_box', array(
'type' => 'checkbox',
'class' => array('add_gift_box form-row-wide'),
'label' => __('Ilość pudełek ozdobnych - 25 PLN/szt'),
'placeholder' => __(''),
), $checkout->get_value( 'add_gift_box' ));
}
Included a custom js file which schould handle the event
jQuery( document ).ready(function( $ ) {
$('#add_gift_box').click(function(){
var data = {
action: 'woocommerce_add_gift_box',
state: '200',
};
jQuery.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: data,
success: function (code) {
console.log(code);
jQuery('body').trigger('update_checkout');
},
dataType: 'html'
});
});
});
And a php fee handling function
function woo_add_cart_fee( $data ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) || ! $_POST ) return;
$extracost = 0;
if (isset($_POST['state'])) {
$extracost = intval($_POST['state']);
}
WC()->cart->add_fee( 'Ozdobne pudełka:', $extracost );
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
add_action('wp_ajax_woocommerce_add_gift_box', 'woo_add_cart_fee', 10);
add_action('wp_ajax_nopriv_woocommerce_add_gift_box', 'woo_add_cart_fee', 10);
For some reasons the value of $_POST['state'] isn't added, the function works when I give a hard coded value, I've tried many option but cant get this to work.
I've seen similar posts but none of them had the answer.

The post data is sent by the AJAX functions in 'post_data', serialized. So to get the value of your checkbox, you only need to parse_str() this!
parse_str( $_POST['post_data'], $post_data );
then you can get your 'add_gift_box' option from $post_data['add_gift_box']. Note that upon order completion, this 'post_data' element is not available anymore and everything is in $_POST.
Complete example, based on your code:
1) adding the checkbox to the checkout
add_action( 'woocommerce_after_checkout_billing_form', 'add_box_option_to_checkout' );
function add_box_option_to_checkout( $checkout ) {
echo '<div id="message_fields">';
woocommerce_form_field( 'add_gift_box', array(
'type' => 'checkbox',
'class' => array('add_gift_box form-row-wide'),
'label' => __('Ilość pudełek ozdobnych - 25 PLN/szt'),
'placeholder' => __(''),
), $checkout->get_value( 'add_gift_box' ));
echo '</div>';
}
2) script to update cart when checkbox clicked (no need for extra AJAX requests!)
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
}
}
3) action to add the fee
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'])) {
$extracost = 25; // not sure why you used intval($_POST['state']) ?
WC()->cart->add_fee( 'Ozdobne pudełka:', $extracost );
}
}

This is awesome!! Thanks a lot. I've changed it a little bit to add a percentage instead. I know this is not a better answer but I have no reputation to push your answer up. For whoever was stuck like me..
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' ); function woo_add_cart_fee( $cart ){
global $woocommerce;
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'])) {
$percentage = 0.01;
$surcharge = ( $woocommerce->cart->cart_contents_total + $woocommerce->cart->shipping_total ) * $percentage;
$woocommerce->cart->add_fee( 'Surcharge', $surcharge, true, '' );
}
}

Related

Hide checkbox (with code) for other Nations

I need help with this code that i found on a blog:
// 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' => __('Consegna su appuntamento'),
'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( __( "Consegna su appuntamento" ), '×', $items_count );
$fee_amount = 4;
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;
}
I want to hide this checkbox in checkout page if the customer Nation is not Italy. Thank you!
I've added a checkbox in checkout page, and now i expect to hide this checkbox if the customer nation is not Italy (so this checkbox will be only visible for Italian customers

Coupon Code shouldn't get mixed up with the customized Discount

I have a Checkout page using Woocommerce where I have Discount added using the following code since I have a checkbox where user could check and the discount will apply. Here is the products page, please add any of them and proceed to Checkout page where you will get that Discount Checbox with label "Senior, Military, etc.". You can try entering "SAVE15" for the coupon code to apply.
// Add a custom checkbox fields after billing fields
function action_woocommerce_after_checkout_billing_form( $checkout ) {
// Add a custom checkbox field
echo '<h3 class="discount-type">' . __('DISCOUNT TYPE') . '</h3>';
woocommerce_form_field( 'discount30', array(
'type' => 'checkbox',
'label' => __( ' Senior, Military, Police, Firefighter, EMT Discount, Teacher',
'woocommerce' ),
'class' => array( 'form-row-wide' ),
), '' );
}
add_action( 'woocommerce_after_checkout_billing_form',
'action_woocommerce_after_checkout_billing_form', 10, 1 );
// Remove "(optional)" label on "discount30" field
function filter_woocommerce_form_field( $field, $key, $args, $value ) {
// Only on checkout page
if ( $key === 'discount30' && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) .
')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
add_filter( 'woocommerce_form_field' , 'filter_woocommerce_form_field', 10, 4 );
// jQuery - Ajax script
function action_wp_footer() {
// Only on Checkout
if ( is_checkout() && ! is_wc_endpoint_url() ) :
if ( WC()->session->__isset('enable_fee') )
WC()->session->__unset('enable_fee')
?>
<script type="text/javascript">
jQuery( function($){
if ( typeof wc_checkout_params === 'undefined' )
return false;
$( 'form.checkout' ).on( 'change', 'input[name=discount30]', function(e) {
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'enable_fee',
'enable_fee': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
add_action( 'wp_footer', 'action_wp_footer' );
// Get Ajax request and saving to WC session
function get_enable_fee() {
if ( isset($_POST['enable_fee']) ) {
WC()->session->set( 'enable_fee', ( $_POST['enable_fee'] ? true : false ) );
}
die();
}
add_action( 'wp_ajax_enable_fee', 'get_enable_fee' );
add_action( 'wp_ajax_nopriv_enable_fee', 'get_enable_fee' );
// Add a custom 3 Cents Discount
function action_woocommerce_cart_calculate_fees( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() )
return;
// Get number of items in the cart.
$items_in_cart = $cart->get_cart_contents_count();
// Calculate
$discount = 0.03 * $items_in_cart;
// Apply discount
if ( WC()->session->get('enable_fee') ) {
$cart->add_fee( __( 'Discount', 'woocommerce' ), -$discount );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1
);
Now, I'm using Coupon Code as well but don't want it to get mixed up so, how can I make a condition that if someone enter the Coupon Code, the discount that ABOVE code applies should be removed?

Select field that add / remove a custom fee in WooCommerce [duplicate]

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:

How to add custom plugin data to the cart in woocommerce using custom button on product page?

I am implementing the custom Buy Now button in my plugin. I had placed the Buy Now button on the product page using this hook
add_action( 'woocommerce_after_add_to_cart_button', 'myCustomBuyNowButton');
So, my next step is to add the product to the cart with quantity, variation details, which I am able to achieve by writing the following function i.e
(function ($) {
$(document).on('click', '.single_add_to_cart_button', function (e) {
e.preventDefault();
var $thisbutton = $(this),
$form = $thisbutton.closest('form.cart'),
id = $thisbutton.val(),
product_qty = $form.find('input[name=quantity]').val() || 1,
product_id = $form.find('input[name=product_id]').val() || id,
variation_id = $form.find('input[name=variation_id]').val() || 0;
var data = {
action: 'woocommerce_ajax_add_to_cart',
product_id: product_id,
product_sku: '',
quantity: product_qty,
variation_id: variation_id,
};
$(document.body).trigger('adding_to_cart', [$thisbutton, data]);
$.ajax({
type: 'post',
url: wc_add_to_cart_params.ajax_url,
data: data,
beforeSend: function (response) {
$thisbutton.removeClass('added').addClass('loading');
},
complete: function (response) {
$thisbutton.addClass('added').removeClass('loading');
},
success: function (response) {
if (response.error && response.product_url) {
window.location = response.product_url;
return;
} else {
$(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $thisbutton]);
}
},
});
return false;
});
})(jQuery);
& ajax is calling the following hook
add_action('wp_ajax_woocommerce_ajax_add_to_cart', 'woocommerce_ajax_add_to_cart');
add_action('wp_ajax_nopriv_woocommerce_ajax_add_to_cart', 'woocommerce_ajax_add_to_cart');
function woocommerce_ajax_add_to_cart() {
$product_id = apply_filters('woocommerce_add_to_cart_product_id', absint($_POST['product_id']));
$quantity = empty($_POST['quantity']) ? 1 : wc_stock_amount($_POST['quantity']);
$variation_id = absint($_POST['variation_id']);
$passed_validation = apply_filters('woocommerce_add_to_cart_validation', true, $product_id, $quantity);
$product_status = get_post_status($product_id);
if ($passed_validation && WC()->cart->add_to_cart($product_id, $quantity, $variation_id) && 'publish' === $product_status) {
do_action('woocommerce_ajax_added_to_cart', $product_id);
if ('yes' === get_option('woocommerce_cart_redirect_after_add')) {
wc_add_to_cart_message(array($product_id => $quantity), true);
}
WC_AJAX :: get_refreshed_fragments();
} else {
$data = array(
'error' => true,
'product_url' => apply_filters('woocommerce_cart_redirect_after_error', get_permalink($product_id), $product_id));
echo wp_send_json($data);
}
wp_die();
}
But I am stuck in adding the custom plugin data to the cart along with the quantity and variation details.
For ex: If the admin has installed a custom product fields plugin that helps them to add the custom fields on their product page to collect extra information. I need to add that information also to the cart.
Can anyone please help me to resolve this issue? Thanks in advance.
Use these hooks
// Add item data to the cart or define custom variable
add_filter( 'woocommerce_add_cart_item_data', 'add_cart_item_datax',10, 3 );
// Display item data to the cart or show custom variable
add_filter( 'woocommerce_get_item_data', 'get_cart_item_data', 10, 2 );
function add_cart_item_datax( $cart_item_data, $productId, $variationId ) {
if ( empty( $cart_item_data['basicpluginstr'] ) ) {
$cart_item_data['basicpluginstr'] = array();
}
$data[] = array(
'name' => 'Name',
'value' => 'valus',
'price' => 50
);
$cart_item_data['basicpluginstr'] = array_merge( $cart_item_data['basicpluginstr'], $data);
return $cart_item_data;
}
function get_cart_item_data( $data, $cartItem ) {
if ( isset( $cartItem['basicpluginstr'] ) ) {
foreach ( $cartItem['basicpluginstr'] as $basicpluginstr ) {
$name = 'PPPPPPP'; //$basicpluginstr['name'];
$value = '12364'; //$basicpluginstr['value'];
$price = '150'; //$basicpluginstr['price'];
}
$data[] = array(
'name' => $name,
'value' => $value,
'display' => 0
);
}
return $data;
}
//Add meta to order - WC 2.x or save the data when the order is made
add_action( 'woocommerce_add_order_item_meta', 'add_order_item_meta' , 10, 2 );
function add_order_item_meta( $item_id, $values ) {
if ( ! empty( $values['basicpluginstr'] ) ) {
foreach ( $values['basicpluginstr'] as $basicpluginstr ) {
$name = $basicpluginstr['name'];
$value = $basicpluginstr['value'];
woocommerce_add_order_item_meta( $item_id, $name, $value );
//woocommerce_add_order_item_meta( $item_id, 'basicpluginstr', 'basicpluginstr value' );
}
}
}
I have added a custom Field in admin and try to add itemdata in cart
<?php
/*
* Plugin Name: Custom Woo option
* Author: Gaurav Dev
* Text Domain: custom-woo-option
* Description: This is the Custom Woo option plugin
* Version: 1.0.0
*/
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
define( 'basicpluginstr_VERSION', '1.0.0' );
define( 'basicpluginstr_URI', plugin_dir_url( __FILE__ ) );
class basicpluginstr
{
//https://stackoverflow.com/questions/21650019/woocommerce-add-input-field-to-every-item-in-cart
function __construct()
{
// Product data tabs
add_filter( 'woocommerce_product_data_tabs', array( $this,'basicpluginstr_product_data_tabs') );
// Product data panels
add_action( 'woocommerce_product_data_panels', array( $this,'basicpluginstr_product_data_panels') );
// Add to cart
add_filter('woocommerce_add_cart_item', array($this, 'add_cart_item'), 999999999999999999, 1);
// Add item data to the cart or define custom variable
add_filter( 'woocommerce_add_cart_item_data', array($this,'add_cart_item_data'),10, 3 );
// Display item data to the cart or show custom variable
add_filter( 'woocommerce_get_item_data', array($this,'get_cart_item_data'), 10, 2 );
// Load cart data per page load
add_filter( 'woocommerce_get_cart_item_from_session', array( $this, 'get_cart_item_from_session' ), 999999999999999999, 2 );
//Add meta to order - WC 2.x or save the data when the order is made
add_action( 'woocommerce_add_order_item_meta', array($this,'add_order_item_meta') , 10, 2 );
//Save post
add_action( 'save_post', array($this,'custom_wp_bakery_save_post_fun'), 12, 1);
//Add Field on single Product Page
add_action( 'woocommerce_before_add_to_cart_button', array($this,'add_name_on_tshirt_field'));
}
/*
* Defined Product Data Tab
*/
function basicpluginstr_product_data_tabs( $tabs ) {
$tabs['basicpluginstr'] = array(
'label' => esc_html__( 'basicpluginstr', 'cus-price-cal' ),
'target' => 'basicpluginstr_settings',
'class' => array( 'show_if_basicpluginstr' ),
);
return $tabs;
}
/*
* Define Product Data Panel
*/
function basicpluginstr_product_data_panels() {
global $post;
$post_id = $post->ID;
$_core_price = get_post_meta( $post_id, '_core_price', true );
?>
<div id='basicpluginstr_settings' class='panel woocommerce_options_panel basicpluginstr_options_panel'>
<h1>Core Price</h1>
<input type="Text" name="_core_price" id="_core_price" value="<?php echo $_core_price;?>">
</div>
<?php
}
function add_cart_item($cart_item) {
if ( isset( $cart_item['basicpluginstr'] ) ) {
foreach ( $cart_item['basicpluginstr'] as $basicpluginstr ) {
$_core_price = $basicpluginstr['_core_price'];
}
$cart_item['data']->set_price($_core_price);
//$cart_item['data']->adjust_price( $extra_cost );
}
return $cart_item;
}
function add_cart_item_data( $cart_item_data, $productId, $variationId ) {
if ( empty( $cart_item_data['basicpluginstr'] ) ) {
$cart_item_data['basicpluginstr'] = array();
}
$data[] = array(
'name' => 'Core Price',
'value' => '10',
'_core_price' => 10
);
$cart_item_data['basicpluginstr'] = array_merge( $cart_item_data['basicpluginstr'], $data);
return $cart_item_data;
}
function get_cart_item_data( $data, $cartItem ) {
if ( isset( $cartItem['basicpluginstr'] ) ) {
foreach ( $cartItem['basicpluginstr'] as $basicpluginstr ) {
$name = $basicpluginstr['name'];
$value = $basicpluginstr['value'];
}
$data[] = array(
'name' => $name,
'value' => $value,
'display' => 0
);
}
return $data;
}
function get_cart_item_from_session($cart_item, $values) {
if ( ! empty( $values['basicpluginstr'] ) ) {
$cart_item['basicpluginstr'] = $values['basicpluginstr'];
$cart_item = $this->add_cart_item( $cart_item );
}
return $cart_item;
}
function add_order_item_meta( $item_id, $values ) {
if ( ! empty( $values['basicpluginstr'] ) ) {
foreach ( $values['basicpluginstr'] as $basicpluginstr ) {
$name = $basicpluginstr['name'];
$value = $basicpluginstr['value'];
woocommerce_add_order_item_meta( $item_id, $name, $value );
//woocommerce_add_order_item_meta( $item_id, 'basicpluginstr', 'basicpluginstr value' );
}
}
}
function custom_wp_bakery_save_post_fun($post_id){
if (isset($_POST['_core_price'])) {
update_post_meta($post_id, '_core_price', $_POST['_core_price']);
}
}
function add_name_on_tshirt_field() {
$_core_price = get_post_meta( get_the_ID(), '_core_price', true );
if (!empty($_core_price)) {
echo '<table class="variations" cellspacing="0">
<tbody>
<tr>
<td class="label"><label for="color">Core Price</label></td>
<td class="value">
<input type="text" name="_core_price" value="'.$_core_price.'" />
</td>
</tr>
</tbody>
</table>';
}
}
}
new basicpluginstr();
}
Please try the example in your working environment and modify it accordingly

Add checkout custom fields data to shipping packages for calculations in WooCommerce

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') );

Categories