I've been struggling with a snippet for WooCommerce that I'd like to add to my child's theme functions but I am reaching the limits of my PHP knowledge.
I have set a custom attribute called pdt_volume, that I will fill everytime I add a product. I would like to remove the Add_to_cart button when the sum of this attribute for all the items already in the cart have reach a max_volume limit.
For example, the Max_volume is 100, I have 4 products of pdt_volume = 20, therefore, the add_to_cart button for a product with a pdt_volume of 25 should be removed so that I cannot add it to the cart.
So I have come up with this snippet, with bits of code found here and there.
But the functions.php won't save it, and others variations of this code has succeeded to register in the functions.php but the website would then give a 500 error...
Please, does someone has any idea how to achieve this?
What am I doing wrong?
Thanks.
EDIT 1 : Alright, so I got this code to actually be registered in the functions.php by the editor without breaking, but on the site, I still get the internal server error. Like something is not computing or something.
EDIT 2 (29/01/2017)
I used the ACF plugin I had purchased a long time ago but didn't find any suitable purpose... so far.
Here is the working code I was able to come up with. This is not a code masterpiece and I won't get any award for this, but it seems to be working so far. At least, it allows me to get a TRUE/FALSE statement that I can use in a if condition to change the add_to_cart button to a Your_box_is_full button.
Indeed, I didn't need any global $woocommerce or $product !
function get_cart_volume() {
$cart_volume = 0;
foreach( WC()->cart->get_cart() as $cart_item ) {
$item_id = $cart_item['product_id'];
$item_volume = get_field('product_volume', $item_id);
$item_qty = $cart_item['quantity'];
$vol_by_qty = $item_volume * $item_qty;
$cart_volume += $vol_by_qty;
}
return $cart_volume;
}
function check_if_full($candidate) {
$max_volume = 100;
$candidate = $product->id;
$a_volume = get_field('product_volume', $candidate);
$b_volume = get_cart_volume();
$check_volume = $a_volume + $b_volume;
if ($check_volume > $max_volume)
return true;
else
return false;
}
//Just a function to see if it's working on the cart page fur debugging purpose
add_action( 'woocommerce_check_cart_items', 'current_volume');
function current_volume() {
if (is_cart() || is_checkout()) {
global $woocommerce;
$current_volume = get_cart_volume();
wc_add_notice( sprintf( '<strong>Volume is %s.</strong>', $current_volume ),
'error' );
}
}
As Helgatheviking says, you get already, with woocommerce_is_purchasable hook in your hooked function, the $product object as 2nd argument. So you don't need and you have to remove global $woocommerce, $product; to make it work without throwing an error.
Your code is going to be:
add_filter('woocommerce_is_purchasable', 'if_room_is_purchasable', 10, 2);
function if_room_is_purchasable ($is_purchasable, $product){
$cart_volume = 0;
$max_volume = 100;
foreach( WC()->cart->get_cart() as $cart_item ){
$item_id = $cart_item['product_id'];
$terms = get_the_terms( $item_id, 'pa_pdt_volume');
foreach($terms as $key => $term){
$cart_volume += $term->name; // May be better with $term->slug;
}
}
$candidate_volume = $cart_volume + $product->get_attribute( 'pa_pdt_volume' );
if ( $candidate_volume > $max_volume )
return false;
else
return true;
}
This should work now without error.
Related
I've been stuck on this for far too long. I've tried everything I've found on stackoverflow and I feel like I'm going around in circles.
I have a form on a product page asking for an invoice number and an amount on the invoice. I can get product attributes to update and display on the Cart page using the following code:
function invoice_save_price( $cart_item_data, $product_id ) {
if( isset( $_POST['invoice_id'] ) ) {
$cart_item_data = array();
$cart_item_data[ "invoice_number" ] = $_POST['invoice_number'];
$cart_item_data[ "invoice_amount" ] = $_POST['invoice_amount'];
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'invoice_save_price', 99, 2 );
I'm using a custom product type - extending simple products. I'm not sure if that's the correct way to do this, as my product has to have a default price set ($1 for now) or it doesn't display.
function wcpt_register_invoice_type () {
class WC_Product_Invoice extends WC_Product {
public function __construct( $product ) {
$this->product_type = 'invoice';
parent::__construct( $product );
}
}
}
However, I can't get the price to update. My code for that is here:
add_action( 'woocommerce_before_calculate_totals', 'invoice_add_custom_price', 99 );
function invoice_add_custom_price($cart_object) {
if (isset($_POST['invoice_id'])) {
foreach ( $cart_object->get_cart() as $value ) {
$newValue = number_format($_POST['invoice_amount'],2);
$value['data']->set_price($newValue);
}
return $value;
}
}
I thought there might've been a conflict with another plugin, so I started testing on a clean install of Wordpress 5.8 and WooCommerce 5.5.2
I've found a lot of references to this in older versions of WooCommerce (3.x) but I'm not having much luck in later versions.
Can someone please tell me what I'm missing? Any help will be appreciated!
Thanks,
I have a wordpress shop, where I sell digital products.
What the function should do:
User clicks add to cart button.
Function checks if the item is already in the cart.
If yes: Redirect user to checkout page without adding the product to cart (so the quantity doesn't change, it stays at 1).
If no: Redirect to checkout and add product to cart (quantity goes from 0 to 1).
What the function looks like:
add_filter('woocommerce_add_to_cart_validation', 'my_validation_handler', 10, 2);
function my_validation_handler($is_valid, $product_id) {
$url = WC()->cart->get_checkout_url();
foreach(WC()->cart->get_cart() as $cart_item_key => $values) {
if ($values['data']->id == $product_id) {
$url = WC()->cart->get_checkout_url();
wp_redirect($url);
exit();
}
else {
return $is_valid;
}
}
}
What happens:
When I implement the code in the functions.php of my child theme: (I already have the product in the cart) I click on the add to cart button again, but nothing happens.
If the cart is empty same thing, nothing happens, no reload nothing, I'm still on the products page.
Important detail:
I know there is a native WooCommerce function (sold seperately). But I have a custom products page and I don't want a message to appear that says "you already added that to cart".
Since I'm retargeting website visitors, the item is still in there sometimes from their last visit. And a expire session solution also not really what I'm looking for.
You can use the following, explanation as comment lines in the code
function my_validation_handler( $passed, $product_id, $quantity, $variation_id = null, $variations = null ) {
// Get checkout url
$checkout_url = wc_get_checkout_url();
// Set variable
$in_cart = false;
// Loop
foreach( WC()->cart->get_cart() as $cart_item ) {
if ( $cart_item['data']->get_id() == $product_id ) {
$in_cart = true;
break;
}
}
// True
if ( $in_cart ) {
wp_safe_redirect( $checkout_url );
exit();
} else {
// Add product to cart
WC()->cart->add_to_cart( $product_id, $quantity );
wp_safe_redirect( $checkout_url );
exit();
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'my_validation_handler', 10, 5 );
As the title says, I'm getting Error 502 Bad Gateway when I try to use the standard function add_to_cart() from WooCommerce
WC()->cart->add_to_cart( 8622 );
Any ideas what's going on? I also tried adding more arguments to the function such as the quantity and etc but doesn't seems to change anything...
WooCommerce documentation: https://docs.woocommerce.com/wc-apidocs/class-WC_Cart.html
Okay, I have managed to fix this by making another function to be called in the function.php file. I am not sure why this works now since it's the same concept, except that the function is now called from the functions.php file from the theme.
Here's the code for anyone that needs this:
// Add item to cart
function add_id_to_cart( $product_id ) {
$flag = true;
//check if product already in cart
foreach(WC()->cart->get_cart() as $key => $val ) {
$_product = $val['data'];
if($product_id == $_product->id ) {
$flag = false;
}
}
// if product not in cart, add it
if ( $flag ) {
WC()->cart->add_to_cart( $product_id );
}
}
We are using this WooCommerce Custom Fields commercial plugin on our Woocommerce e-shop for individual customization of our products and I am trying to find a way how to hide payment method if key 'wccf' is in product meta.
I am trying to upgrade a code below, I want to replace shipping country checking, but I don't know how to get and check 'wccf' key.
function payment_gateway_disable_country( $available_gateways ){
global $woocommerce;
if (isset($available_gateways['cod']) && $woocommerce->customer->get_shipping_country() <> 'IT'){
unset($available_gateways['cod']);
}
return $available_gateways;
}
add_filter('woocommerce_available_payment_gateways', 'payment_gateway_disable_country');
Does anybody can you help me?
Try with below code. Put the code in functions.php
function payment_gateway_disable_country($available_gateways){
global $woocommerce;
if (isset($available_gateways['cod']) && $woocommerce->customer->get_shipping_country() <> 'IT'){
//fetching the cart
$session_data = WC()->session->get('wccf');
if(!empty($session_data)){
unset($available_gateways['cod']);
}
}
return $available_gateways;
}
add_filter('woocommerce_available_payment_gateways', 'payment_gateway_disable_country');
Something like the following in your filter should do it, assuming the product has a wccf entry in its meta data.
function payment_gateway_disable_wccf($available_gateways){
$cart = WC()->cart;
if( $cart ){
foreach($cart->get_cart() as $currItem){
if( get_post_meta($currItem['product_id'], 'wccf', true) )
unset($available_gateways['cod']);
}
}
return $available_gateways;
}
add_filter('woocommerce_available_payment_gateways', 'payment_gateway_disable_wccf');
Thank you all for your support and help! Finally, plugin developer send me a code which solved my problem.
$cart = WC()->cart->get_cart();
$wccf_is_set = false;
foreach ($cart as $cart_item) {
if (isset($cart_item['wccf'])) {
// mark that there's data set
$wccf_is_set = true;
}
}
if ($wccf_is_set === true) {
// do what you need if the data is set
}
$replace_order = new WC_Cart();
$replace_order->empty_cart( true );
$replace_order->add_to_cart( "256", "1");
The above code add product 256 to the Cart 1 time. But the issue I'm having is that I want to be able to completely override the product price... as far as I can tell, the only thing I can do it apply a coupon to the Cart.
Is there a way to completely override the price to something totally custom?
Here is the code for overriding price of product in cart
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
$custom_price = 10; // This will be your custome price
foreach ( $cart_object->cart_contents as $key => $value ) {
$value['data']->price = $custom_price;
// for WooCommerce version 3+ use:
// $value['data']->set_price($custom_price);
}
}
Hope it will be useful...
You need to introduce an if statement for checking product id, in above code:
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
$custom_price = 10; // This will be your custome price
$target_product_id = 598;
foreach ( $cart_object->cart_contents as $value ) {
if ( $value['product_id'] == $target_product_id ) {
$value['data']->price = $custom_price;
}
/*
// If your target product is a variation
if ( $value['variation_id'] == $target_product_id ) {
$value['data']->price = $custom_price;
}
*/
}
}
Add this code anywhere and make sure that this code is always executable.
After adding this code, when you'll call:
global $woocommerce;
$woocommerce->cart->add_to_cart(598);
Only this product will be added with overridden price, other products added to cart will be ignored for overriding prices.
Hope this will be helpful.
I have tried all above code samples and latest woocommerce 3.0 is not support any of the above example. Use below code and working perfectly for me.
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
$custom_price = 10; // This will be your custom price
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$cart_item['data']->set_price($custom_price);
}
}
After release of woocommerce version 3.0.0 product price is update on add to cart using set_price($price) function. The example is given as below :
add_action( 'woocommerce_before_calculate_totals', 'mj_custom_price' );
function mj_custom_price( $cart_object ) {
$woo_ver = WC()->version;
$custom_price = 10;
foreach ( $cart_object->cart_contents as $key => $value )
{
if($woo_ver < "3.0.0" && $woo_ver < "2.7.0")
{
$value['data']->price = $custom_price;
}
else
{
$value['data']->set_price($custom_price);
}
}
}
Many Thanks
For the Wordpress and Woocommerce latest version,Please use like this
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
foreach ( $cart_object->cart_contents as $key => $value ) {
$custom_price = 5;
$value['data']->set_price($custom_price);
}
}
For eveeryone that got here from Google. The above is now deprecated as i found out updating to WooCommerce 3.0.1.
Instead of the above you now need to use set_price instead of price
Here is an example:
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart_object ) {
$custom_price = 10; // This will be your custome price
foreach ( $cart_object->cart_contents as $key => $value ) {
$value['data']->set_price = $custom_price;
}
}
I hope this helps people in the future :)
This is how i did it, first i add my custom price to cart_item_data witch can save custom data to cart items, then i use woocommerce_before_calculate_totals, loop the cart and add the previously added price.
function add_donation_to_cart() {
$cart_item_data = array('price' => $_REQUEST['donate_amount']);
$woocommerce->cart->add_to_cart( 5395, 1, '', array(), $cart_item_data);
}
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price' );
function add_custom_price( $cart ) {
foreach ( $cart->cart_contents as $key => $value ) {
$value['data']->price = $value['price'];
}
}
With WooCommerce 2.5 I found this to be a 2-part process. The first step is to change the run-time display of pricing when added to the cart via the woocommerce_add_cart_item filter. The second part is to set the persistent session data which is read during checkout via the woocommerce_get_cart_item_from_session filter. This seems to be faster than hooking the calculate totals filters (such as woocommerce_before_calculate_totals) as they are run very frequently in WooCommerce.
More details here:
woocommerce change price while add to cart
To make it dynamic ( override price for each item in cart separately ), you need to save the override product price in session with cart item key as session key using woocommerce_add_to_cart hook.
by using these session values you can calculate correct Cart Total and make the altered price appear in the Order Item as well
You can use the following
add_filter( 'woocommerce_cart_item_price', 'kd_custom_price_message' );
function kd_custom_price_message( $price ) {
$textafter = ' USD';
return $price . $textafter;
}