Change product price dynamically in WooCommerce - php

I'm trying to change the WooCommerce price dynamically on WooCommerce, already tried various solution posted here, but no one worked for my case.
Here's an example, I have an ajax function that calls the receive_order_ajax_request function, add the products into the cart, and after I call the update_vehicle_price to update the product's price. But all products remains with the same price. Can someone give me a help?
class WhollOrder {
public function __construct() {
add_action( 'wp_ajax_nopriv_receive_order_ajax_request', array( $this, 'receive_order_ajax_request' ) );
add_action( 'wp_ajax_receive_order_ajax_request', array( $this, 'receive_order_ajax_request' ) );
}
public function receive_order_ajax_request() {
global $woocommerce;
$booking_details = $_POST['booking_details'];
if ( isset( $booking_details ) && ! empty( $booking_details ) ) {
foreach ( $booking_details['vehicles'] as $vehicle ) {
$woocommerce->cart->add_to_cart( $vehicle['product_id'], (int) $vehicle['product_qty'] );
}
$this->update_vehicle_price( $booking_details['vehicles'] );
} else {
wp_send_json_error(
array(
'message' => 'Preencha todos os campos'
)
);
}
wp_die();
}
private function update_vehicle_price( $vehicles ) {
global $woocommerce;
foreach ( WC()->cart->get_cart() as $key => $cart_item ) {
foreach ( $vehicles as $vehicle ) {
if ( $vehicle['product_id'] == $cart_item['product_id'] ) {
WC()->cart->get_cart()[$key]['data']->set_price( 1000.00 );
}
}
}
}
}
new WhollOrder();
This is not a duplicate because the way I coded is not possible to use the others question's answers.

Yea dude, I've been here. The price is reloaded after you go to the checkout page.
You need to set it using this hook : woocommerce_checkout_create_order_line_item.
Change cart item prices in WooCommerce version 3.0

Related

How to hide checkout date picker when WooCommerce cart contains a virtual product?

I need to deactivate a checkout date picker generated by a plugin when a product on cart is virtual.
Here's the hook they gave for that:
apply_filters('woocommerce_delivery_disabled_dates', $disableDates);
Based on that information, this is my code attempt:
add_filter( 'woocommerce_checkout_fields' , 'disable_dates' );
function disable_dates( $fields ) {
$only_virtual = true;
foreach( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// Check if there are non-virtual products
if ( ! $cart_item['data']->is_virtual() ) $only_virtual = false;
}
if( $only_virtual ) {
apply_filters(‘woocommerce_delivery_disabled_dates’, $disableDates);
}
return $fields;
}
However this does not give the desired result, any advice how to hide the checkout date picker when the cart contains a virtual product?
The main issues is that $disabledDates is undefined - I would however change $fields to $disableDates as it makes a bit more sense. See below:
apply_filters('woocommerce_delivery_disabled_dates', $disableDates);
add_filter( 'woocommerce_checkout_fields' , 'disable_dates' );
function disable_dates( $disableDates ) {
$only_virtual = true;
foreach( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// Check if there are non-virtual products
if ( ! $cart_item['data']->is_virtual() ) $only_virtual = false;
}
if( $only_virtual ) {
apply_filters('woocommerce_delivery_disabled_dates', $disableDates);
}
return $disableDates;
}
The $disableDates variable is the input argument for your callback of the hook which you named $fields ( I think )
Ps. this is just a guess based on the code you posted. There is quite a bit that is not clear to me, but $disableDates in your original code clearly should have a value.
No need to use the woocommerce_checkout_fields hook,
the logic can be applied in the appropriate hook.
So you get:
function filter_woocommerce_delivery_disabled_dates( $disableDates ) {
// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Loop through cart items
foreach ( WC()->cart->get_cart_contents() as $cart_item_key => $cart_item ) {
// Check if there are virtual products
if ( $cart_item['data']->is_virtual() ) {
$disableDates = true;
break;
}
}
}
return $disableDates;
}
add_filter( 'woocommerce_delivery_disabled_dates', 'filter_woocommerce_delivery_disabled_dates', 10, 1 );

Allow guest checkout for specific products only in WooCommerce

The following code add a custom field to admin product settings to manage guest checkout at product level:
// Display Guest Checkout Field
add_action( 'woocommerce_product_options_general_product_data', 'woo_add_custom_general_fields' );
function woo_add_custom_general_fields() {
global $woocommerce, $post;
echo '<div class="options_group">';
// Checkbox
woocommerce_wp_checkbox( array(
'id' => '_allow_guest_checkout',
'wrapper_class' => 'show_if_simple',
'label' => __('Checkout', 'woocommerce' ),
'description' => __('Allow Guest Checkout', 'woocommerce' )
) );
echo '</div>';
}
// Save Guest Checkout Field
add_action( 'woocommerce_process_product_meta', 'woo_add_custom_general_fields_save' );
function woo_add_custom_general_fields_save( $post_id ){
$woocommerce_checkbox = isset( $_POST['_allow_guest_checkout'] ) ? 'yes' : 'no';
update_post_meta( $post_id, '_allow_guest_checkout', $woocommerce_checkbox );
}
// Enable Guest Checkout on Certain products
add_filter( 'pre_option_woocommerce_enable_guest_checkout', 'enable_guest_checkout_based_on_product' );
function enable_guest_checkout_based_on_product( $value ) {
if ( WC()->cart ) {
$cart = WC()->cart->get_cart();
foreach ( $cart as $item ) {
if ( get_post_meta( $item['product_id'], '_allow_guest_checkout', true ) == 'yes' ) {
$value = "yes";
} else {
$value = "no";
break;
}
}
}
return $value;
}
But it doesn't work actually. What I am doing wrong? How can I fix it?
I am trying to allow guest purchases for specific products. The admin custom field display and save custom field value is working (the 2 first functions), But login/register never comes up on checkout page, even if there are products in cart that doesn't allow guest checkout.
The filter hook enable_guest_checkout_based_on_product doesn't exist anymore and has been replaced by another hook a bit different.
So your code is going to be:
add_filter( 'woocommerce_checkout_registration_required', 'change_tax_class_user_role', 900 );
function change_tax_class_user_role( $registration_required ) {
if ( ! WC()->cart->is_empty() ) {
$registration_required = false; // Initializing (allowing guest checkout by default)
// Loop through cart items
foreach ( WC()->cart->get_cart() as $item ) {
// Check if there is any item in cart that has not the option "Guest checkout allowed"
if ( get_post_meta( $item['product_id'], '_allow_guest_checkout', true ) !== 'yes' ) {
return true; // Found: Force checkout user registration and exit
}
}
}
return $registration_required;
}
Code goes in functions.php file of your active child theme (or active theme). It should works.
Related continuation: Redirection for non checkout guest allowed in WooCommerce

Set cart item custom prices from session data in WooCommerce 3

I Made a custom form option on site to update price and send that data through ajax and try to get in filter woocommerce_before_calculate_totals Session.
Here is code
add_action( 'woocommerce_before_calculate_totals', 'calculate_total_price', 99 );
function calculate_total_price( $cart_object )
{
global $woocommerce;
session_start();
$tac_dd_discounted_price = $_SESSION['wdm_user_price_data'];
$target_product_id = $_SESSION['wdm_user_product_id_data'].'<br/>.';
$_SESSION['productlist'][] =
[
'price' => $tac_dd_discounted_price,
'productid' => $target_product_id
];
$arrys = array_merge( $_SESSION[ "productlist" ]);
$_SESSION[ "productlist" ] = array_unique($arrys);
// This unique array created in seesion fro multi product which show correct data.
$price_blank="1";
foreach ( $cart_object->get_cart() as $cart_item ) {
$id= $cart_item['data']->get_id();
//$target_product_id=$arrys['productlist']['productid'];
//$tac_dd_discounted_price=$arrys['productlist']['price'];
if ( $id == $target_product_id ) {
$cart_item['data']->set_price($tac_dd_discounted_price);
}
else
{
$cart_item['data']->set_price($my_price['productlist']['price']);
}
}
}
But issue is for one product in cart price show correct but when try to add two product the Seession variable append same value in both product
First, instead of using PHP $_SESSION you should better use WooCommerce dedicated WC_Session class:
// Set the data (the value can be also an indexed array)
WC()->session->set( 'custom_key', 'value' );
// Get the data
WC()->session->get( 'custom_key' );
Now in your code function, you are just getting from PHP Session one product and one price in:
$tac_dd_discounted_price = $_SESSION['wdm_user_price_data'];
$target_product_id = $_SESSION['wdm_user_product_id_data']; // ==> Removed .'<br/>.'
Instead you should need to get an array of product IDs and prices when there is many products in cart.
Also, you don't need global $woocommerce;…
As you don't show all other related JS/Ajax/PHP code and as your question is not detailed, is not possible to help you more than that.
I did it anyone who used custom session for price need to update the cart and checkout page this is the hook which will help you a lot.
add_filter( 'woocommerce_add_cart_item' , 'set_woo_prices');
add_filter( 'woocommerce_get_cart_item_from_session', 'set_session_prices', 20 , 3 );
function set_woo_prices( $woo_data ) {
session_start();
$tac_dd_discounted_price = $_SESSION['wdm_user_price_data'];
$target_product_id = $_SESSION['wdm_user_product_id_data'];
if ( ! isset($tac_dd_discounted_price ) || empty ($tac_dd_discounted_price ) ) { return $woo_data; }
$woo_data['data']->set_price( $tac_dd_discounted_price );
$woo_data['my_price'] = $tac_dd_discounted_price;
return $woo_data;
}
function set_session_prices ( $woo_data , $values , $key ) {
if ( ! isset( $woo_data['my_price'] ) || empty ( $woo_data['my_price'] ) ) { return $woo_data; }
$woo_data['data']->set_price( $woo_data['my_price'] );
return $woo_data;
}

woocommerce_before_calculate_totals fires twice

Writing an addition to the site, want to modify the price in the cart. Have the following code:
function apd_product_custom_price($cart_item_data, $product_id)
{
if (isset($_POST['use_rewards']) && !empty($_POST['use_rewards']))
{
$cart_item_data['use_rewards'] = $_POST['use_rewards'];
}
return $cart_item_data;
}
add_filter('woocommerce_add_cart_item_data', 'apd_product_custom_price', 99, 2);
function apd_apply_custom_price_to_cart_item($cart_object)
{
if( !WC()->session->__isset( 'reload_checkout' )) {
foreach ($cart_object->cart_contents as $value) {
if(isset($value['use_rewards'])) {
$price = $value['data']->get_price() -
$value['use_rewards'];
$value['data']->set_price($price);
}
}
}
}
add_action('woocommerce_before_calculate_totals', 'apd_apply_custom_price_to_cart_item',10);
By some reason the hook woocommerce_before_calculate_totals fires twice. if I replace the code in the function apd_apply_custom_price_to_cart_item($cart_object) with just echo 1; it displays 11 in the cart page. Can some please help?
I forgot the link I should refer to for a solution. You can use this at the top of your function:
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
Most likely some other plugins hooks to 'woocommerce_before_calculate_totals' action.
Try to disable plugins one by one and see witch one is causing this behaviour.
In my case I found that WooCommerce-multilingual plugin hooks to woocommerce_before_calculate_totals action.
So I did this:
add_action( 'woocommerce_before_calculate_totals', '_wm_ponc_upte_prc', 99 );
function _wm_ponc_upte_prc( $cart_object ) {
if ( !WC()->session->__isset( "reload_checkout" ) ) {
foreach ( WC()->cart->get_cart() as $key => $value ) {
// checking if user checked checkbox (optional)
if ( isset( $value['wm_ponc_fee'] ) && ( $value[ 'wm_ponc_fee' ] === 'yes' ) ) {
// your calculations ....
// and Remove your action after you are done.
remove_action( 'woocommerce_before_calculate_totals', '_wm_ponc_upte_prc', 99 );
}
}
}
}
I have removed action after custom calculations. And that's it.
I see exactly the same issue - my hooked function is firing twice, leading to the option price being added at 2x the cost. My solution was to load the product, get the price from that and then add my incremental cost to that.
function tbk_woo_update_option_price( $cart_object ) {
$option_price = 3.50;
foreach ( $cart_object->get_cart() as $cart_item_key => $cart_item ) {
$item_id = $cart_item['data']->id;
//Hook seems to be firing twice for some reason... Get the price from the original product data, not from the cart...
$product = wc_get_product( $item_id );
$original_price = $product->get_price();
$new_price = $original_price + $option_price;
$cart_item['data']->set_price( $new_price );
}
}
add_action( 'woocommerce_before_calculate_totals', 'tbk_woo_update_option_price', 1000, 1 );

Woocommerce delivery&payment options - What´s wrong with my php code?

I am trying to hide some payment options in Woocommerce in case of specific delivery option. I tried to put this to my functions.php but It´s not working and I don´t know why.
Can you help me please?
function payment_gateway_disable_country( $available_gateways, $available_methods )
{
global $woocommerce;
if ( isset( $available_methods['local_delivery'] ) ){
unset( $available_gateways['paypal'] );
}
return $available_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'payment_gateway_disable_country' );
My research:
link 1
link 2
link 3
link 4
The available delivery methods do not get passed as a parameter in the filter woocommerce_available_payment_gateways - you need to load them in and check them.
The code below should remove the paypal payment option one if the user selects local delivery. If your checkout page is the AJAX based one then as the user changes the delivery method, the available payment options should also change.
function payment_gateway_disable_country($available_gateways) {
global $woocommerce;
$packages = $woocommerce->shipping->get_packages();
foreach ( $packages as $i => $package ) {
$chosen_method = isset( $woocommerce->session->chosen_shipping_methods[ $i ] ) ?
$woocommerce->session->chosen_shipping_methods[ $i ] : '';
if ('local_delivery' == $chosen_method) {
unset($available_gateways['paypal']);
break;
}
}
return $available_gateways;
}
add_filter(
'woocommerce_available_payment_gateways',
'payment_gateway_disable_country'
);
Let me know if you have any issues with the code; I did not have a chance to test it with woocommerce.
$available_methods will not be accessible inside your function. So first define it globally & access as global variable inside function, somewhat like this:
global $available_methods;
$available_methods = array( 'local_delivery' => 'yes' );
function payment_gateway_disable_country( $available_gateways )
{
global $woocommerce, $available_methods;
if ( isset( $available_methods['local_delivery'] ) ){
unset( $available_gateways['paypal'] );
}
return $available_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'payment_gateway_disable_country' );

Categories