I've used the following code which works fine, it makes all orders default status to be on hold.
/**
* Auto Complete all WooCommerce orders.
*/
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_order' );
function custom_woocommerce_auto_complete_order( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
$order->update_status( 'on-hold' );
}
But I need to combine this with shipping/billing address. i.e. execute this code Only if the order's shipping or billing address is NOT UK or France. Customers from all other countries will be placed on hold as per this code, while UK & France orders get the default order status set by the payment geteway's settings.
Any help will be much appreciated.
Try the following to exclude France and UK billing and shipping countries:
add_action( 'woocommerce_thankyou', 'country_based_auto_on_hold_orders' );
function country_based_auto_on_hold_orders( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
if ( ! ( in_array( $order->get_billing_country(), ['UK', 'FR'] ) || in_array( $order->get_shipping_country(), ['UK', 'FR'] ) ) ) {
$order->update_status( 'on-hold' );
}
}
Now using woocommerce_thankyou hook, is the old way. To avoid multiple email notifications on status changes, use the following instead:
For all payment gateways except Cash on delivery (COD):
add_action( 'woocommerce_payment_complete_order_status', 'wc_auto_on_old_paid_order', 10, 3 );
function wc_auto_on_old_paid_order( $status, $order_id, $order ) {
if ( ! ( in_array( $order->get_billing_country(), ['UK', 'FR'] ) || in_array( $order->get_shipping_country(), ['UK', 'FR'] ) ) ) {
$status = 'on-hold'
}
return $status;
}
For Cash on delivery (COD) payments:
add_action( 'woocommerce_cod_process_payment_order_status', 'wc_auto_complete_cod_order', 10, 2 );
function wc_auto_complete_cod_order( $status, $order ) {
if ( ! ( in_array( $order->get_billing_country(), ['UK', 'FR'] ) || in_array( $order->get_shipping_country(), ['UK', 'FR'] ) ) ) {
$status = 'on-hold'
}
return $status;
}
Related: WooCommerce: Auto complete paid orders
Related
I'm using a plugin on my WooCommerce site called Codisto. The purpose of the plugin is to consolidate orders from sales channels such as Amazon and eBay into my WooCommerce dashboard for better visibility and order management.
Upon order import into my WooCommerce dashboard I would like my Amazon orders to automatically be assigned a status of "Amazon". I have created the custom status however have been unable to properly code a solution that can correctly recognize the order and auto assign the custom status.
Here is my code:
if ( 'processing' && ( 'on-hold' === $order->status || 'pending' === $order->status || 'failed' === $order->status ) ) {
$has_amazon_order = false;
foreach ( $order->get_order_id() as $order_id ) {
$order = $order_id->get_order_id();
$amazon_order = get_post_meta( $order_id, '_codisto_amazonorderid', true );
if ( $amazon_order == 'yes' ) {
$has_amazon_order = true;
break;
}
}
if ( $has_amazon_order == 'yes' ) {
$status = 'amazon';
}
}
return $status;
}
add_action( 'woocommerce_payment_complete_order_status', 'rb_wc_set_amazon_order_status_on_import', 20, 3 );
I've been looking at the developer's code and I believe the function is related to the $amazonorderid and $createdby param as referenced here:
if ( ! $order_id ) {
$new_order_data_callback = array( $this, 'order_set_date' );
add_filter( 'woocommerce_new_order_data', $new_order_data_callback, 1, 1 );
$createdby = 'eBay';
if ( $amazonorderid ) {
$createdby = 'Amazon';
}
$order = wc_create_order( array( 'customer_id' => $customer_id, 'customer_note' => $customer_note, 'created_via' => $createdby ) );
remove_filter( 'woocommerce_new_order_data', $new_order_data_callback );
$order_id = $order->get_id();
update_post_meta( $order_id, '_codisto_orderid', (int)$ordercontent->orderid );
update_post_meta( $order_id, '_codisto_merchantid', (int)$ordercontent->merchantid );
if ( $amazonorderid ) {
update_post_meta( $order_id, '_codisto_amazonorderid', $amazonorderid );
Any and all suggestions are greatly appreciated!
I have two scripts that are interfering with each other. What I need for this website is that: all successful purchases should go to page https://aefcoaching.com/gracias-por-tu-compra, except successful purchase of Product ID 1813, which should go to https://aefcoaching.com/gracias-gimnasio-mental/
/* # Redirect to the Thank You page after successful payment in WooCommerce */
if( !function_exists('sc_custom_redirect_after_purchase') ):
function sc_custom_redirect_after_purchase() {
global $wp;
if ( is_checkout() && !empty($wp->query_vars['order-received']) ) :
$order_id = absint($wp->query_vars['order-received']);
$order_key = wc_clean($_GET['key']);
$th_page_url = 'https://aefcoaching.com/gracias-por-tu-compra';
$redirect = add_query_arg(
array(
'order' => $order_id,
'key' => $order_key,
), $th_page_url);
wp_safe_redirect($redirect);
exit;
endif;
}
add_action('template_redirect', 'sc_custom_redirect_after_purchase');
endif;
/* # Redirect Gimnasio Mental purchases to a specific Thank You Page */
function action_woocommerce_thankyou( $order_id ) {
if( ! $order_id ) {
return;
}
// Instannce of the WC_Order Object
$order = wc_get_order( $order_id );
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// False
$redirection = false;
// Loop through order items
foreach ( $order->get_items() as $item_key => $item ) {
// Product ID(s)
$product_ids = array( $item->get_product_id(), $item->get_variation_id() );
// Product ID in array
if ( in_array( 1813, $product_ids ) ) {
$redirection = true;
}
}
}
// Make the custom redirection when a targeted product has been found in the order
if ( $redirection ) {
wp_safe_redirect( home_url( '/gracias-gimnasio-mental/' ) );
exit;
}
}
add_action( 'woocommerce_thankyou', 'action_woocommerce_thankyou', 10, 1 );
The first piece works great. The second doesn't because of the first one. I'm not sure how to integrate these two rather than have 2 separate codes. Can you help me?
Please merge the two logics into one , by changing your sc_custom_redirect_after_purchase function into the following:
function sc_custom_redirect_after_purchase() {
global $wp;
if ( is_checkout() && !empty($wp->query_vars['order-received']) ) :
$order_id = absint($wp->query_vars['order-received']);
$order_key = wc_clean($_GET['key']);
$th_page_url = 'https://aefcoaching.com/gracias-por-tu-compra';
//////////////////////
$order = wc_get_order( $order_id );
foreach ( $order->get_items() as $item_key => $item ) {
// Product ID(s)
$product_ids = array( $item->get_product_id(), $item->get_variation_id() );
// Product ID in array
if ( in_array( 1813, $product_ids ) ) {
// $redirection = true;
$th_page_url = 'https://aefcoaching.com/gracias-gimnasio-mental/';
}
}
/////////////////////
$redirect = add_query_arg(
array(
'order' => $order_id,
'key' => $order_key,
), $th_page_url);
wp_safe_redirect($redirect);
exit;
endif;
}
One of my products requires a specific thank you page.
Here's the code I have. The Product ID is 1813 and the category is gimnasio-mental. I don't really need, nor want to include the category in this code, so if it can be simplified, even better!
add_action( 'template_redirect', 'wc_custom_redirect_after_purchase' );
function wc_custom_redirect_after_purchase() {
if ( ! is_wc_endpoint_url( 'order-received' ) ) return;
// Define the product IDs in this array
$product_ids = array( 1813 ); // or an empty array if not used
// Define the product categories (can be IDs, slugs or names)
$product_categories = array( 'gimnasio-mental' ); // or an empty array if not used
$redirection = false;
global $wp;
$order_id = intval( str_replace( 'checkout/order-received/', '', $wp->request ) ); // Order ID
$order = wc_get_order( $order_id ); // Get an instance of the WC_Order Object
// Iterating through order items and finding targeted products
foreach( $order->get_items() as $item ){
if( in_array( $item->get_product_id(), $product_ids ) || has_term( $product_categories, 'product_cat', $item->get_product_id() ) ) {
$redirection = true;
break;
}
}
// Make the custom redirection when a targeted product has been found in the order
if( $redirection ){
wp_redirect( home_url( '/gracias-gimnasio-mental/' ) );
exit;
}
}
You could use the woocommerce_thankyou action hook against template_redirect
Explanation via comment tags added in the code
function action_woocommerce_thankyou( $order_id ) {
if( ! $order_id ) {
return;
}
// Instannce of the WC_Order Object
$order = wc_get_order( $order_id );
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// False
$redirection = false;
// Loop through order items
foreach ( $order->get_items() as $item_key => $item ) {
// Product ID(s)
$product_ids = array( $item->get_product_id(), $item->get_variation_id() );
// Product ID in array
if ( in_array( 1813, $product_ids ) ) {
$redirection = true;
}
}
}
// Make the custom redirection when a targeted product has been found in the order
if ( $redirection ) {
wp_safe_redirect( home_url( '/gracias-gimnasio-mental/' ) );
exit;
}
}
add_action( 'woocommerce_thankyou', 'action_woocommerce_thankyou', 10, 1 );
I ran into an issue in WooCommerce and I'm wondering if anyone else has experienced it too.
I sell certain products that are too fragile to be shipped by UPS/DHL/FedEx. So I have to ship these products via pallet. To solve my problem I created a "request a quote" shipping method that allows my customers to select BACS as the payment method, request a quote as the shipping method and submit their orders. And after I have calculated the shipping costs, I update the order (change the shipping method to N/A) and change the status from "on-hold" to "pending payment" to allow the customer to pay by card if they wish to.
This is where I ran into the issue. I noticed that if I unset several payment gateways and if these certain shipping methods are selected, these payment gateways are not available to the customer in the "order-pay" endpoint (website/my-account/orders/) even if I remove the shipping method from the order.
Is there a way around this?
This is the code I am using to Disable Payment Gateway For Specific Shipping Method.
add_filter( 'woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1 );
function filter_woocommerce_available_payment_gateways( $available_gateways ) {
$gateways_to_disable = array( 'cardgatecreditcard', 'cardgategiropay', 'cardgateideal', 'cardgatesofortbanking' );
$shipping_methods = array( 'flat_rate', 'request_shipping_quote' );
$disable_gateways = false;
// Check if we need to disable gateways
foreach ( $shipping_methods as $shipping_method ) {
if ( strpos( WC()->session->get( 'chosen_shipping_methods' )[0], $shipping_method ) !== false ) $disable_gateways = true;
}
// If so, disable the gateways
if ( $disable_gateways ) {
foreach ( $available_gateways as $id => $gateway ) {
if ( in_array( $id, $gateways_to_disable ) ) {
unset( $available_gateways[$id] );
}
}
}
return $available_gateways;
}
UPDATE After consulting with a few developers they advised that this code runs every time Payment Gateways are required and suggested that I run this snippet only on the Checkout page.
They suggested adding the following to my code:
if ( is_checkout_pay_page() ) {
// unset Payment Gateways
}
SOLVED Here's my attempt and it works. But not sure if it can we expressed better:
add_filter( 'woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1 );
function filter_woocommerce_available_payment_gateways( $available_gateways ) {
if ( ! ( is_checkout_pay_page() ) ) {
$gateways_to_disable = array( 'cardgatecreditcard', 'cardgategiropay', 'cardgateideal', 'cardgatesofortbanking' );
$shipping_methods = array( 'flat_rate', 'request_shipping_quote' );
$disable_gateways = false;
// Check if we need to disable gateways
foreach ( $shipping_methods as $shipping_method ) {
if ( strpos( WC()->session->get( 'chosen_shipping_methods' )[0], $shipping_method ) !== false ) $disable_gateways = true;
}
// If so, disable the gateways
if ( $disable_gateways ) {
foreach ( $available_gateways as $id => $gateway ) {
if ( in_array( $id, $gateways_to_disable ) ) {
unset( $available_gateways[$id] );
}
}
}
return $available_gateways;
}
else { return $available_gateways;
}
}
add_filter( 'woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1 );
function filter_woocommerce_available_payment_gateways( $available_gateways ) {
if ( ! ( is_checkout_pay_page() ) ) {
$gateways_to_disable = array( 'paymentgateway1', 'paymentgateway2', 'paymentgateway3' );
$shipping_methods = array( 'shippingmethod1', 'shippingmethod2', 'shippingmethod3' );
$disable_gateways = false;
// Check if we need to disable gateways
foreach ( $shipping_methods as $shipping_method ) {
if ( strpos( WC()->session->get( 'chosen_shipping_methods' )[0], $shipping_method ) !== false ) $disable_gateways = true;
}
// If so, disable the gateways
if ( $disable_gateways ) {
foreach ( $available_gateways as $id => $gateway ) {
if ( in_array( $id, $gateways_to_disable ) ) {
unset( $available_gateways[$id] );
}
}
}
return $available_gateways;
}
else { return $available_gateways;
}
}
How do I change the order status from on hold to my own custom status for a specific shipping method if the selected payment gateway is BACS?
This is how I added my own custom status:
// Register New Order Status
add_filter( 'woocommerce_register_shop_order_post_statuses', 'register_custom_order_status' );
function register_custom_order_status( $order_statuses ){
// Status must start with "wc-"
$order_statuses['wc-custom-status'] = array(
'label' => _x( 'Calculating Shipping', 'Order status', 'woocommerce' ),
'public' => false,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop( 'Calculating Shipping <span class="count">(%s)</span>', 'Calculating Shipping <span class="count">(%s)</span>', 'woocommerce' ),
);
return $order_statuses;
}
// Show Order Status in the Dropdown # Single Order and "Bulk Actions" # Orders
add_filter( 'wc_order_statuses', 'show_custom_order_status' );
function show_custom_order_status( $order_statuses ) {
$order_statuses['wc-custom-status'] = _x( 'Calculating Shipping', 'Order status', 'woocommerce' );
return $order_statuses;
}
add_filter( 'bulk_actions-edit-shop_order', 'get_custom_order_status_bulk' );
function get_custom_order_status_bulk( $bulk_actions ) {
// Note: "mark_" must be there instead of "wc"
$bulk_actions['mark_custom-status'] = 'Change status to calculating shipping';
return $bulk_actions;
}
This solution was inspired by WooCommerce change BACS order status based on user roles seems to work but it changes the order status for shipping methods not specified here:
function bacs_order_payment_pending_order_status_shipping_method( $order_id ) {
// Get $order object
$order = wc_get_order( $order_id );
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Get shipping method
$shipping_method = $order->get_shipping_methods();
// Shipping Methods
$methods = (array) $shipping_method;
// Shipping Methods to check
$shipping_methods_to_check = array( 'flat_rate', 'request_shipping_quote' );
// Compare
$compare = array_diff( $methods, $shipping_methods_to_check );
// Result is empty
if ( empty ( $compare ) ) {
if ( $order->get_payment_method() == 'bacs' && $order->has_status( 'on-hold' ) ) {
$order->update_status( 'custom-status' );
}
}
}
}
add_action( 'woocommerce_thankyou', 'bacs_order_payment_pending_order_status_shipping_method', 10, 1 );
The answer code from Change Woocommerce Order Status based on Shipping Method also works but I would like to specify several shipping methods.
UPDATE: In case you want to include logic to set another order status if the shipping methods are not found:
add_action( 'woocommerce_thankyou', 'bacs_order_payment_pending_order_status_shipping_method', 10, 1 );
function bacs_order_payment_pending_order_status_shipping_method( $order_id ) {
// Get WC_Order object from the order Id
$order = wc_get_order( $order_id );
// Check that we get a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Shipping Methods to check
$shipping_methods_to_check = array( 'flat_rate', 'request_shipping_quote' );
$condition = $order->get_payment_method() == 'bacs' && $order->has_status( 'on-hold' );
// Loop through shipping items (objects)
foreach($order->get_shipping_methods() as $shipping_item ){
// Check for matched defined shipping methods
if( in_array( $shipping_item->get_method_id(), $shipping_methods_to_check ) && $condition ){
$order->update_status( 'custom-status' ); // Change Order Status Custom
}
else {$order->update_status( 'pending' ); // Change Order Status Pending
}
}
}
}
Try the following instead (code is commented):
add_action( 'woocommerce_thankyou', 'bacs_order_payment_pending_order_status_shipping_method', 10, 1 );
function bacs_order_payment_pending_order_status_shipping_method( $order_id ) {
// Get WC_Order object from the order Id
$order = wc_get_order( $order_id );
// Check that we get a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Shipping Methods to check
$shipping_methods_to_check = array( 'flat_rate', 'request_shipping_quote' );
$condition = $order->get_payment_method() == 'bacs' && $order->has_status( 'on-hold' );
// Loop through shipping items (objects)
foreach($order->get_shipping_methods() as $shipping_item ){
// Check for matched defined shipping methods
if( in_array( $shipping_item->get_method_id(), $shipping_methods_to_check ) && $condition ){
$order->update_status( 'custom-status' ); // Change order status
return; // Exit
}
}
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
related: Change Woocommerce Order Status based on Shipping Method