I need the Woocommerce cart to be cleaned in case I send more than four items to it via url.
I came up with this code, but it only cleans the cart if there are already five items in it.
//in functions.php
add_filter( 'woocommerce_add_to_cart_validation', 'remove_cart_item_before_add_to_cart', 20, 3 );
function remove_cart_item_before_add_to_cart( $passed, $product_id, $quantity ) {
if( WC()->cart->get_cart_contents_count() >= 5 )
WC()->cart->empty_cart();
return $passed;
}
Another problem is that, even the code above that is not useful to me, does not work if I add multiple courses via url, as in:
https://exemple.net/cart?fill_cart=100,101,102,103,104,105,106
That is, the code in functions.php only works from the website, and not by url.
All I need is clear the cart when sending more than 4 items by url.
I prefer a solution in PHP, but a JS solution will do. Thanks for who can help me.
I found a solution using the free plugin Cart links for WooCommerce, and making a few change in its code.
I will describe below what I did:
1) To start install the plugin, this will allow you to add products using the fill_cart parameter in url (as described in my question)
2) edit the plugin file soft79-cart-links-for-woocommerce.php found at: yoursite/wp-content/plugins/soft79-cart-links-for-woocommerce/
3) go to line 141 or find the declaration of the method fill_cart
Inside the fill_cart method uncomment (or add) the code to clean the cart:
public function fill_cart( $fill_string ) {
$original_notices = wc_get_notices();
wc_clear_notices();
////Clear the cart
//WC()->cart->empty_cart(); <-- uncomment here!
Save the file. Now any new items that arrive via url must clean the cart first.
Related
I'm looking to create a PHP code snippet that I would add to my functions.php file but I'm not sure how to proceed.
Someone asked the same question 2 years ago (Woocommerce - disable certain shipping methods based on time of day) but finally opted for a plugin that does that. I already use add-ons for detailed delivery options and I don't want to change or add another one just for this simple function if something can be done easily with php.
So I'm looking to disable a shipping method if the client order after 11AM (website time zone).
So I have this code for now :
if (date('H') > 11) {
$shippingmethod1.disable();
}
Can someone give me the proper code to make it work?
This is quiet simple using woocommerce_package_rates filter hook.
Now you need to find out what is the shipping rate Id reference that you need to target. For that you will inspect the desired shipping method radio button (<input> field) with your browser tools to get value as shown below:
Once you get it you will set that in the code below:
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_time', 10, 2 );
function hide_shipping_method_based_on_time( $rates, $package )
{
// Set your default time zone (http://php.net/manual/en/timezones.php)
date_default_timezone_set('Europe/London');
// Here set your shipping rate Id
$shipping_rate_id = 'local_pickup:13';
// When this shipping method is available and after 11 AM
if ( array_key_exists( $shipping_rate_id, $rates ) && date('H') > 11 ) {
unset($rates[$shipping_rate_id]); // remove it
}
return $rates;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Clearing shipping caches:
You will need to empty your cart, to clear cached shipping data
Or In shipping settings, you can disable / save any shipping method, then enable back / save.
before WooCommerce 3.0 came out my code had worked like a charm to save custom values from the cart into the order on checkout. But since then I'm not able to create custom meta for orders.
Environment: Wordpress 4.9.4 & WooCommerce 3.3.3
Hooks
add_action('woocommerce_checkout_update_order_meta', 'custom_meta_to_order', 20, 1);
add_action('woocommerce_checkout_create_order', 'custom_meta_to_order', 20, 1);
The Hook number 1 is the one I tried the most, the 2 one was just an experiment with some literal changes mentioned in this topic.
Function
The following functions-code is related to hook number 1:
if (!function_exists('custom_meta_to_order')) {
function custom_meta_to_order($order_id, $values) {
$order = wc_get_order( $order_id );
$order->update_meta_data('_TESTKEYstart', 'Hello');
if (isset($values['myValue'])) {
$myValue = $values['myValue'];
if (!empty($myValue)) $order->update_meta_data('_myKey', $myValue);
}
$order->update_meta_data('_TESTKEYend', 'Bye');
$order->save();
}
}
I've checked also in the mySQL table table wp_woocommerce_order_itemmeta if at least the two _TESTKEY*-meta-entrys will be created (because they don't have a condition).
But it seems that the meta-keys and values don't getting created via this hook and function.
The function itself getting called, so at least the hooks itselfs are working.
So my question is: "What am I doing wrong?"
UPDATED: There is some errors in your code…
Both hooks have only 1 argument (not 2, so $values doesn't exist)
To get your custom field you should use $_POST['myValue'] instead.
and other things like each hook has a different argument:
$order_id for woocommerce_checkout_update_order_meta
$order for woocommerce_checkout_create_order
Below I have replaced $_POST['myValue'] by $_POST['billing_country'] as you don't give the code for this custom checkout field…
So here are both ways:
1) The best way for me, as explained here:
if ( ! function_exists('custom_meta_to_order') ) {
add_action( 'woocommerce_checkout_create_order', 'custom_meta_to_order', 20, 1 );
function custom_meta_to_order( $order ) {
$order->update_meta_data('_TESTKEYstart', 'Hello');
if (isset($_POST['billing_country'])) {
$myValue = $_POST['billing_country'];
if (!empty($myValue)) $order->update_meta_data('_my_key', $myValue);
}
$order->update_meta_data('_TESTKEYend', 'Bye');
}
}
Code goes in function.php file of your active child theme (or theme). Tested and works.
2) The other way:
if ( ! function_exists('custom_meta_to_order') ) {
add_action('woocommerce_checkout_update_order_meta', 'custom_meta_to_order', 20, 1);
function custom_meta_to_order( $order_id ) {
// get an instance of the WC_Order object
$order = wc_get_order( $order_id );
$order->update_meta_data('_TESTKEYstart', 'Hello');
if (isset($_POST['billing_country'])) {
$myValue = $_POST['billing_country'];
if (!empty($myValue)) $order->update_meta_data('_my_key', $myValue);
}
$order->update_meta_data('_TESTKEYend', 'Bye');
// Save the order data and meta data
$order->save();
}
}
Code goes in function.php file of your active child theme (or theme). Tested and works.
The proof:
And (in database wp_postmeta table for this order ID):
Tested in WooCommerce version 3.3+
You can use the old way too (which works):
if ( ! function_exists('custom_meta_to_order') ) {
add_action('woocommerce_checkout_update_order_meta', 'custom_meta_to_order', 20, 1);
function custom_meta_to_order( $order_id ) {
update_post_meta( $order_id, '_TESTKEYstart', 'Hello' );
if ( isset( $_POST['billing_country'] ) ) {
$myValue = $_POST['billing_country'];
if (!empty($myValue))
update_post_meta( $order_id, '_my_key', $myValue);
}
update_post_meta( $order_id, '_TESTKEYend', 'Bye');
}
}
Code goes in function.php file of your active child theme (or theme). Tested and works.
Related: Add extra meta for orders in Woocommerce
Because comments are really hard to read (because of to much restricted formatation), this answer is just a response to the answer from LoicTheAztec.
I wrote a longer answer but it seems gone, so I sorry now for the much shorter one!
First our misunderstanding
You understood that I would like to use custom values from products but in my case it was a little bit other. I wrote an external application which included the wp-load.php and posted then data back to the product-page into the cart.
So the problem showed up here was the attempt to write the data from the cart into the order on checkout.
Recommend ways doesn't worked at first
The recommend ways you suggested all doesn't worked. I also stripped them so much down that they have should work and just write something into the meta. I've no clue which plugin/theme-function pranked me this time here.
But I was able to solve the problem
And many more! Just because I found the blog-post where I found out in the past, how to do this and as addition to my personal luck the author wrote already the changes for WP3.0, related to this process.
Still your post helped me
The errors you showed me bugged me since then and because it was hard to follow and inspect everything with Sublime and CodeIntel (and my start with Symfony itself) I decided to buy PHPStorm which showed and allowed me to fix all of my deprecated (legacy-using) functions by updating them properly.
( Finally no more global-variables: Yay. )
I mean, showing up parameters inline and deprecation-strokes already did a great job. But a bug-free working code-intel/reference which doesn't dies on big projects is just awesome.
That's why I marked your answer now as solution, thanks. Otherwise I would have just fixed the problem maybe (thanks to the authors blog-post) but still would sit on a ticking time bomb.
Completely new to Woocommerce/wordpress here. On the cart page mydomain.local/cart What filter should I use to show/hide a flat rate shipping method at certain times. From admin I managed to add an extra flat rate method and named it "Next day". Now I would like to show that flat rate method only before 4PM. I tried in functions.php
add_filter( 'woocommerce_package_rates', 'custom_change_shipping', 10);
function custom_change_shipping($rates) {
var_dump($rates);
}
Nothing seems to change and also I cant seem to debug the $rates variable as nothing is outputted when var_dump($rates);. I tried it both anonymous and as an admin but nothing seems to work.
Thanks #LoicTheAztec for confirming whether I was using the right filter. My other problem was that I was not able to output var_dump on the /cart page.
I found out that I need to clear my "cart cache" by going to woocommerce->settings->shipping and in the region, disable then enable again and click on save changes.
By doing this I could see my output from var_dump.
Filter posted earlier by #LoicTheAztec (as requested by #robert)
add_filter( 'woocommerce_package_rates', 'custom_hide_shipping', 100 );
function custom_hide_shipping( $rates ) {
$current_time = date_i18n(('H'), current_time('timestamp')); //Uses Timezone Settings > General
$maximum_time = array (
'time' =>'16'); //4PM
if ($current_time >= $maximum['time']){
unset( $rates['flat_rate:X'] ); // change X to your rate id
}
return $rates;
}
Maybe I overlooked it, but as much as I searched, I could not find which action to hook when a subscription changes price or frequency in Woocommerce Subscriptions.
The documentation says that to support price changes in your payment gateway you have to list subscription_amount_changes, but nowhere it says which function will be called when the amount actually changes..
Also in the Action reference I was unable to find an action hook which is called when the subscription amount or frequency changes. If anyone has a clue which hook to use or how to implement this particular feature, please tell me.
Edit
Ok thanks for the comments and answer by #Reigel, so if I understand correctly the change of a subscription in the admin menu (which I indeed refer to), has to be handled by the save_post action. Could you provide a small example how to hook this action and check if it is a subscription and get the $order_id (I guess this is the same as post_id?) to use in the subscription management calls?
Thank you very much already!
This should be considered an addon to the answer by #Reigel. If you upvote this, upvote his answer too.
Here's an example of hooking the pre_post_update action. It occurs a little before the save_post action. Both actions are triggered in the wp_insert_post() function in post.php.
function post_save_subscription_check( $post_ID, $data )
{
if( $data['post_type'] == 'product' ) {
if (!empty($_POST['_subscription_price']) && get_post_meta($post_ID, '_subscription_price', true) != $_POST['_subscription_price']) {
/* do stuff here */
}
if (!empty($_POST['_subscription_period']) && get_post_meta($post_ID, '_subscription_period', true) != $_POST['_subscription_period']) {
/* do stuff here */
}
}
}
add_action('pre_post_update', 'post_save_subscription_check', 10, 2 );
In the logic we are checking for the old value, obtained with get_post_meta() and the new value, held in the $_POST variable and comparing them.
This code only executes when a post updates, not for a new post
The code gets placed in your theme functions.php or custom plugin code.
In live code I would recommend cleaning any $_POST data before using it. I haven't bothered here.
I will try to explain about supports.
subscription_amount_changes is just a support and will not fire anything. You can use it for conditional statements, like:
if ( !$chosen_gateway->supports( 'subscription_amount_changes' )) {
echo 'Please be considerate and do not change the price for the chosen gateway does not support it.';
}
now, other plugins can then check if the chosen gateway supports subscription_amount_changes and do their appropriate actions.
action hook which is called when the subscription amount or frequency
changes
subscription is just a product type. Which means this is just a post with a post_type of product. The amount and frequency are just post meta. all are handled on save_post action. add_action( 'save_post', __CLASS__ . '::save_subscription_meta', 11 );. This is on the post_type=product. You have to check also for save_post on post_type=shop_order as it's more appropriate for checking support. Because there's already a gateway chosen.
I am a WP noob but very comfortable in PHP.
I am working with a client and we have built a product customization tool as an Angular.js single page application. When the product is finished being customized we are seeking to inject it into a WooCommerce cart so the client can check out. To do this we are $_POSTing the data to a PHP file in the root directory of the WP install. The code to catch it looks like:
require_once('./wp-load.php' );
global $woocommerce;
$woocommerce->session->set_customer_session_cookie(true);
$woocommerce->cart->empty_cart();
$id_arr = $_GET['productID'];
$pdfName = $_GET['pdfName'];
for($i=0; $i<count($id_arr); $i++){
$id = $id_arr[$i];
if ($id==0) continue;
if ($i==0){
$ret = $woocommerce->cart->add_to_cart($id, 1, '', '', array('pdfName'=>$pdfName));
}else{
$ret = $woocommerce->cart->add_to_cart($id);
}
}
wp_redirect(site_url().'/cart/');
The products are all correctly added to the cart but after checkout there is no sign of the metadata. After extensive research, I have found an article here: https://wpml.org/forums/topic/woocommerce-add-to-cart-does-not-work-with-wpml-activated/ that shows me that plugins can cause this behavior. So I have two specific questions?
Does my code make sense, am I creating the metadata array correctly?
Do I need to create something in WooCommerce called pdfName before I can do this?
Is there another way that metadata can be added to an order in
WooCommerce that may work around this problem?
It looks like you are adding the metadata correctly. However, as soon as you refresh, WooCommerce re-creates the cart data. Therefore you have to tell WooCommerce to maintain the metadata when it is pulling the cart from the stored session. Well, at least that is my understanding of it. So I think you need to filter thee $cart_item as it is run through the woocommerce_get_cart_item_from_session filter:
add_filter( 'woocommerce_get_cart_item_from_session', 'so_29660316_get_cart_item_from_session', 11, 2 );
function so_29660316_get_cart_item_from_session( $cart_item, $values ) {
if ( isset( $values['pdfName'] ) ) {
$cart_item['pdfName'] = $values['pdfName'];
}
return $cart_item;
}