woocommerce checkout update shipping value more than once - wordpress

Woocommerce allows the use of the code below to update the shipping cost.
$('body').trigger('update_checkout', { update_shipping_method: true });
Am using a custom shipping plugin and am able to update the cost through ajax and eventually update my total.
The problem is, the update_checkout can only work when the billing_address_1, billing_city, shipping_city and a few other fields have been changed. So I have to do something like below:
$("#billing_address_1").trigger("keypress").val(function(i,val){return val + ' -';});
$('body').trigger('update_checkout', { update_shipping_method: true });
Is there a better way to achieve this, other than make the form dirty for woocommerce to update the shipping cost?
Thanks in advance!!

This by design of woocommerce. This scripts assumes that update is needed when changing address or country.
jQuery('body').trigger('update_checkout');
/* what this does is update the order review table but what it doesn't do is update shipping costs;
the calculate_shipping function of your shipping class will not be called again;
so if you were like me and you made a shipping method plugin and you had to change costs based on payment method then
this is the only way to ensure it does just that
*/
If you want to make things work add this (to plugin file or functions.php):
function action_woocommerce_checkout_update_order_review($array, $int)
{
WC()->cart->calculate_shipping();
return;
}
add_action('woocommerce_checkout_update_order_review', 'action_woocommerce_checkout_update_order_review', 10, 2);
Quotation from: https://gist.github.com/neamtua/bfdc4521f5a1582f5ad169646f42fcdf
For reson why, read this ticet:
https://github.com/woocommerce/woocommerce/issues/12349

Related

Woocommerce Stripe - hide shipping methods in google and apple pay

I need to hide in google pay and apple pay certain delivery methods in plugin (https://wordpress.org/plugins/woocommerce-gateway-stripe/) Can I do it with a filter or something?
Some shipping methods i have can't use - they're unsupported with apple and google pay.
Support of WC Stripe plugin told me:"Google and Apple Pay uses whichever shipping method is available on the site for the Stripe payment gateway. There isn’t an inbuilt option to selectively hide certain shipping method from Google and Apple pay, and we’re not aware of a workaround as well. I recommend taking a lot at a similar discussion here (related to disabling shipping method based on the payment gateway)" but I don't know how I do that.
–
Thanks for help.
The answer of the above mentioned question is "Yes". We can hide the shipping methods only in Apple Pay Using Stripe. Currently, there is no settings both in Woo-commerce and Stripe to select the specific shipping methods. But you can achieve that functionality by adding custom code in the right file and function. Please follow all the steps:
Step1: The file url for Stripe is listed below:
woocommerce-gateway-stripe/includes/payment-methods/class-wc-stripe-payment-request.php
Step2: Look for the following function in the file
public function get_shipping_options( $shipping_address, $itemized_display_items = false )
Step3: Remember that "STRIPE" by default uses the first Shipping method by default. So you need to check in that particular function, where that thing is happening.
Step4: Right before that specific IF condition --
"if ( isset( $data['shipping_options'][0] ) )"
Step5: Insert the Following Code before that IF condition
foreach($data['shipping_options'] as $index => $myshipping){
if(strpos($myshipping['label'],'Select Future Date') !== false){
unset($data['shipping_options'][$index]);
$data['shipping_options']= array_values($data['shipping_options']);
}
}
Note: You can do by ID or any other element in an Array.
You just need to match the shipping method ID and then Unset that ID. Please don't forget to update the array by using array_values() function.

WooCommerce Subscriptions - Action on initial payment

I am using the WooCommerce subscriptions plugin, in particular the woocommerce_subscription_payment_complete function.
I am using it like this:
add_action('woocommerce_subscription_payment_complete','subscription_created');
function subscription_created($subscription) {
echo 'Run when subscription payment is complete';
}
This works, but it also fires when a renewal payment completes. Does anybody know of a way to determine if the payment was for an initial subscription payment rather than a renewal?
You could use woocommerce_checkout_subscription_created, however the problem here is that it will fire before payment is processed - and I'm assuming you need to fire your even after payment has been successful.
One way to approach this is to set meta on the subscription post, that denotes whether your custom function has been run, and checking that meta with an if statement like this:
add_action('woocommerce_subscription_payment_complete','subscription_created');
function subscription_created($subscription) {
//check if meta exists/is not true
if (!get_post_meta($subscription->id, 'has_my_function_run', true)) {
//update meta to bool(true)
update_post_meta($subscription->id, 'has_my_function_run', true);
//run your function
echo 'Run when subscription payment is complete';
}
}
I am sure there is a better way to approach this though, so keep an eye out for other answers. It might be a good idea to look into hooking into woocommerce_order_status_processing, checking if it contains a subscription product, and then running your function, but that won't work if WooCommerce generates a new order for every subscription renewal.

woocommerce order to mark as completed upon visiting a specific page

I want a woocommerce order to be automatically marked as completed upon visiting a specific page in WordPress
This specific page will have the order_id in GET variable. Now what i need to know is how to find an order by order_id and mark the status as completed on a specific WordPress page.
You can do it with following piece of code:
if(is_page('page_title')){
$order = new WC_Order($_GET['your_order_id']);
//wc-completed, wc-processing
$update_status = array('ID'=>$_GET['your_order_id'],'post_status'=>'wc-completed');
wp_update_post( $update_status );
}
First check whether It is on your specific page or not.
Second thing is to get your order
Third step is to update status of order.
Let me know if you have any doubt.
EDITED
You can refer codex for more details on is_page.
If you have page_id then you need to put condition like if(is_page(42)) where 42 is ID of your page.
So, Rohil_PHPBeginner's answer works like a charme. If you urgently search for a "just copy and paste" solution and have no time to figure things out, go ahead and use this ready to use snippet for your functions.php:
Don't forget to replace the number 42 with the page id of your desired page that will handle as an order-completion-url. Afterwards you can call the order completion by url by: http://your-url.com/yourdeletionpage/?your_order_id=ORDER_ID_TO_BE_COMPLETED
function my_abhaken() {
if(is_page(42)){
$order = new WC_Order($_GET['your_order_id']);
//wc-completed, wc-processing
$update_status = array('ID'=>$_GET['your_order_id'],'post_status'=>'wc-completed');
wp_update_post( $update_status );
}
}
add_action('wp_head', 'my_abhaken');

Removing payment gateways from WooCommerce

I have a WooCommerce shop (running local) but I want to remove the payment gateways. The customer should be able to place an order without paying any cent, I will send them an invoice manually.
I can not really find where to disable this, it seems not to be standard in WooCommerce.
Have tried disabling all the payment gateways in the backend, but you have to leave one payment gateway enabled.
Thanks in advance!
Just add this line in functions.php in your theme:
add_filter('woocommerce_cart_needs_payment', '__return_false');
Leave 'Cash on Delivery' enabled, and it won't take a payment at the checkout. You can easily change the 'Cash on Delivery' titles and labels to something like 'No Payment Required' or similar.
Something that the other answers to this question haven't addressed is the fact that you need a way for the customer to eventually pay the invoice. Using Cash on Delivery (renamed to suit your needs) perfectly accomplishes not having the user actually pay at checkout, but the problem is that if Cash on Delivery was your only payment method, it will still be the only payment method when you send them the invoice.
I think in most cases you're going to want only cash on delivery during the cart checkout, and a different payment method (like Stripe) for the invoice payment method.
Here's the full workflow to create a deferred payment setup.
Like #crdunst mentions, you should use Cash on Delivery and rename
it to "Wait for Invoice" or something.
Enable all of the payment gateways that you ever want to use (in this example, we'll just use Cash on Delivery and Stripe. Cash on Delivery will be our "checkout" payment gateway, and Stripe will be our invoice payment gateway.
Use the following filter to turn on and off gateways based on whether or not you're on the order-pay endpoint (the page used for invoice payments).
/**
* Only show Cash on Delivery for checkout, and only Stripe for order-pay
*
* #param array $available_gateways an array of the enabled gateways
* #return array the processed array of enabled gateways
*/
function so1809762_set_gateways_by_context($available_gateways) {
global $woocommerce;
$endpoint = $woocommerce->query->get_current_endpoint();
if ($endpoint == 'order-pay') {
unset($available_gateways['cod']);
} else {
unset($available_gateways['stripe']);
}
return $available_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'so1809762_set_gateways_by_context');
Of course, if you're using a gateway other than stripe for the order-pay page, you'll want to make sure that you update unset($available_gateways['stripe']); to the proper array key.
After that, you should be good to go! Your site will now display different gateways based on whether or not you're on the invoice pay page!
Other option would be using BACS payment method, where you could explain the client that he will be invoiced later.
You can even add some info at the email that is sent when BACS is used.

Modifying Wordpress post status on Publish

I am attempting to validate fields on a custom post type in the admin panel Edit Post page.
When the user clicks "Publish" I want to validate fields in the POST data, and change the post_status to "pending" if the data does not pass the tests. When this occurs, I'd also like to add errors to the page in the admin notices area.
I've been trying this with an added hook to the "wp_insert_post" action which also saves our own data. I'm not certain of the order of operations, but I'm assuming that the wp_insert_post events happen first, and then my function gets called via the hook.
The problem is that it's the Wordpress function which is doing the post publish actions, so by the time I get to validate data, Wordpress has already saved the post with a status of "publish". What I need to do is either prevent that update, or change the status back to "pending", but I'm having little success in finding a way to do this within the API.
So, here's an order of operations I'd like to effect:
1. admin user edits post data and clicks "Publish"
2. via wp_insert_post, my data validation and post meta save routine is called
3. If data passes validation, post status is "published"
4. Otherwise, post status set to "pending" & message shown in admin notice area
Surely someone has done this, but extensive Googling just leads me to the same seemingly irrelevant pages. Can someone point me in the right direction here? Thanks in advance-
UPDATE:
So, RichardML was indeed correct, hooking to the wp_insert_post_data filter gave me the right place to validate admin post edit page fields. I'm updating this however to note what the rest of the solution is, specifically getting the reason reported in the admin notice area.
First off, you can't just output data or set a field because the admin page is the result of a redirect, and by the time you get to rendering the admin post page again, the admin_notices action is already gone. The trick was something I picked up from another forum, and it's hackish, but it works.
What you'll need to do is in your validation filter function, if you determine that you will need to display errors, is use set_option() to add a blog option with a unique name (I used 'publish_errors'). This should be HTML code in a div with a class of "error".
You will also need to add an action hook for 'admin_notices', pointing at a function which checks for the existence of the 'publish_errors' option, and if it finds it, prints it to the page and deletes it with delete_option().
You can use the wp_insert_post_data filter to inspect and modify post data before it's inserted into the database.
In response to your update I don't think it's necessary to temporarily add an option to the database. It should be possible to simply add a query string variable to the Wordpress redirect, something like this:
add_filter('wp_insert_post_data', 'my_post_data_validator', '99');
function my_post_data_validator($data) {
if ($data['post_type'] == 'post') {
// If post data is invalid then
$data['post_status'] = 'pending';
add_filter('redirect_post_location', 'my_post_redirect_filter', '99');
}
return $data;
}
function my_post_redirect_filter($location) {
remove_filter('redirect_post_location', __FILTER__, '99');
return add_query_arg('my_message', 1, $location);
}
add_action('admin_notices', 'my_post_admin_notices');
function my_post_admin_notices() {
if (!isset($_GET['my_message'])) return;
switch (absint($_GET['my_message'])) {
case 1:
$message = 'Invalid post data';
break;
default:
$message = 'Unexpected error';
}
echo '<div id="notice" class="error"><p>' . $message . '</p></div>';
}

Resources