Woocommerce simple filter php - php

My php skills is very low. I need some help this this function.
What it should do: When a order is marked as "failed" it should redirect to the woocommerce cart with an error message.
But problem is that this code redirect ALL status to the cart with the error message (even if payment is approved).
add_action( 'woocommerce_thankyou', function(){
global $woocommerce;
$order = new WC_Order();
if ( $order->status != 'failed' ) {
wp_redirect( $woocommerce->cart->get_cart_url() ); // or whatever url you want
wc_add_notice ( __( 'Payment Failed', 'woocommerce' ), 'error');
exit;
}
});

Currently you are cheching if status IS NOT failed and then redirect.
Change
if ( $order->status != 'failed' ) {
to
if ( $order->get_status() == 'failed' ) {
See PHP comparison operators.
Also, you are not getting correct order. Your function should take $order_id and load correct order.
add_action( 'woocommerce_thankyou', function( $order_id ){
$order = new WC_Order( $order_id );
if ( $order->get_status() == 'failed' ) {
wp_redirect( $woocommerce->cart->get_cart_url() ); // or whatever url you want
wc_add_notice ( __( 'Payment Failed', 'woocommerce' ), 'error');
exit;
}
}, 10, 1);

First of all you need to use the hook "woocommerce_order_status_failed" instead of "woocommerce_thankyou" as it will trigger only when the order status is failed.
Secondly you need to pass the order id in the function new WC_Order() so that it will get the details of that order. and then you can use the if statement to check if the order status if failed or not. You are using wrong operator "!=" in the if statement, so it is going to cart page for All status except failed one. You should use the "==" operator so that if the order status is equal to failed only then the statement will processed. The function you are using to get url is not compatible with new version of woocommerce, However you can use get_permalink( wc_get_page_id( 'cart' ) ) function to get the url of cart page.
Here is an example :
add_action( 'woocommerce_order_status_failed', 'mysite_failed');
function mysite_failed($order_id) {
$url = get_permalink( wc_get_page_id( 'cart' ) );
$order = new WC_Order( $order_id );
if ( $order->get_status() == 'failed' ) {
wp_redirect($url);
wp_redirect( $woocommerce->cart->wc_get_cart_url() ); // or whatever url you want
wc_add_notice ( __( 'Payment Failed', 'woocommerce' ), 'error');
exit;
}
}

Related

Woocommerce change status based on payment method

I would like to immidialtey change the order status from specific orders (payment method = stripe_sofort) to a custom status, that I already have in use:
add_action( 'woocommerce_thankyou', 'woocommerce_auto_processing_orders');
function woocommerce_auto_processing_orders( $order_id ) {
if ( ! $order_id )
return;
$order = wc_get_order( $order_id );
// If order is "on-hold" update status to "processing-melle"
if( $order->get_payment_method() == 'stripe_sofort' && $order->has_status( 'on-hold' ) ) {
$order->update_status( 'my_status' );
}
}
this code does not work, but I actually don't understand why. do you guys have an idea?
thanks!

How to automatically change woocommerce processing status to completed

How to change in woocommerce order status from processing to completed
?
I found snippet, but it only changes status if you go to thank you page, but if my customer decides just to close paypal page and don't go to thank you page ?
Then it is still processing, tested it already. I need automatically to detect processing status and change it to processing.
This will check for when the order changes status. If the status changes to processing, it will set the status to completed. Note that it does go through processing, so the user will probably get two emails back to back. You can disable one of the emails in the WC settings dashboard.
function wc_status_change($order_id,$old_status,$new_status) {
$order = new WC_Order( $order_id );
if($order->status == 'processing'){
$order->update_status('completed');
}
}
In your case you have two options the first may not work as it is related to previous versions of woocommerce but the second one should work
add the code to your functions.php
1º
add_filter( 'woocommerce_payment_complete_order_status', 'update_order_status_woo', 10, 2 );
function update_order_status_woo( $order_status, $order_id ) {
$order = new WC_Order( $order_id );
if ( $order_status == 'processing' && ( 'on-hold' == $order->status || 'pending' == $order->status || 'failed' == $order->status ) ) {
return 'completed';
}
return $order_status;
}
2º
add_action('woocommerce_order_status_changed', 'auto_update_processing_to_complete');
function auto_update_processing_to_complete($order_id)
{
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
if ($order->data['status'] == 'processing') {
$order->update_status( 'completed' );
}
}

Change Status of Order to Confirmed without Sending Confirmation Email when Updating Via Custom Bulk Action Handler

Need a bulk status update to Orders to change from On Hold to Completed but without sending confirmation emails. However, still need to retain the email functionality. This would be a new custom bulk action in addition to the standard WooCommerce bulk action to update to Completed (which still would send the confirmation emails). I have the extra option added with no problem but can't find a method that will preclude the email notification or a way to temporarily disable email notifications (which doesn't sound like a good approach anyway).
So far code is as below. Everything is fine except the $order->update_status('completed') triggers the confirmation email.
Have tried using set_status() but that produces the same result (update_status calls set_status).
/*
* Custom bulk action in dropdown - Change status to completed without sending Confirmation Email
*/
add_filter( 'bulk_actions-edit-shop_order', 'register_bulk_action' ); // edit-shop_order is the screen ID of the orders page
function register_bulk_action( $bulk_actions ) {
$bulk_actions['complete_with_no_email'] = 'Change status to completed (no confirmation emails)';
return $bulk_actions;
}
/*
* Bulk action handler
*/
add_action( 'admin_action_complete_with_no_email', 'bulk_process_custom_status' ); // admin_action_{action name}
function bulk_process_custom_status() {
// if an array with order IDs is not presented, exit the function
if( !isset( $_REQUEST['post'] ) && !is_array( $_REQUEST['post'] ) )
return;
// New order emails
foreach( $_REQUEST['post'] as $order_id ) {
$order = new WC_Order( $order_id );
$order_note = 'Changed Status to Completed via bulk edit (no confirmation email)';
$order->update_status('completed', $order_note); //STILL SENDS EMAIL
}
// of course using add_query_arg() is not required, you can build your URL inline
$location = add_query_arg( array(
'post_type' => 'shop_order',
'changed' => count( $_REQUEST['post'] ), // number of changed orders
'ids' => join( $_REQUEST['post'], ',' ),
'marked_fulfilled_no_emails' => 1,
'post_status' => 'all'
), 'edit.php' );
wp_redirect( admin_url( $location ) );
exit;
}
/*
* Notices for Bulk Action
*/
add_action('admin_notices', 'custom_order_status_notices');
function custom_order_status_notices() {
global $pagenow, $typenow;
if( $typenow == 'shop_order'
&& $pagenow == 'edit.php'
&& isset( $_REQUEST['marked_fulfilled_no_emails'] )
&& $_REQUEST['marked_fulfilled_no_emails'] == 1
&& isset( $_REQUEST['changed'] ) ) {
$message = sprintf( _n( 'Order status changed.', '%s order statuses changed.', $_REQUEST['changed'] ), number_format_i18n( $_REQUEST['changed'] ) );
echo "<div class=\"updated\"><p>{$message}</p></div>";
}
}
Wanting to avoid triggering confirmation emails when using a custom bulk edit option from orders.
The best way I found to solve this was to add a flag using update_post_meta when looping through the selected orders flagging them to bypass the email confirmation.This, together with a function that hooks into woocommerce_email_recipient_customer_completed_order to return nothing for those that have been flagged and at the same time removing the flag so that all other functionality still triggers the email confirmation as normal afterwards. The relevant functions here:
Add the hook to add a new option for bulk editing:
/*
* Custom bulk action in dropdown - Change status to completed without sending Confirmation Email
*/
add_filter( 'bulk_actions-edit-shop_order', 'register_bulk_action' ); // edit-shop_order is the screen ID of the orders page
function register_bulk_action( $bulk_actions ) {
$bulk_actions['complete_with_no_email'] = 'Change status to completed (no confirmation emails)';
return $bulk_actions;
}
Handle this new option here, making sure to flag each of the selected posts with update_user_meta so we can avoid emailing them
/*
* Bulk action handler
* admin_action_{action name}
*/
add_action( 'admin_action_complete_with_no_email', 'bulk_process_complete_no_email' );
function bulk_process_complete_no_email() {
// if an array with order IDs is not presented, exit the function
if( !isset( $_REQUEST['post'] ) && !is_array( $_REQUEST['post'] ) )
return;
// Loop through selected posts
foreach( $_REQUEST['post'] as $order_id ) {
// Use this flag later to avoid sending emails via hook woocommerce_email_recipient_customer_completed_order
update_post_meta($order_id, 'bypass_email_confirmation', true);
$order = new WC_Order( $order_id );
$order_note = 'Changed Status to Completed via bulk edit (no confirmation email)';
$order->update_status('completed', $order_note);
}
// of course using add_query_arg() is not required, you can build your URL inline
$location = add_query_arg( array(
'post_type' => 'shop_order',
'changed' => count( $_REQUEST['post'] ), // number of changed orders
'ids' => join( $_REQUEST['post'], ',' ),
'marked_fulfilled_no_emails' => 1,
'post_status' => 'all'
), 'edit.php' );
wp_redirect( admin_url( $location ) );
exit;
}
This just adds a notice after the bulk action is completed
/*
* Notices for the Bulk Action
* This just adds the notice after action has completed
*/
add_action('admin_notices', 'custom_order_status_notices');
function custom_order_status_notices() {
global $pagenow, $typenow;
if( $typenow == 'shop_order'
&& $pagenow == 'edit.php'
&& isset( $_REQUEST['marked_fulfilled_no_emails'] )
&& $_REQUEST['marked_fulfilled_no_emails'] == 1
&& isset( $_REQUEST['changed'] ) ) {
$message = sprintf( _n( 'Order status changed.', '%s order statuses changed.', $_REQUEST['changed'] ), number_format_i18n( $_REQUEST['changed'] ) );
echo "<div class=\"updated\"><p>{$message}</p></div>";
}
}
Finally, hook into every time the site is going to send a confirmation email and prevent it from doing so when the flag is present. Importantly, remove the flag here as well so only our bulk action above will prevent the confirmation email.
/*
* Hook into every time the site is going to email customer and stop it if the flag is present
*/
add_filter('woocommerce_email_recipient_customer_completed_order','handle_email_recipient_completed_order', 10, 2);
function handle_email_recipient_completed_order($recipient, $order) {
//if notifications are disabled (e.g. by bulk_process_complete_no_email)
$notifications_disabled = get_post_meta($order->get_id(), 'bypass_email_confirmation', true);
if ($notifications_disabled) {
update_post_meta($order->get_id(), 'bypass_email_confirmation', false);
return '';
} else {
return $recipient;
}
}
Hopefully this helps someone, I spent quite a while trying to find an answer to this particular question and couldn't find it elsewhere.

WooCommerce order-received redirect based on payment method

Usually in WooCommerce submitted orders are redirect to /order-received/ once payment is completed.
Is it possible to redirect customer to a custom page for a particular payment method?
For example:
Payment method 1 -> /order-received/
Payment method 2 -> /custom-page/
Payment method 3 -> /order-received/
With a custom function hooked in template_redirect action hook using the conditional function is_wc_endpoint_url() and targeting your desired payment method to redirect customer to a specific page:
add_action( 'template_redirect', 'thankyou_custom_payment_redirect');
function thankyou_custom_payment_redirect(){
if ( is_wc_endpoint_url( 'order-received' ) ) {
global $wp;
// Get the order ID
$order_id = intval( str_replace( 'checkout/order-received/', '', $wp->request ) );
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
// Set HERE your Payment Gateway ID
if( $order->get_payment_method() == 'cheque' ){
// Set HERE your custom URL path
wp_redirect( home_url( '/custom-page/' ) );
exit(); // always exit
}
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works.
How to get the Payment Gateway ID (WC settings > Checkout tab):
A small correction.
"exit" needs to be within the last condition
add_action( 'template_redirect', 'thankyou_custom_payment_redirect');
function thankyou_custom_payment_redirect(){
if ( is_wc_endpoint_url( 'order-received' ) ) {
global $wp;
// Get the order ID
$order_id = intval( str_replace( 'checkout/order-received/', '', $wp->request ) );
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
// Set HERE your Payment Gateway ID
if( $order->get_payment_method() == 'cheque' ){
// Set HERE your custom URL path
wp_redirect( home_url( '/custom-page/' ) );
exit(); // always exit
}
}
}

Avoid repetitive emails notification on some auto completed orders

I'm using this little peace of code on WooCommerce from this answer to auto-complete paid processing orders based on payment gateways:
/**
* AUTO COMPLETE PAID ORDERS IN WOOCOMMERCE
*/
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_paid_order', 10, 1 );
function custom_woocommerce_auto_complete_paid_order( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
// No updated status for orders delivered with Bank wire, Cash on delivery and Cheque payment methods.
if ( ( get_post_meta($order->id, '_payment_method', true) == 'bacs' ) || ( get_post_meta($order->id, '_payment_method', true) == 'cod' ) || ( get_post_meta($order->id, '_payment_method', true) == 'cheque' ) ) {
return;
}
// "completed" updated status for paid Orders with all others payment methods
else {
$order->update_status( 'completed' );
}
}
This is working mostly perfect
Mainly using a special payment gateway by SMS which API is bridged on 'cod' payment method and that can process payment after 'woocommerce_thankyou, out side frontend. In that case the ON HOLD status orders are passed afterward to PROCESSING status. To automate an autocomplete behavior on those cases, I use this other peace of code from this answer and it works:
function auto_update_orders_status_from_processing_to_completed(){
// Get all current "processing" customer orders
$processing_orders = wc_get_orders( $args = array(
'numberposts' => -1,
'post_status' => 'wc-processing',
) );
if(!empty($processing_orders))
foreach($processing_orders as $order)
$order->update_status( 'completed' );
}
add_action( 'init', 'auto_update_orders_status_from_processing_to_completed' );
THE PROBLEM: I am getting repetitive emails notifications concerning the new completed orders.
How can I avoid this repetitive email notifications cases?
Thanks
Updated (2019)
Added version code for Woocommerce 3+ - Added Woocommerce version compatibility.
To avoid this strange fact of repetitive email notifications, is possible to create a custom meta key/value for each processed order, when changing order status to completed, using WordPress update_post_meta() function. Then we will test before in a condition, if this custom meta data key/value exist with get_post_meta() function for each processed order.
So your two code snippets will be now:
1) AUTO COMPLETE PAID ORDERS IN WOOCOMMERCE (2019 update)
For woocommerce 3+:
add_action( 'woocommerce_payment_complete_order_status', 'wc_auto_complete_paid_order', 10, 3 );
function wc_auto_complete_paid_order( $status, $order_id, $order ) {
if ( ! $order->has_status('completed') && $order->get_meta('_order_processed') != 'yes') {
$order->update_meta_data('_order_processed', 'yes');
$status = 'completed';
}
return $status;
}
For all woocommerce versions (compatibility since version 2.5+):
add_action( 'woocommerce_payment_complete_order_status', 'wc_auto_complete_paid_order', 10, 3 );
function wc_auto_complete_paid_order( $status, $order_id, $order = null ) {
// Getting the custom meta value regarding this autocomplete status process
$order_processed = get_post_meta( $order_id, '_order_processed', true );
// Getting the WC_Order object from the order ID
$order = wc_get_order( $order_id );
if ( ! $order->has_status( 'completed' ) && $order_processed != 'yes' ) {
$order = wc_get_order( $order_id );
// setting the custom meta data value to yes (order updated)
update_post_meta($order_id, '_order_processed', 'yes');
$order->update_status( 'completed' ); // Update order status to
}
return $status;
}
2) SCAN ALL "processing" orders to auto-complete them (added Woocommerce compatibility)
add_action( 'init', 'auto_update_orders_status_from_processing_to_completed' );
function auto_update_orders_status_from_processing_to_completed(){
if( version_compare( WC_VERSION, '3.0', '<' ) {
$args = array('numberposts' => -1, 'post_status' => 'wc-processing'); // Before WooCommerce version 3
} else {
$args = array('limit' => -1, 'status' => 'processing'); // For WooCommerce 3 and above
}
// Get all current "processing" customer orders
$processing_orders = (array) wc_get_orders( $args );
if( sizeof($processing_orders) > 0 ){
foreach($processing_orders as $order ) {
// Woocommerce compatibility
$order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;
// Checking if this custom field value is set in the order meta data
$order_processed = get_post_meta( $order_id, '_order_processed', true );
if (! $order->has_status( 'completed' ) && $order_processed != 'yes' ) {
// Setting (updating) custom meta value in the order metadata to avoid repetitions
update_post_meta( $order_id, '_order_processed', 'yes' );
$order->update_status( 'completed' ); // Updating order status
}
}
}
}
Code goes in function.php file of your active child theme (or theme). Or also in any plugin php files.
I have test this code and it should work for you (due to your particular SMS bridged payment method)

Categories