I've coded in a custom select box to a group of my products that changes the price based on the user's selection. It works well, but now I need to change the product title too based on their selection.
Basically if option 1 is chosen, the product name stays the same. But is option 2 is chosen, I need to add "-RZ" to the end of the product title.
I'm not sure if I can do this in the 'woocommerce_before_calculate_totals' hook where I altered the prices, but if anyone knows the hook I should use and the code to access the current product's title via PHP that would be great.
Here is the code that alters the price if it's helpful:
function calculate_core_fee( $cart_object ) {
if( !WC()->session->__isset( "reload_checkout" )) {
/* core price */
//echo $additionalPrice;
//$additionalPrice = 100;
foreach ( $cart_object->cart_contents as $key => $value ) {
$product_id = $value['product_id'];
if( isset( $value["addOn"] ) && $value["addOn"] == $product_id) {
$additionalPrice = $value['core'];
/* Woocommerce 3.0 + */
$orgPrice = floatval( $value['data']->get_price() );
//echo $additionalPrice;
//echo $orgPrice;
$value['data']->set_price( $orgPrice + $additionalPrice );
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'calculate_core_fee', 99 );
I know may have to get the name and store it in a SESSION variable to use later if the hook to do this is on the cart, checkout, or order page rather than the single-product page.
Yes this is possible in the same hook. You can manipulate the product title with class WC_Product get_name() and set_name() methods. But as for the price, you should set and get a custom cart field value to make it (just as $additionalPrice = $value['core'];).
See here a simple related answer: Changing WooCommerce cart item names
So you could have something like (just a fake example):
// Get your custom field cart value for the user selection
$userSelection = $value['user_selection'];
// Get original title
$originalTitle = $value['data']->get_name();
// Conditionally set the new item title
if($userSelection == 'option2')
$value['data']->set_name( $originalTitle . '-RZ' );
Related
I'm trying to do a special logic for my custom plugin. If the user has added a specific product type in their cart, in the checkout page there must be radio inputs that determine whether the user wants the specific product type to be shipped or stored in vault. I've done everything for the frontend part (creating the radio inputs, built the JavaScript logic to remove from the DOM what's not necessary and so on...) but I now need to programatically remove the shipping from the order and remove the "Shipping" row inside the order preview in the checkout page. I tried the following filter
add_filter( 'woocommerce_cart_shipping_method_full_label', 'remove_shipping_labels', 10, 2 );
function remove_shipping_labels( $label, $method ) {
return '';
}
But it's removing just the label text "Free Shipping" but not the entire shipping row inside the order preview in the checkout page. How can I programatically remove the shipping availability from an order through AJAX and update the user interface inside the checkout page?
function hide_shipping_based_on_prod_type( $rates ) {
global $woocommerce;
$items = $woocommerce->cart->get_cart();
foreach ( $items as $item => $values ) {
$product_id = $values['data']->get_id();
$product_type = WC_Product_Factory::get_product_type( $values['data']->get_id() );
if ( 'simple' === $product_type ) { //check product types of woocommerce to add more conditions
unset( $rates['free_shipping:1'] );
}
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'hide_shipping_based_on_prod_type', 100 );
add_action(
'after_setup_theme',
function() {
WC_Cache_Helper::get_transient_version( 'shipping', true );
}
);
I'm selling Gift Cards via WooCommerce on Wordpress. My customer should be able to set a value for the gift card amount by himself. I just was able to do this via a plugin. Is there a possibilty to do this by changing some code or via functions.php?
Installed Pimwick Gift Card Pro
Yes, but it's a fairly complex process if doing so from a completely fresh WooCommerce installation with no additional plugins. You will need to do the following things to achieve it:
Add a custom input field to the product to add the custom price
Save the data from the custom input field to the session (cart) when that product is added to the cart
Add the cart meta (created above in #2) to the order when the order is created
Adjust the cost of the product based on the custom price meta (added above in #3).
Step 1: Add a custom input field:
You can add the input field using the woocommerce_before_add_to_cart_button filter as shown below.
Alternatively you can use the woocommerce_wp_text_input - here's an example.
add_action( 'woocommerce_before_add_to_cart_button', 'add_custom_price_input', 100 );
function add_custom_price_input() {
if(get_the_ID() != 123) { //use the product ID of your gift card here, otherwise all products will get this additional field
return;
}
echo '<input type="number" min="50" placeholder="50" name="so_57140247_price">';
}
Step 2: Save custom price to Cart/Session
Next, we need to make sure that your custom input field data is carried over to the cart/session data. We can make use of the woocommerce_add_cart_item_data ( docs | example ) filter to that:
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_meta_to_cart', 10, 3 );
function add_custom_meta_to_cart( $cart_item_data, $product_id, $variation_id ) {
$custom_price = intval(filter_input( INPUT_POST, 'so_57140247_price' ));
if ( !empty( $custom_price ) && $product_id == 123 ) { //check that the custom_price variable is set, and that the product is your gift card
$cart_item_data['so_57140247_price'] = $custom_price; //this will add your custom price data to the cart item data
}
return $cart_item_data;
}
Step 3: Add cart meta to the order
Next we have to add the meta from the cart/session to the order itself so that it can be used in the order-total calculations. We use the woocommerce_checkout_create_order_line_item ( docs | example ) to do this:
add_action( 'woocommerce_checkout_create_order_line_item', 'add_custom_meta_to_order', 10, 4 );
function add_custom_meta_to_order( $item, $cart_item_key, $values, $order ) {
//check if our custom meta was set on the line item of inside the cart/session
if ( !empty( $values['so_57140247_price'] ) ) {
$item->add_meta_data( '_custom_price', $values['so_57140247_price'] ); //add the value to order line item
}
return;
}
Step 4: Adjust total of gift card line item
Finally, we simply adjust the cost of the line item of the gift card based on the value entered into the input field. We can hook into woocommerce_before_calculate_totals ( docs | example ) to do this.
add_action( 'woocommerce_before_calculate_totals', 'calculate_cost_custom', 10, 1);
function calculate_cost_custom( $cart_obj ) {
foreach ( $cart_obj->get_cart() as $key => $value ) {
$price = intval($value['_custom_price']);
$value['data']->set_price( $price );
}
}
I have a function on my Woocommerce website that enables customers to set a custom amount to pay for a specific product, based on a value I'm passing through the URL.
I'm using the woocommerce_before_calculate_totals hook, and up until I upgraded to WC 3.3.5, it was working fine. Now, when I run the code, the checkout initially shows the custom amount.
However, once the loader has finished updating, it resets the price to '0' (i.e. displaying £0.00 the checkout page's total fields).
Here's that code:
add_action( 'woocommerce_before_calculate_totals', 'pay_custom_amount', 99);
function pay_custom_amount() {
$payment_value = $_GET['amount'];
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if($cart_item['data']->id == 21 ){
$cart_item['data']->set_price($payment_value);
}
}
}
Well, colour me baffled. I've trawled Stack Overflow for solutions but can't see any similar problems. I see the hook runs multiple times but gather this is normal.
If anyone know what might be happening here, it would be great if you could share.
You can't get a price from an URL and set it in woocommerce_before_calculate_totals action hook. This needs to be done differently.
In the below code:
the first hooked function will get that "amount" from the URl and will set it (register it) in cart item object as custom data.
the 2nd hooked function will read that amount from custom cart item data and will set it as the new price.
Now your the target product ID in your code need to be the same ID that the added to cart product.
The code:
// Get the custom "amount" from URL and save it as custom data to the cart item
add_filter( 'woocommerce_add_cart_item_data', 'add_pack_data_to_cart_item_data', 20, 2 );
function add_pack_data_to_cart_item_data( $cart_item_data, $product_id ){
if( ! isset($_GET['amount']) )
return $cart_item_data;
$amount = esc_attr( $_GET['amount'] );
if( empty($amount) )
return $cart_item_data;
// Set the custom amount in cart object
$cart_item_data['custom_price'] = (float) $amount;
$cart_item_data['unique_key'] = md5( microtime() . rand() ); // Make each item unique
return $cart_item_data;
}
// Alter conditionally cart item price based on product ID and custom registered "amount"
add_action( 'woocommerce_before_calculate_totals', 'change_conditionally_cart_item_price', 30, 1 );
function change_conditionally_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// HERE set your targeted product ID
$targeted_product_id = 21;
foreach ( $cart->get_cart() as $cart_item ) {
// Checking for the targeted product ID and the registered "amount" cart item custom data to set the new price
if($cart_item['data']->get_id() == $targeted_product_id && isset($cart_item['custom_price']) )
$cart_item['data']->set_price($cart_item['custom_price']);
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
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.
I need to programmatically and dynamically change the price of an item in the cart.
I’ve tried varying combinations of Woocommerce action hooks, the cart and session objects, but nothing quite seems to do the trick. I thought this wouldn’t be so challenging.
add_action( 'woocommerce_before_calculate_totals', 'change_cart_item_price' );
function change_cart_item_price( $cart_object ) {
foreach ( $cart_object->cart_contents as $key => $value ) {
if( 123 == $value['data']->id ) {
$new_price = function_to_get_new_price( $value, get_current_user_id( ) );
$value['data']->price = $new_price;
}
}
}
The above code changes the price for each item only on the checkout page, or when updating the cart (ie: the hook is called when removing an item from the cart), but not indefinitely.
I'm using the Woocommerce Gravity Forms add-on. I have one product in particular, which will be ordered multiple times by a given user. The user will be allowed 5x free with only shipping fees, and each above 5 will be $20. I have this much coded and functional with Gravity Forms hooks that dynamically populate fields. Shipping is specific to fields within the gravity form, therefore I am leaving that calculation to Gravity Forms.
My issue is that if a user reduces the quantity of this product from their order (removes one of the items from the cart), it should re-calculate the price of each item of the same product within the cart, otherwise they could be over-charged (an item that used to be the 6th is now the 4th, but the price remains the same, which it shouldn't)
Therefore, I would like to re-calculate the price of each item in the cart, based on the quantity of this particular product, every time something is removed from the cart.
--- EDIT ---
The above code works, but I'm realizing the issue must be a custom loop I'm using to display the prices...
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = $cart_item['data'];
if( 123 == $_product->post->ID ) {
$price_not_updated = $cart_item['data']->price;
}
}
I figured it out... I looked at the woocommerce cart docs and essentially realized that the prices I was getting had yet to be calculated. So, before running the loop, I had to do the action that I was initially hooking into to change the prices.
Thanks for your help!
function getUpdatedCartPrices() {
do_action( 'woocommerce_before_calculate_totals', WC()->cart );
$horray_updated_prices_works = array();
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = $cart_item['data'];
if( 123 == $_product->post->ID ) {
$horray_updated_prices_works[] = $cart_item['data']->price;
}
}
}
I changed the function to have a second parameter so that you can use it dynamically with any product as long as you call the proper id. I also set the function return value to either a success or error message. This way you can know if it was changed, and if so, to what price. Hope this helps.
by the way, having this function called again when the cart is updated should solve the recalculation issue. It would be great if i could see the code for your $function_to_get_new_price() function.
add_action( 'woocommerce_before_calculate_totals', 'change_cart_item_price' );
function change_cart_item_price($id, $cart_object ) {
foreach ( $cart_object->cart_contents as $key => $value ) {
if( $id == $value['data']->id ) {
$new_price = function_to_get_new_price( $value, get_current_user_id( ) );
$value['data']->price = $new_price;
$successMsg = "The price of item $value['data']->id was set to $value['data']->price".;
return $successMsg;
}else{
$errorMsg = "Price was not changed!";
return $errorMsg;
}
}
}