everyone, i am trying to stop a plugin function from executing if a certain product id is in the cart. I have tried and written the following code and put them in my theme functions.php, but it doesn't seem to work. Instead, the whole page become blank. Can anyone help me out?
$found = false;
global $woocommerce;
foreach($woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if( $_product->id == 1097 ) {
$found = true;
}
}
if ($found){
remove_action('woocommerce_before_order_notes', array($wdt, 'show_field'), 20);
}
By itself, remove_action('woocommerce_before_order_notes', array($wdt, 'show_field'), 20); works. But once i tried to link it to work base on product id, the whole website just cannot load. Thank you!
The variable $wdt does not seam to be initialized. You should ether use the class name(string) or an instance of that class here.
An other guess is that your code runs before the action is added. Make sure you run your code on a later hook in the execution see this for reference: http://codex.wordpress.org/Plugin_API/Action_Reference#Actions_Run_During_a_Typical_Request
So if the code that add the hook runs at init, you can try to run your code at wp_loaded. Like this:
add_action('wp_loaded','my_remove_order_notes');
function my_remove_order_notes()
{
//Your code
}
Also, make sure that the priority parameter matches with the code where the action hook is added. The default priority is 10.
Edit:
Ok, you should not remove the filter. Filters are supposed to be used for manipulating the data and the return the new data back. Like this:
add_filter( 'woocommerce_checkout_fields' , 'custom_remove_order_comments', 99 );
function custom_remove_order_comments( $fields )
{
global $woocommerce;
foreach($woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if( $_product->id == 1097 ) {
unset($fields['order']['order_comments']); //Remove the order comments field
}
return $fields; //Return the data back to WooCommerce
}
Related
I need to hide a shipping method depending on if a discount code is used or not.
But I don't find how to hide a shipping method in the order confirmation page.
I saw that answer but it does nothing, I tried this code to verify:
add_filter( 'woocommerce_package_rates', 'custom_shipping_rates', 100, 2 );
function custom_shipping_rates( $rates, $package ) {
exit();
}
Which should block page display but the page is well loaded.
EDIT: The filter is never called because wordpress uses stored rates in class-wc-shipping.php:
if ( ! is_array( $stored_rates ) || $package_hash !== $stored_rates['package_hash'] || 'yes' === get_option( 'woocommerce_shipping_debug_mode', 'no' ) )
{
...
// Filter the calculated rates.
$package['rates'] = apply_filters( 'woocommerce_package_rates',
$package['rates'], $package );
...
}
else
{
$package['rates'] = $stored_rates['rates'];
}
That code should actually work unless you have an old wc version. You can verify if that hook exist by searching for it in /plugins/woocommerce code base. If you don't find it, then something is wrong with the updates.
If you find it and your code still doesn't work, then the only other reason is that you placed that snipped of code in a point that never get fired or you simple come too late.
Could you please add where and how you placed that code so that we can see better what is going on?
Edit:
if you look above the snipped you copied you will see:
// Get rates stored in the WC session data for this package.
$wc_session_key = 'shipping_for_package_' . $package_key ;
$stored_rates = WC()->session->get( $wc_session_key );
which makes me think that is a session-related thing. So in order to fully test you need to either open the website with another browser, empty your browser cache + cookie or use an anonymous browser session
There's a trick to disable the usage of cache, I limited it to the "update order review" action that way:
if (preg_match('#update_order_review#i',$_SERVER['REQUEST_URI']))
{
add_filter('transient_shipping-transient-version', function($value, $name)
{
return false;
}, 10, 2);
}
add_filter( 'woocommerce_package_rates', 'custom_shipping_rates', 100, 2 );
function custom_shipping_rates( $rates, $package )
{
//get coupons
$reduc=WC()->cart->get_coupons();
$hidemr=isset($reduc['thediscountcode']);
if ($hidemr)
{
foreach($rates as $k=>$v)
{
if (preg_match('#MethodLabelToHide#i',$v->get_label()))
unset($rates[$k]);
}
}
return $rates;
}
I have a custom field in my products, that needs to be updated through a function, whenever the stock in any of the variations change.
Are there hooks for this? If so, which ones and what is their output ($post_id for example)?
I think you are looking for woocommerce_reduce_order_stock action.
More info about this hook.
Here is a whole list of available hooks.
-- EDIT
Function should look like this:
function test( $order ) { // you get an object $order as an argument
$items = $order->get_items();
$items_ids = array();
foreach( $items as $item ) {
$items_ids[] = $item['product_id'];
}
die( print_r($items_ids) ); // it should break script while reduce stock
}
add_action( 'woocommerce_reduce_order_stock', 'test' );
I have achieved the same using woocommerce_product_set_stock and woocommerce_variation_set_stock hook.
These hooks run when the stock is changed (either increased, or decreased). Even after the stock is decreased after product purchase.
add_action( 'woocommerce_product_set_stock', 'stock_changed' );
add_action( 'woocommerce_variation_set_stock', 'stock_changed' );
function stock_changed( $product ) {
// Do something
}
Since WooCommerce 4.9+, woocommerce_product_before_set_stock and woocommerce_variation_before_set_stock are added to signal that the value of stock_quantity for a product/variation is about to change.
add_action( 'woocommerce_product_before_set_stock', 'stock_about_to_change' );
add_action( 'woocommerce_variation_before_set_stock', 'stock_about_to_change' );
function stock_about_to_change( $product ) {
// Do something
}
I want add to cart two product at the same time, one is original (current) product and second is from drop-down list
add_action('woocommerce_add_to_cart', 'custome_add_to_cart');
$cnt=2
function custome_add_to_cart() {
global $woocommerce;
$cnt = $cnt + 1;
echo $cnt."X";
echo $p_id=$_POST['assessories'];
$woocommerce->cart->add_to_cart($p_id, 1);
}
Output:-
As you can see in output image below , it adding same drop-down item many time in cart but i want only 1 quantity to add to cart. it seems that add_to_cart function run many times.
What should i do or how to add filter with passing second drop-down product as parameter to add to cart function ? so i can add this product also in cart.
This should work:
add_action('woocommerce_add_to_cart', 'custom_add_to_cart');
function custom_add_to_cart() {
global $woocommerce;
$product_id = $_POST['assessories'];
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
Based on following source: https://docs.woothemes.com/document/automatically-add-product-to-cart-on-visit/
The woocommerce "add_to_cart" functions run the hook "woocommerce_add_to_cart". So, in your code "add_to_cart" is run, which is running "woocommerce_add_to_cart" which runs your code, which runs "add_to_cart", etcetera etcetera... You created a recursive loop.
You need to find an alternative way, or stop calling $woocommerce->cart->add_to_cart($p_id, 1); in your own code.
What you might be looking for is a variable product with some attributes!
Anyway if really you want to do that then you just need the remove_action function :
add_action('woocommerce_add_to_cart', 'custome_add_to_cart');
function custome_add_to_cart() {
$p_id=$_POST['assessories'];
remove_action('woocommerce_add_to_cart', __FUNCTION__);
WC()->cart->add_to_cart( $p_id );
}
This prevents the action from looping indefinitely and is pretty simple.. So it will be added only once for that product. You might want to get the added to cart quantity and give it as a second parameter to the WC()->cart->add_to_cart function so they are both the same quantity
The __FUNCTION__ is a magic PHP tag just giving you the name of the current fucnction as a string, si if the function name is not the same it will still work
This might be old, but have you tried unsetting the assessories param after adding to cart?, this would break the loop.
function custome_add_to_cart() {
global $woocommerce;
if(isset($_POST['assessories'])){
$cnt = $cnt + 1;
echo $cnt . "X";
echo $p_id = $_POST['assessories'];
$woocommerce->cart->add_to_cart($p_id, 1);
unset($_POST['assessories']);
}
}
I'm building a site with a checkout, the site has 2 products, that need to be sold individually. So to prevent people from adding the first item, leaving the cart, then adding the second item, I wanted to set up the cart to auto-empty. So I decided to test it for the homepage. The initial function I had was this:
function my_empty_cart(){
global $woocommerce;
$woocommerce->cart->empty_cart();
}
add_action('init', 'my_empty_cart');
That works perfectly. But the cart is always empty because of this. So I decided to add in an "if" statement:
function my_empty_cart() {
global $woocommerce;
if ( is_front_page() && isset( $_GET['empty-cart'] ) ) {
$woocommerce->cart->empty_cart();
}
}
add_action( 'init', 'my_empty_cart' );
And that doesn't work...at all. I've tried it with "is_home" and "is_page" (with various page titles and ids). I even tried removing the "&& isset" part, just to test. At this point i'm lost, I've never had this much difficulty with a simple php code and i'm pulling out my hair at this point. Is there something simple i'm just not seeing?
this worked for me (dont relies on WordPress conditional):
/*empty cart if user come to homepage*/
add_action( 'init', 'woocommerce_clear_cart_url' );
function woocommerce_clear_cart_url() {
global $woocommerce;
if ($_SERVER['REQUEST_URI'] === '/') {
$woocommerce->cart->empty_cart();
}
}
Conditional tags (is_home(), is_front_page(), etc) don't work at the time the 'init' hook fires. You can use 'wp' hook instead. It runs immediately after wp class object is set up (http://codex.wordpress.org/Plugin_API/Action_Reference/wp).
function my_empty_cart() {
global $woocommerce;
if ( is_front_page() && isset( $_GET['empty-cart'] ) ) {
$woocommerce->cart->empty_cart();
}
}
add_action( 'wp', 'my_empty_cart' );
I am currently working on an online shop with WooCommerce. I faced the problem that I want to grant a discount to customers who chose a specific shipping method. The discount is 0.50 for every single product. I basically solved this problem with the following code in my "functions.php":
add_action('woocommerce_before_calculate_totals', 'woo_add_cart_fee');
function woo_add_cart_fee() {
global $woocommerce;
$cart = $woocommerce->cart->get_cart();
//Calculating Quantity
foreach ($cart as $cart_val => $cid) {
$qty += $cid['quantity'];
}
if ($woocommerce->cart->shipping_label == "specific shipping method") {
$woo_fee = $qty * (-0.5);
$woo_name = "discount for specific shipping method";
}
$woocommerce->cart->add_fee(__($woo_name, 'woocommerce'), $woo_fee, true);
}
The code technically works, the only problem I have now is that if a customer changes the shipping method i.e. from the "specific shipping method" to a "normal one" (without any discount) or the other way round, it always displays and calculates the discount value from the previously chosen shipping method. In other words it is always one step back and therefore displays the customer the wrong total amount.
Does anyone has an idea to solve this problem?
This solutions is for Woocommerce 2.1.X!
I am not sure if this might help. I was facing a similar problem, where I needed to retrieve the chosen shipping method. In the file \wp-content\plugins\woocommerce\includes\wc-cart-functions.php I found a method called wc_cart_totals_shipping_html().
Within this method there is a check of the current selected shipping method that contains the following code:
$packages = WC()->shipping->get_packages();
foreach ( $packages as $i => $package ) {
$chosen_method = isset( WC()->session->chosen_shipping_methods[ $i ] ) ? WC()->session->chosen_shipping_methods[ $i ] : '';
}
I used this code in my own functions.php to check for the currently selected shipping method and it works. Example:
add_filter( 'woocommerce_billing_fields', 'wc_change_required_fields');
function wc_change_required_fields($address_fields) {
$packages = WC()->shipping->get_packages();
foreach ( $packages as $i => $package ) {
$chosen_method = isset( WC()->session->chosen_shipping_methods[ $i ] ) ? WC()->session->chosen_shipping_methods[ $i ] : '';
}
if ($chosen_method == 'local_delivery') {
$address_fields['billing_address_1']['required'] = true;
// place your changes that depend on the shipping method here...
}
}
Hope that helps!
This is very old, but I ran into this issue myself and had to work out the solution.
Woocommerce stores pre-calculated cart totals in the database, rather than calculating them on the fly. But the shipping method choice is stored as a session variable. So shipping changes are not reflected immediately at checkout without a visit or refresh of a cart page.
With the original posted code, the shipping changes were not reflected because they aren't recalculated and stored. To do this, the function needs to be tricked into thinking it's a cart page first, and then recalculating the totals to be stored.
GLOBAL $woocommerce;
if ( ! defined('WOOCOMMERCE_CART') ) {
define( 'WOOCOMMERCE_CART', true );
}
And then at the end of the function, after all the desired changes have been made refresh and store.
WC()->cart->calculate_totals();
See also CODEX for WC_AJAX::update_shipping_method()
http://docs.woothemes.com/wc-apidocs/source-class-WC_AJAX.html#148-174
Mark's answer worked for me, however I had to delete all transient values prior to running the code. Otherwise, it would simply restore the saved values.
public function clear_shipping_transients() {
global $wpdb;
$wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_cp_quote_%') OR `option_name` LIKE ('_transient_timeout_cp_quote_%') OR `option_name` LIKE ('_transient_wc_ship_%')" );
}