WooCommerce Shipping Plugin - Checkout Shipping Cost Not Updating(AJAX) - wordpress

I've searched to find any solution but nothing worked.
Here what I want to do:
Add new field in checkout page called Shipping show as selectbox filled with Preorder and Non-preorder
If preorder then would show Location field show as selectbox
If non-preorder then would show Location field same as step 2 but different list option.
When Shipping and Location filled correctly, shipping cost would show with correct shipping cost.
Problem
When I filled all required field and Shipping, Location shipping cost wound calculate again. It do AJAX request, but shipping cost keep the same.
But, when I change Name or Street Address shipping cost updated correctly, which is bad behavior. When user click Place Order immediately would POST wrong shipping cost.
Here my Youtube Video to make clear what I ask for help.
What I did to create my own plugin:
Create custom field using hook something like this
public function woocommerce_checkout_fields( $fields )
{
// var_dump(have_rows('location', 'option'));
// die('test');
$options = [];
$options[''] = 'Select Shipping';
$options['pre-order'] = 'Pre Order';
if (!$this->hasPreorderItem()) {
$options['non-pre-order'] = 'Non Pre Order';
}
// Add custom billing shipping
$fields['billing']['billing_shipping'] = array (
'type' => 'select',
'label' => 'Shipping',
'placeholder' => 'Select shipping',
'class' => array ('address-field', 'update_totals_on_change' ),
'required' => true,
'options' => $options
// 'options' => $this->getLocations()
);
$fields['billing']['billing_location_pre_order'] = array (
'type' => 'select',
'label' => 'Location(Pre Order)',
'placeholder' => 'Select Preorder Location',
'class' => array ('address-field', 'update_totals_on_change' ),
'required' => false,
'options' => $this->preorderLocations->getLocations()
// 'options' => $this->getLocations()
);
// Add custom billing location
$fields['billing']['billing_location'] = array (
'type' => 'select',
'label' => 'Location',
'placeholder' => 'Select location',
'class' => array ('address-field', 'update_totals_on_change' ),
'required' => false,
'options' => $this->locations->getLocations()
// 'options' => $this->getLocations()
);
return $fields;
}
Create class to help calculate cost based on Shipping and Location.
What I have tried
Using this answer but no luck. Click here for the question.
Tried to make field to required, as I saw someone said it only update when all required fields filled.
Tried to disable cache in wp-config.php

I found solution from this link
I might help someone that has similar problem. You just need to clear the session. So, WooCommerce would re-calculate and recall your calculate_shipping() function.
To do that add woocommerce_checkout_update_order_review hook. It would look something like this
add_action('woocommerce_checkout_update_order_review', 'action_woocommerce_checkout_update_order_review', 10, 1);
function action_woocommerce_checkout_update_order_review( $posted_data )
{
global $woocommerce;
$packages = $woocommerce->cart->get_shipping_packages();
foreach( $packages as $package_key => $package ) {
$session_key = 'shipping_for_package_'.$package_key;
$stored_rates = WC()->session->__unset( $session_key );
}
}

Related

How to add or link purchased product to customer

I am doing migration from very old custom made ecommerce site that is working as subscription model. I have 3 different products that contains custom data to is available to customers that have purchased to product.
So i am importing customers by their email address and i need to add products to their purchase / order history so the can get their hands on into custom data.
So how to link a product to customer?
I'm not so sure about those custom fields but it seem like what to need is to create orders programmatically, where you "link" existing users and existing products.
Luckily, WooCommerce allow us to do that :)
take a look at this code:
function create_order() {
// Create product
$product = WC_Helper_Product::create_simple_product();
WC_Helper_Shipping::create_simple_flat_rate();
$order_data = array('status' => 'pending', 'customer_id' => 1, 'customer_note' => '', 'total' => '');
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
// Required, else wc_create_order throws an exception
$order = wc_create_order($order_data);
// Add order products
$item_id = $order->add_product($product, 4);
// Set billing address
$billing_address = array('country' => 'US', 'first_name' => 'Jeroen', 'last_name' => 'Sormani', 'company' => 'WooCompany', 'address_1' => 'WooAddress', 'address_2' => '', 'postcode' => '123456', 'city' => 'WooCity', 'state' => 'NY', 'email' => 'admin#example.org', 'phone' => '555-32123');
$order->set_address($billing_address, 'billing');
// Add shipping costs
$shipping_taxes = WC_Tax::calc_shipping_tax('10', WC_Tax::get_shipping_tax_rates());
$order->add_shipping(new WC_Shipping_Rate('flat_rate_shipping', 'Flat rate shipping', '10', $shipping_taxes, 'flat_rate'));
// Set payment gateway
$payment_gateways = WC()->payment_gateways->payment_gateways();
$order->set_payment_method($payment_gateways['bacs']);
// Set totals
$order->set_total(10, 'shipping');
$order->set_total(0, 'cart_discount');
$order->set_total(0, 'cart_discount_tax');
$order->set_total(0, 'tax');
$order->set_total(0, 'shipping_tax');
$order->set_total(40, 'total');
// 4 x $10 simple helper product
return wc_get_order($order->id);
}
at the 5th line, you set the customer ID
and, at the 12th line, you assign the product to the order.
caveat: I'm not sure how much of this snippet is required by wc_create_order(), as the official documentation is very poor.
I'd try to run this function as clean as possible, just using the minimum information (or the information that you have available).
Something like this:
function create_order() {
// Create product
$product = WC_Helper_Product::create_simple_product();
$order_data = array('status' => 'pending', 'customer_id' => 1, 'customer_note' => '', 'total' => '');
// Required, else wc_create_order throws an exception
$order = wc_create_order($order_data);
// Add order products
$item_id = $order->add_product($product, 4);
// Set totals
//$order->set_total(40, 'total');
return wc_get_order($order->id);
}
good luck!

Why does my value (from custom fields) get override by old value (from said fields)?

I'm trying to have the value from 2 custom fields that the user put in through My Account/Edit-Address shown in the same custom fields but in checkout, right now it gets override by old (input) values even though the field (seen through browser inspector) has the new value. How do I stop this?
I'm fairly new to both woocommerce, plugin-making and wordpress. Right now I've not really tried much that made any difference (put the code in different order, changed up the priorities, changed names... As you see, I don't really know what I'm doing).
This is how I made the fields:
add_filter( 'woocommerce_checkout_fields' , 'plugin_add_custom_billing_fields' );
function plugin_add_custom_billing_fields($fields) {
$fields['billing']['billing_org_number'] = array(
'label' => __('Organisationsnummer', 'woocommerce'),
'placeholder' => __('T.ex. 1234-5678', 'woocommerce'),
'required' => true,
'class' => array('form-row-wide'),
'clear' => true,
);
$fields['billing']['billing_org_reference'] = array(
'label' => __('Kostnadsställe/referens', 'woocommerce'),
'placeholder' => __('T.ex. Per Olofsson', 'woocommerce'),
'required' => true,
'class' => array('form-row-wide'),
'clear' => true,
);
return $fields;
}
This is how I save the fields:
function reigel_woocommerce_checkout_update_user_meta( $customer_id, $posted ) {
var_dump($customer_id, $posted);
if (isset($posted['billing_org_number'])) {
$dob = sanitize_text_field( $posted['billing_org_number'] );
update_user_meta( $customer_id, 'billing_org_number', $dob);
}
if (isset($posted['billing_org_reference'])) {
$dob = sanitize_text_field( $posted['billing_org_reference'] );
update_user_meta( $customer_id, 'billing_org_reference', $dob);
}
}
add_action( 'woocommerce_update_user_meta', 'reigel_woocommerce_checkout_update_user_meta', 10, 2 );
As you see, I've been searching through StackOverflow before and got some help from Reigel! Tell me if you need any more code.
The results I want: My value (from database) to be shown in Checkout after edited in My Account/Edit-Address.
Actual results: The old value is shown in Checkout, the new in My Account/Edit-Address.
EDIT: Seems like the plugin for Klarna Checkout is messing up with sessions.
EDIT 2: Yes, it was Klarna. I'll push this problem for a later time because the team discussed and opted to remove the plugin instead.

Woocommerce checkout only refresh on postcode

I am trying to make checkout faster and my shipping is only based on the postcode so I do not want 'order review' to refresh when address, country, state is change.
I know I need to fiddle with: woocommerce/includes/class-wc-ajax.php
Specifically: update_order_review();
Is there a way to do this by adding code to my themes functions.php rather than comment out core code?
I don't think so that there is a legal way of doing it. But there is a work around to it. You can remove woocommerce default fields from your checkout form and add your custom fields. - This way it will not trigger ajax on its update.
You can add/remove custom fields on checkout this way:
add_filter( 'woocommerce_checkout_fields' , 'vid_remove_billing_postcode_checkout' );
function vid_remove_billing_postcode_checkout( $fields ) {
unset($fields['billing']['billing_postcode']);
$fields['shipping']['shipping_phone'] = array(
'label' => __('Phone', 'woocommerce'),
'placeholder' => _x('Phone', 'placeholder', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide'),
'clear' => true
);
return $fields;
}

Filter shipping method based on custom checkout field at checkout page

I am using Woocommerce WordPress plugin
Added one custom field at checkout page, called - Address Type which is drop down contains 2 values. Business/Commercial and Residential
I have total 3 shipping methods - International Flat Rate, Flat Rate, Free Shipping
Now, condition that I want when end user select residential then and then they will get all 3 shipping methods but once user select a business option then hide/remove International Flat Rate and Flat Rate shipping methods (I mean show only Free Shipping).
add_filter( 'woocommerce_checkout_fields' , 'add_address_type_field' );
function add_address_type_field( $fields ) {
$address_type_field = array(
'type' => 'select',
'label' => __('Address Type', 'woocommerce'),
'required' => false,
'class' => array('address-field', 'form-row-wide', 'validate-addresstype'),
'clear' => true,
'options' => array(
'residential' => 'Residential',
'business' => 'Business/Commercial'
),
);
$fields['billing']['billing_address_type'] = $address_type_field;
$fields['shipping']['shipping_address_type'] = $address_type_field;
return $fields;
}
add_filter('woocommerce_package_rates', 'display_shipping_method_based_on_state', 10, 2);
if(!function_exists('display_shipping_method_based_on_state')) {
function display_shipping_method_based_on_state($rates) {
global $woocommerce;
$state = WC()->customer->shipping_state;
$address_type = WC()->customer->shipping_address_type;
$free_shipping = $rates['free_shipping'];
if($address_type == 'business')
{
$rates = array();
$rates['free_shipping'] = $free_shipping;
}
return $rates;
}
}
This is my code that I am trying. Let me know where I am wrong?
Thanks in advance!

Why is the invoice page different for another user?

When I go to admin/store/orders/50457/invoice as the administrator, I see the following:
Notice how it has a payment method of "Free order" and the total at the bottom is $0.00.
When I go to the same page as a non-administrator, I see the following:
Notice how Payment Method is empty and the total for the order is $8.21.
The correct one is what the administrator sees, so what is going on that makes the two behave differently?
EDIT: It turns out in a module I created (a long time ago) called tf_store_credit.module, I have the following:
function tf_store_credit_line_item(){
global $user;
$total_credit= uc_store_credit_f_get_user_credit($user->uid);
if ($total_credit>0){
$items[] = array
(
'id' => 'store-credit', // You will use this ID in the javascript
'title' => t('Store Credit'), // This is the text that will be displayed on the line item in the subtotal
'callback' => 'tf_store_credit_line_item_callback', // This is the callback function
'stored' => TRUE,
'default' => FALSE,
'calculated' => TRUE,
'display_only' => FALSE,
'weight' => 15,
);
}
return $items;
}
The problem is that it is getting the currently logged in user's store credit instead of the user who placed the order. So how would I go about getting the correct user?
In tf_store_credit.module, I modified it like this:
function tf_store_credit_line_item(){
global $user;
$total_credit= uc_store_credit_f_get_user_credit($user->uid);
if ($total_credit>0 || in_array("view_orders", $user->roles)){
$items[] = array
(
'id' => 'store-credit', // You will use this ID in the javascript
'title' => t('Store Credit'), // This is the text that will be displayed on the line item in the subtotal
'callback' => 'tf_store_credit_line_item_callback', // This is the callback function
'stored' => TRUE,
'default' => FALSE,
'calculated' => TRUE,
'display_only' => FALSE,
'weight' => 15,
);
}
return $items;
}
In uc_free_order.module, I did a similar thing so that "Payment method" showed up:
function uc_free_order_payment_method() {
global $user;
if ($user->name=='blah' || $user->name=='blah2' || in_array("view_orders", $user->roles)){
$methods[] = array(
'id' => 'free_order',
'name' => t('Free order'),
'title' => t('Free order - payment not necessary.'),
'desc' => t('Allow customers with $0 order totals to checkout without paying.'),
'callback' => 'uc_payment_method_free_order',
'checkout' => TRUE,
'no_gateway' => TRUE,
'weight' => 10,
);
return $methods;
}
}

Resources