I'm currently using a Woocommerce session to save information that the user inputs on the cart page which affects a fee added to the transaction.
I need to be able to access this information right after the order has been completed to make necessary updates to the user's account.
I figured woocommerce_thankyou would be a good hook to use, but unfortunately the session only seems to be available half of the time.
Are there any better hooks to use where I could confirm that the purchase had been completed and the session information would be available?
You need to save that session data as custom order meta data, to be able to use it afterwards (replace my_key, in the code below, with the correct session key):
// Add custom order meta data with temporary data from WC_Session
add_action( 'woocommerce_checkout_create_order', 'add_session_data_as_custom_order_meta_data', 10, 2 );
function add_session_data_as_custom_order_meta_data( $order, $data ) {
if ( $session_data = WC()->session->get('my_key') ) {
$order->update_meta_data( '_session_data', $session_data );
}
}
Code goes on function.php file of your active child theme (or theme). Tested and works.
Then to access the data you will use th WC_Data method get_meta() on the WC_Order Object:
$session_data = $order->get_meta('_session_data');
Or also using get_post_meta() function from a defined order Id:
$session_data = get_post_meta( $order_id, '_session_data', true );
Related
Is it possible to automatically copy the value of a Customer's custom field to an Order's custom field when this customer places the order?
Should it be done using any plugin/extension or thru customized coding behind the scenes?
This custom field does not need to be displayed on customer order view. We just need it to distinguish whether the order was placed by Consumer or Wholesale when we get it thru API.
I'm totally new in this system, i did a lot of research but couldn't find any direction for this.
Any advice/suggestion would be very appreciated.
You can use woocommerce_thankyou hook to add this user data to the order meta data:
add_action( 'woocommerce_thankyou', 'orders_from_processing_to_pending', 10, 1 );
function orders_from_processing_to_pending( $order_id ) {
if ( ! $order_id )
return;
$order = wc_get_order( $order_id );
$user_id = get_current_user_id();
//Set HERE the meta key of your custom user field
$user_meta_key = 'some_meta_key';
// Get here the user custom field (meta data) value
$user_meta_value = get_user_meta($user_id, $user_meta_key, true);
if ( ! empty($user_meta_value) )
update_post_meta($order_id, $user_meta_key, $user_meta_value);
else
return;
}
Code goes in function.php file of your active child theme (active theme or in any plugin file).
This code is tested and works.
After, if you want to display that value on admin edit order backend or in frontend customer view order and emails notifications, you will have to use some more code and some other hooks…
My customer wants to enable for some specific customers to pay afterwards via invoice.
So i've added an extra field in the user profiles, where he can select yes/no.
This field works fine and saves properly.
Depending on the choice:
no = default webshop behavior and customer needs to pay direct.
yes = customer can order items without paying, he'll get an invoice later on.
Also tried different payment methods, but they are available for everybody, i only want them for specific users.
Now i've tried based on that field in the functions.php to add a conditional filter like so:
if (esc_attr( get_the_author_meta( 'directbetalen', $user->ID ) ) == 'no') {
add_filter('woocommerce_cart_needs_payment', '__return_false');
}
But it doesn't seem to work?
I want payment to be skipped when the field is set to no.
Else proceed as normal and customer needs to pay.
Using WordPress get_user_meta() function, try the following :
add_filter( 'woocommerce_cart_needs_payment', 'disable_payment_for_specific_users' );
function show_specific_payment_method_for_specific_users( $needs_payment ) {
if ( get_user_meta( get_current_user_id(), 'directbetalen', true ) === 'no' ) {
$needs_payment = false;
}
return $needs_payment;
}
Code goes in functions.php file of your active child theme (or active theme). It should work.
In WoCommerce, I would like to disable particular payment methods and show particular payment methods for a subscription products in WooCommerce (and vice versa).
This is the closest thing we've found but doesn't do what I am expecting.
Yes, there are plugins that will do this but we want to achieve this without using another plugin and without making our stylesheet any more nightmarish than it already is.
Any help on this please?
Here is an example with a custom hooked function in woocommerce_available_payment_gateways filter hook, where I can disable payment gateways based on the cart items (product type):
add_filter('woocommerce_available_payment_gateways', 'conditional_payment_gateways', 10, 1);
function conditional_payment_gateways( $available_gateways ) {
// Not in backend (admin)
if( is_admin() )
return $available_gateways;
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$prod_variable = $prod_simple = $prod_subscription = false;
// Get the WC_Product object
$product = wc_get_product($cart_item['product_id']);
// Get the product types in cart (example)
if($product->is_type('simple')) $prod_simple = true;
if($product->is_type('variable')) $prod_variable = true;
if($product->is_type('subscription')) $prod_subscription = true;
}
// Remove Cash on delivery (cod) payment gateway for simple products
if($prod_simple)
unset($available_gateways['cod']); // unset 'cod'
// Remove Paypal (paypal) payment gateway for variable products
if($prod_variable)
unset($available_gateways['paypal']); // unset 'paypal'
// Remove Bank wire (Bacs) payment gateway for subscription products
if($prod_subscription)
unset($available_gateways['bacs']); // unset 'bacs'
return $available_gateways;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
All code is tested on Woocommerce 3+ and works.
This is just an example to show you how things can work. You will have to adapt it
This code has been very useful to me, but there is an error in it that I had to fix: the line
$prod_variable = $prod_simple = $prod_subscription = false;
must be put OUTSIDE (before) the FOREACH otherwise it will reset the flag everytime a new item is executed. I my case, I needed to unset a specific payment method whenever a subscription product was on the cart. As it is, this code will work only if there is just a single subscription product. If I put another different item on cart, the flag will be turn to false again and the payment method will load. Putting the line outside the FOREACH will fix this problem.
In previous versions of Woocommerce, an email notification was sent automatically when an order was changed from pending status to cancelled status (In my case, this happens after an allotted time set in the inventory section of the admin).
In WooCommerce 3.0.8 they have removed this automation and labelled as a fix:
https://github.com/woocommerce/woocommerce/blob/master/CHANGELOG.txt
And the pull request is here:
https://github.com/woocommerce/woocommerce/pull/15170/files
I'm looking to restore this functionality, but obviously copy/pasting this line back in to the Woocommerce core files isn't a good idea as it will get overwritten when the platform updates.
I know the best method would to be to create a function and hook into the cancelled order action via functions.php but after having a look I'm a bit lost about how to do this. Here is the line which was replaced:
add_action( 'woocommerce_order_status_pending_to_cancelled_notification', array( $this, 'trigger' ), 10, 2 );
How can I restore this old automated functionality?
The good new: Using woocommerce_order_status_pending_to_cancelled action hook with a custom function hook in it, solve your problem definitively:
add_action('woocommerce_order_status_pending_to_cancelled', 'cancelled_send_an_email_notification', 10, 2 );
function cancelled_send_an_email_notification( $order_id, $order ){
// Getting all WC_emails objects
$email_notifications = WC()->mailer()->get_emails();
// Sending the email
$email_notifications['WC_Email_Cancelled_Order']->trigger( $order_id );
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and perfectly works in WooCommerce 3+ (still work on version 4.8+)
Is there a simple way or a plugin to retain checkout information entered by the client after he/she leaves and comes back?
This plugin retains "fields information for customers when they navigate back and forth" however it has quite a lot of recent bad reviews so I don't think I'll use that for production. Any alternative suggestion?
---- Update ----
The code below is working, but only if data is submitted!
The only possible ways are javascript/jQuery form event detection on checkout fields and worpress Ajax:
Using ajax connected to some session transients function (as in code below).
Using (javascript) web Storage: localStorage, sessionStorage…
I have found some real interesting code in this thread that is using sessions transients to store checkout data.
// this function sets the checkout form data as session transients whenever the checkout page validates
function set_persitent_checkout ( $a ) {
$arr = array();
foreach ( $a as $key => $value )
if ( ! empty($value) )
$arr[$key] = $value;
WC()->session->set( 'form_data', $arr );
return $a;
}
add_action( 'woocommerce_after_checkout_validation', 'set_persitent_checkout' );
// this function hooks into woocommerce_checkout_get_value to substitute standard values with session values if present
function get_persistent_checkout ( $value, $index ) {
$data = WC()->session->get('form_data');
if ( ! $data || empty($data[$index]) )
return $value;
return is_bool($data[$index]) ? (int) $data[$index] : $data[$index];
}
add_filter( 'woocommerce_checkout_get_value', 'get_persistent_checkout', 10, 2 );
// This is a fix for the ship_to_different_address field which gets it value differently if there is no POST data on the checkout
function get_persitent_ship_to_different ( $value ) {
$data = WC()->session->get('form_data');
if ( ! $data || empty($data['ship_to_different_address']) )
return $value;
return is_bool($data['ship_to_different_address']) ? (int) $data['ship_to_different_address'] : $data['ship_to_different_address'];
}
add_action( 'woocommerce_ship_to_different_address_checked', 'get_persitent_ship_to_different' );
Add this code to the functions.php file located in your active child theme or theme.
Explanations from the author:
1. Save the form data:
The first function set_persitent_checkout hooks into woocommerce_after_checkout_validation.
Whenever that hook is fired, any current form data is saved as a WordPress transient via the WC_Session_Handler class (which was recently updated in version 2.5 to be a lot more efficient).
2. Check the saved data on reload:
Next we hook woocommerce_checkout_get_value with get_persitent_checkout. As the name suggests, here we check the session transients and return any matches for the current field if found.
3. Make ship_to_different_address work:
The only difficult was the ship_to_different_address field, which gets its value through a different method.
To get around this the final function was added. This works exactly the same as the previous function, but hooks into woocommerce_ship_to_different_address_checked.
There you have it. It would be nice if the data was saved after every field update on checkout, but the woocommerce_after_checkout_validation hook fires enough to capture the data at all the important points.
Functions.php snipped posted by LoicTheAztec didn't work for me.
I found this plugin which remembers everything I type or select in Woocommerce checkout, including shipping fields and my custom additions to the template:
Save Abandoned Carts – WooCommerce Live Checkout Field Capture
Account passwords, if creating during checkout, are naturally not remembered.