How to access WooCommerce custom billing field in hooks - php

I'm writing a custom WordPress function that will change the flat_rate shipping when a customer changes the "State" field from a select menu. Currently I'm doing it in my theme's functions.php
I have created a custom field to represent "State" field as a drop down menu in the billing fields. I used "WooCommerce Checkout Manager" plugin to setup the custom field and disabled the default "State" field.
Now I want to change the shipping cost depending on the value of my custom "State" field. I'm unable to retrieve the data of the field. Also I want to know what hook I can use to change the flat rate shipping once this field's value is changed.
I've used this filter hook (woocommerce_package_rates) and it doesn't work.
Here is my code to do it which I got it from another tutorial then made my customization
function wc_ninja_change_flat_rates_cost( $rates, $package ) {
$destination = $package['destination'];
$city = $destination['myfield12']; // getting the city field value
// Make sure flat rate is available
if ( isset( $rates['flat_rate'] ) ) {
if ( $city == 'Alex' || $city == 'الإسكندرية' ) {
// Set flat rate to cost $10 more
$rates['flat_rate']->cost = 30;
}
else {
$rates['flat_rate']->cost = 20;
}
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'wc_ninja_change_flat_rates_cost', 10, 2 );

I found this:
How to update shipping cost in cart dynamically (ajax) based on a custom field in WooCommerce
Basically it captures the field data through JS and send an Ajax request to the server which then stores the value in the session. Then adds an additional fee. It is not exactly what I was seeking to do but its a functional workaround.

Related

Make Billing Phone required on Checkout Field Based on Shipping Method - Woocommerce

I want to set the billing phone number required or not required based on the shipping method.
I have set the shipping method as an array and checked it from the session selected shipping method but it not working
add_filter('woocommerce_checkout_fields', 'fire_remove_billing_checkout_fields');
function fire_remove_billing_checkout_fields($fields) {
global $woocommerce;
$methods = array('flat_rate:2', 'flat_rate:3', 'flat_rate:17', 'flat_rate:20');// Set shipping method to hide the checkout field(s).
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = $chosen_methods[0];
if(in_array($chosen_shipping, $methods)){
$fields['billing']['billing_phone'][ 'required' ] = true;
}else{
$fields['billing']['billing_phone'][ 'required' ] = false;
}
return $fields;
}
Your code works well for me. I've added my shipping rate IDs and it works as expected, however refresh of the page is necessary, because WooCommerce doesn't refresh the billing fields natively on update_checkout trigger.
You should either reload the page using Javascript/jQuery on updated_checkout event, or reload only the billing fields using AJAX like so:
add_action( 'wp_footer', 'reload_billing_fields_on_updated_checkout' );
function reload_billing_fields_on_updated_checkout() {
?>
<script>
jQuery(document.body).on('updated_checkout', () => {
jQuery('.woocommerce-billing-fields').load(`${location.href} .woocommerce-billing-fields>*`, '');
});
</script>
<?php
}
Keep in mind that it might take a short while for those fields to reload, so you might want to add some loading CSS classes, or maybe a spinner.

How to safely pass value from WP Forms to PHP code?

I'm using Wordpress forms (gravity forms plugin) and I'm trying to pass price value to payment platform. I'm using just a hook with code that after form submission passes value to URL and redirects to payment page:
add_action('gform_after_submission', 'link_to_payment', 10, 2);
function link_to_payment($entry, $form) {
$price = $entry['6.2'];
header("Location: http://www.******.***/test.php?price='.$price");
exit();
}
Obviously problem with this is just that any person with webtools can change the value of $entry['6.2'] in html code and get a different price to pay. My question is, is there a safe way to pass value from HTML page to PHP code that user couldn't change in HTML code?
As these are the price of products which is set from the backend, you don't need to get the price from the frontend.
Create a new hidden field which has ID of the product. Let's say the name of field is 6.3.
add_action('gform_after_submission', 'bks_link_to_payment', 10, 2);
function bks_link_to_payment($entry, $form) {
$product_id = $entry['6.3']; // Make sure you change the field to the one you create.
$product = wc_get_product( $product_id ); // get product object from the backend.
// If the product exists.
if ( $product ) {
$price = $product->get_price(); // This would give you the price of the product.
header("Location: http://www.******.***/test.php?price='.$price");
exit();
}
}
So, in case someone changes the id of the product using webtools you are making sure that the product exists and the price is fetched from the database so it can't be altered.

How to change Woocommerce shipping labels in cart, checkout and also on orders

I'm trying to change the shipping label based on whether any of the products in cart has an addon.
For that purpose, I am using How can I modify a Woocommerce shipping label answer code, with some changes to suit my needs.
The HTML:
<input type="hidden" name="shipping_method[0]" data-index="0" id="shipping_method_0_flat_rate5" value="flat_rate:5" class="shipping_method">
<label class="shipping__list_label" for="shipping_method_0_flat_rate5">Standard Shipping (2-3 days): <span class="woocommerce-Price-amount amount"><bdi>3,95<span class="woocommerce-Price-currencySymbol">€</span></bdi></span></label>
So the label Standard Shipping (2-3 days) must display Shipping with customization (4-6 days) if a certain condition is met (in this case: the field custom_text is not empty).
The functions.php:
//Change Standard Shipping Label if product is customized
add_filter( 'woocommerce_cart_shipping_method_full_label', 'change_shipping_label', 10, 2 );
function change_shipping_label( $full_label, $method ){
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( !empty( $cart_item['custom_text'] ) ) {
$full_label = str_replace( "Standard Shipping (2-3 days)", "Shipping with customization (4-6 days)", $full_label );
}
}
return $full_label;
}
This was a success. If the condition is met the label changes to Shipping with customization (4-6 days) prior checkout.
However, the label change does not apply after checkout (thank you page and emails, it displays the original "Standard Shipping (2-3 days)".
Can I display this label change also on thank you page and emails?
Update 2
Based on the provided code and informations, to change specific shipping label on orders, using shipping rate Id to target the desired shipping method:
add_action( 'woocommerce_checkout_create_order_shipping_item', 'action_wc_checkout_create_order_shipping_item', 10, 4 );
function action_wc_checkout_create_order_shipping_item( $item, $package_key, $package, $order ) {
// Targeting "flat_rate:5" by its instance ID
if( $item->get_instance_id() == 5 ) {
$item->set_method_title( "Shipping with customization (4-6 days)" );
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Related: Change specific shipping method title on WooCommerce orders after checkout

Customization on WooCommerce variable product with custom fields

We have created a site using WooCommerce and WordPress with predefined products.
However, Product A must have variations, to resolve this, we added custom fields such as Colors, Dimensions, etc...
Now once the end-users are navigating to the product, we are able to fetch the custom field values. We also modified the UI so that users can pick and choose from these custom fields. (We have a preview of the modifications done via JS/CSS), so for instance, if they choose a green color we use JS to add a layer of green so that the preview is real time.
Now, we have one challenge.
-> What is the best way to go about adding this product PLUS all modifications done to the cart?
So for instance Product A was modified (on the front-end) using data pulled from the custom fields to include Color: Green and Size: 100x100 instead of defaults values. How do we store this and pass the customized product to the cart?
Appreciate the help!. Glad to add more details if something is not clear.
(There are plugins out there that can provide this functionality; Things similar to WooCommerce Product Add-On, etc... However, we have to custom develop the feature.)
It requires some steps.
1). For your product page:
First you might need to add hidden fields to the add to cart form for each custom field like (example):
add_action( 'woocommerce_before_add_to_cart_button', 'add_hidden_empty_input_fields' );
function add_hidden_empty_input_fields() {
?>
<input type="hidden" name="hidden_color" id="hidden_color" value="">
<input type="hidden" name="hidden_dimensions" id="hidden_dimensions" value="">
<?php
}
Then you will have to make some changes to your Javascript code to set the custom fields chosen values in those hidden fields.
2). Pass the custom fields selected values as custom cart item data (example):
add_filter('woocommerce_add_cart_item_data', 'add_custom_field_data', 10, 3 );
function add_custom_field_data( $cart_item_data, $product_id, $variation_id ) {
if ( isset($_POST['hidden_color']) && ! empty($_POST['hidden_color']) ) {
$cart_item_data['color'] = esc_attr($_POST['hidden_color']);
}
if ( isset($_POST['hidden_dimensions']) && ! empty($_POST['hidden_dimensions']) ) {
$cart_item_data['dimensions'] = esc_attr($_POST['hidden_dimensions']);
}
return $cart_item_data;
}
And optionally display values on cart items (example):
add_filter( 'woocommerce_get_item_data', 'display_custom_cart_item_data', 10, 2 );
function display_custom_cart_item_data( $cart_data, $cart_item ) {
if ( isset($cart_item['color']) ) {
$cart_data[] = array( "name" => __("Color"), "value" => $cart_item['color'] );
}
if ( isset($cart_item['dimensions']) ) {
$cart_data[] = array( "name" => __("Dimensions"), "value" => $cart_item['dimensions'] );
}
return $cart_data;
}
3). Save the custom cart item data as custom order item meta data (example):
add_action( 'woocommerce_checkout_create_order_line_item', 'save_custom_order_item_meta_data' , 10, 4 );
function save_custom_order_item_meta_data( $item, $cart_item_key, $values, $order ) {
if ( isset($values['color']) ) {
$item->add_meta_data( __("Color"), $values['color'] );
}
if ( isset($values['dimensions']) ) {
$item->add_meta_data( __("Dimensions"), $values['dimensions'] );
}
}
Note: The data is going to be displayed on everywhere on orders and email notifications.
Code goes in functions.php file of the active child theme (or active theme). It should work.
The variations have a post_id, you would just use the variation post_id instead of the main product one.

Add Custom attributes from a variable product to cart in WooCommerce

I am trying to redirect my custom shop page to cart page after user select custom attributes (liability and hours) and then clicks the purchase button.
I have written custom JS code which retrieves the variation_id and attributes value and append it to the URL so that it automatically gets added to cart and get's redirected to cart page.
href="yourdomain.com/?add-to-cart=47&variation_id=88&quantity=3&attribute_pa_colour=blue&attribute_pa_size=m"
This is the URL format which I have found in a blog: (https://businessbloomer.com/woocommerce-custom-add-cart-urls-ultimate-guide/) and I made my link in this format.
My link is:
localhost/wordpress/cart/?add-to-cart=1185&variation_id=1641&quantity=1&attribute_pa_liability=2_million&attribute_pa_hours=500_hours
Where liability and hours is my custom attribute which has values as 1 million, 2 million and 500 hours, 750 hours respectively.
But when it get's redirected to cart page woocommerce give me an error and shows it's alert box which shows the error message as "liability and hours are required fields".
I think woocommerce is unable to get the attribute values through my URL.
Can anyone explain why is this happening and what is the error if there is any?
Updated
This "Business Bloomer" guide is a little outdated… You need 2 things:
1). The correct URL
You don't need to addto cart the product and the variation Id with all related attributes. You just need to add to cart the variation ID + your custom attributes like this: localhost/wordpress/cart/?add-to-cart=1641&quantity=1&pa_liability=2_million&pa_hours=500_hours
2). Registering (and display) your custom attributes:
// Store the custom data to cart object
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_product_data', 10, 2 );
function save_custom_product_data( $cart_item_data, $product_id ) {
$bool = false;
$data = array();
if( isset( $_REQUEST['pa_liability'] ) ) {
$cart_item_data['custom_data']['pa_liability'] = $_REQUEST['pa_liability'];
$data['pa_liability'] = $_REQUEST['pa_liability'];
$bool = true;
}
if( isset( $_REQUEST['pa_hours'] ) ) {
$cart_item_data['custom_data']['pa_hours'] = $_REQUEST['pa_hours'];
$data['pa_hours'] = $_REQUEST['pa_hours'];
$bool = true;
}
if( $bool ) {
// below statement make sure every add to cart action as unique line item
$cart_item_data['custom_data']['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'custom_variations', $data );
}
return $cart_item_data;
}
// Displaying the custom attributes in cart and checkout items
add_filter( 'woocommerce_get_item_data', 'customizing_cart_item_data', 10, 2 );
function customizing_cart_item_data( $cart_data, $cart_item ) {
$custom_items = array();
if( ! empty( $cart_data ) ) $custom_items = $cart_data;
// Get the data (custom attributes) and set them
if( ! empty( $cart_item['custom_data']['pa_liability'] ) )
$custom_items[] = array(
'name' => 'pa_liability',
'value' => $cart_item['custom_data']['pa_liability'],
);
if( ! empty( $cart_item['custom_data']['pa_hours'] ) )
$custom_items[] = array(
'name' => 'pa_hours',
'value' => $cart_item['custom_data']['pa_hours'],
);
return $custom_items;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works
You will need to add this data to the order items too
First uncheck the ajax add to cart option from admin panel
Then you need to make variation with your attributes then find out product id, quantity, attribute slug and attribute name(used to show in cart) and variation id and then make your cart url like given below.
The add to cart link with attribute is : https://www.your-domain.com/?add-to-cart=(product id)&quantity=(numeric quantity)&attribute_pa_(attribute slug)=(attribute name)&variation_id=(variation id)
For more details you can visit http://www.codemystery.com/wordpress-woocommerce-add-cart-link-variations/
The other answers are correct in regards to the add to cart url format (should be: /add-to-cart=product_id&my_custom_attr=whatever&my_custom_attr2=somthing)
Then there is a very good plugin to handle this type of functionality for storing the custom product attributes called WC Fields Factory.
And the writer of the plugin also has a great article on how to do this w/o need of a plugin. As well as an answer on a similar question here.

Categories