How can I redirect back to the /cart after I click the 'Undo' link when I delete an item from it?
I am not concerned if the cart is empty or not. I had to implement a template_redirect already, so when a user "removes" an item from the cart it redirects back to the cart rather than the home page. With:
add_action( 'template_redirect', function( ) {
$_var = ( $_GET[ 'removed_item' ] ) ?? null;
//var_dump($_var);
if( $_var == '1' ){
wp_safe_redirect( '/cart', 301 );
die();
}
} );
Can I hook into the same action? I don't see a query string after clicking the 'Undo' tho...
EDIT
I can see where the action is done. It's in the plugin includes/class-ws-form-handler.php, right around line 536... containing:
// Undo Cart Item
$cart_item_key = sanitize_text_field( $_GET['undo_item'] );
WC()->cart->restore_cart_item( $cart_item_key );
$referer = wp_get_referer() ? remove_query_arg( array( 'undo_item', '_wpnonce' ), wp_get_referer() ) : wc_get_cart_url();
wp_safe_redirect( $referer );
exit;
EDIT 2:
Adding the following to my redirection above does nothing...
// undo the remove, redirect back to cart
if ( ! empty( $_GET['undo_item'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cart' ) ) {
// Undo Cart Item
$cart_item_key = sanitize_text_field( $_GET['undo_item'] );
WC()->cart->restore_cart_item( $cart_item_key );
wp_safe_redirect( wc_get_cart_url() );
exit;
}
So, when I var_dump wp_get_referer() I get back the home page of the site, which is not what I am looking for. I do not want to modify this file due to that not being that great of an idea... so, how can I just modify the action instead? The function itself is: public static function update_cart_action()
So... I ended up have to do some voodoo to get this to work.
Here is the hook...
// undo the remove, redirect back to cart
// check if the cart is updated... if it is, proceed
$_cu = apply_filters( 'woocommerce_update_cart_action_cart_updated', true );
if( $_cu ) {
global $woocommerce;
if ( ! empty( $_GET['undo_item'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cart' ) ) {
// item
$cart_item_key = sanitize_text_field( $_GET['undo_item'] );
// Get the cart
$woocommerce->cart->get_cart();
// restore the item
$woocommerce->cart->restore_cart_item( $cart_item_key );
// now do the redirect
wp_safe_redirect( wc_get_cart_url() );
exit;
}
}
It is applied in the init event
Related
What code should I add to functions.php to remove "Checkout is not available whilst your cart is empty." notice in Woocommerce.
I found the code in includes/wc-template-functions.php that is responsible for displaying this message.
// When on the checkout with an empty cart, redirect to cart page.
if ( is_page( wc_get_page_id( 'checkout' ) ) && wc_get_page_id( 'checkout' ) !== wc_get_page_id( 'cart' ) && WC()->cart->is_empty() && empty( $wp->query_vars['order-pay'] ) && ! isset( $wp->query_vars['order-received'] ) && ! is_customize_preview() && apply_filters( 'woocommerce_checkout_redirect_empty_cart', true ) ) {
wc_add_notice( __( 'Checkout is not available whilst your cart is empty.', 'woocommerce' ), 'notice' );
wp_safe_redirect( wc_get_cart_url() );
exit;
}
Overwriting the core file is NOT an option, any advice?
You can use the woocommerce_checkout_redirect_empty_cart filter hook. Since the message is only displayed if this condition is true
add_filter( 'woocommerce_checkout_redirect_empty_cart', '__return_false' );
Another option is to use the woocommerce_add_notice filter hook and if the message matches, return false
function filter_woocommerce_add_notice ( $message ) {
// Equal to (Must be exactly the same).
// If the message is displayed in another language, adjust where necessary!
if ( $message == 'Checkout is not available whilst your cart is empty.' ) {
return false;
}
return $message;
}
add_filter( 'woocommerce_add_notice', 'filter_woocommerce_add_notice', 10, 1 );
I am trying to prevent access to the checkout page when there are no shipping options available. I have disabled the "proceed to checkout' button but want to prevent the customer from directly accessing the checkout page. I have tried this snippet which works in terms of preventing the access, however if a customer DOES have a valid shipping option the success message is replaced by the cart page which now of course has nothing in it and informs the customer their cart is empty so they try an re-order again.
Any help gratefully welcome.
function prevent_checkout_access_no_shipping() {
// Check that WC is enabled and loaded
if( function_exists( 'is_checkout' ) && is_checkout() ) {
// get shipping packages and their rate counts
$packages = WC()->cart->get_shipping_packages();
foreach( $packages as $key => $pkg ) {
$calculate_shipping = WC()->shipping->calculate_shipping_for_package( $pkg );
if( empty( $calculate_shipping['rates'] ) ) {
wp_redirect( esc_url( WC()->cart->get_cart_url() ) );
exit;
}
}
}
}
add_action( 'wp', 'prevent_checkout_access_no_shipping' );
You can try this below code. In your code, you redirect after the first empty shipping rate
function prevent_checkout_access_no_shipping() {
// Check that WC is enabled and loaded
if( function_exists( 'is_checkout' ) && is_checkout() ) {
$packages_valid = 0;
// get shipping packages and their rate counts
$packages = WC()->cart->get_shipping_packages();
foreach( $packages as $key => $pkg ) {
$calculate_shipping = WC()->shipping->calculate_shipping_for_package( $pkg );
if( !empty( $calculate_shipping['rates'] ) ) {
$packages_valid++;
}
}
if (!$packages_valid) {
wp_redirect( esc_url( WC()->cart->get_cart_url() ) , 302);
exit;
}
}
}
add_action( 'template_redirect', 'prevent_checkout_access_no_shipping' );
I have this code:
add_action('template_redirect', 'woo_custom_redirect');
function woo_custom_redirect( $redirect ) {
if (
! is_user_logged_in()
&& (is_checkout())
) {
wp_redirect( home_url( '/my-account/edit-account/' ) );
return $redirect;
}
}
How can I replace the redirection condition when I make an order to purchase a product from a certain category?
For example, if a user purchases a product from a certain category, then when he attempts to place an order, he redirects to registration and back, after successful registration.
The following code will redirect to my account page the non logged user in checkout page when they have an item from a specific product category. You will have to define in the code your specific product category:
add_action('template_redirect', 'woo_custom_redirect');
function woo_custom_redirect( $redirect ) {
// HERE set your product category (can be term IDs, slugs or names)
$category = 'posters';
$found = false;
// CHECK CART ITEMS: search for items from our product category
foreach ( WC()->cart->get_cart() as $cart_item ){
if( has_term( $category, 'product_cat', $cart_item['product_id'] ) ) {
$found = true;
break;
}
}
if ( ! is_user_logged_in() && is_checkout() && $found ) {
wp_redirect( get_permalink( get_option('woocommerce_myaccount_page_id') ) );
exit();
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
I needed to do this recently and this solution worked for me. This solution checks what product categories the items are in, in the order details once the order has been received. So the redirect will take place after payment has been made.
add_action( 'template_redirect', 'woocommerce_redirect_after_checkout' );
function woocommerce_redirect_after_checkout() {
global $wp;
if ( is_checkout() && ! empty( $wp->query_vars['order-received'] ) ) {
$order_id = absint( $wp->query_vars['order-received'] );
$order = wc_get_order( $order_id );
$prod_category = [CAT ID OR SLUG];
foreach( $order->get_items() as $item ) {
if( has_term( $prod_category, 'product_cat', $item['product_id'] ) ) {
// change below to the URL that you want to send your customer to
$redirect_url = 'https://www.example.com/custom-thank-you/';
wp_redirect($redirect_url );
exit;
}
}
}
}
I use Lirox One theme on Wordpress with WooCommerce. I want make custom redirections after payment:
If a customer buy product ID 333, It will be redirected to product 444 (for example).
I have make some custom code but it doesn't works, I get an error 500 (and debug is empty).
What I am doing wrong and how can I make it work?
This is my code:
add_action( 'woocommerce_thankyou', 'check_order_product_id', 1 );
function check_order_product_id( $order_id ){
$order = new WC_Order( $order_id );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item['product_id'];
//* single product id
if ( $product_id == 399 ) {
// Content Title line
$url = 'http://yoursite.com/custom-url1';
}
if ( $product_id == 358 ) {
$url = 'http://yoursite.com/custom-url2';
}
if ( $product_id == 398 ) {
$url = 'http://yoursite.com/custom-url3';
}
if ( $product_id == 357) {
$url = 'http://yoursite.com/custom-url5';
}
if ( $product_id == 356) {
$url = 'http://yoursite.com/custom-url6';
}
if ( $product_id == 335) {
$url = 'http://yoursite.com/custom-url';
}
if ( $order->status != 'failed' ) {
wp_redirect($url);
exit;
}
For redirections, use a custom function hooked in WordPress template_redirect action hook, to avoid errors 500…
I have changed your code as you will see, to match your requirements. This code is made for WooCommerce version 3+:
add_action( 'template_redirect', 'conditional_redirection_after_payment');
function conditional_redirection_after_payment(){
// When "thankyou" order-received page is reached …
if ( is_wc_endpoint_url( 'order-received' ) ) {
global $wp;
// Get the order ID from the browser url
$order_id = intval( str_replace( 'checkout/order-received/', '', $wp->request ) );
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
// If the order status is 'failed' we stop the function
if( $order->has_status( 'failed' ) ) return;
// HERE set in the array for each product ID the coresponding url final path
$product_id_url_paths = array(
'399' => '/custom-url1',
'358' => '/custom-url2',
'398' => '/custom-url3',
'357' => '/custom-url4',
'356' => '/custom-url5',
'335' => '/custom-url6',
);
// Iterating through each order items
foreach( $order->get_items() as $item_id => $item_values ){
// The Product ID
$product_id = $item_values->get_product_id();
foreach( $product_id_url_paths as $key_id => $url_path ){
if( $key_id == $product_id ){
// Product is found and ID match: we got our path url. We redirect
wp_redirect( home_url( $url_path ) );
exit(); // always exit
}
}
}
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Code is tested and works on WC 3+
Note: In your Code you have to remove the exit which you have used after the wp_redirect. Other all will work fine. Some more References are provided below in order to have better understanding of the Concept.
Explanation: Then you Provide Redirect only for the Particular Product
ID alone not For all the Product IDS since it may lead you to the
Internal Server Error as it is in the Foreach Loop.
It is Fine using wp_redirect() for the redirection purpose.
It is correct what have you checked for the Product ID. The Thing is that you have to follow another method if the URL are to be explicitly passed.
// We don't know for sure whether this is a URL for this site,
// so we use wp_safe_redirect() to avoid an open redirect.
wp_safe_redirect( $url );
// We are trying to redirect to another site, using a hard-coded URL.
wp_redirect( 'https://example.com/some/page' );
Some More Reference:
<?php wp_redirect( home_url() ); exit; ?>
Redirects can also be external, and/or use a “Moved Permanently” code :
<?php wp_redirect( 'http://www.example-one.com', 301 ); exit; ?>
The code below redirects to the parent post URL which can be used to redirect attachment pages back to the parent.
<?php wp_redirect( get_permalink( $post->post_parent ) ); exit; ?>
Reference: https://developer.wordpress.org/reference/functions/wp_redirect/
Th accepted answer works for Woocommerce 3+, for older versions (I'm using 2.6.4) it does not. For anyone else using this version, try the following code:
add_action( 'template_redirect', 'conditional_redirection_after_payment');
function conditional_redirection_after_payment(){
// When "thankyou" order-received page is reached …
if ( is_wc_endpoint_url( 'order-received' ) ) {
global $wp;
$order_id = intval( str_replace( 'checkout/order-received/', '', $wp->request ) );
// Get an instance of the WC_Order object
$order = new WC_Order( $order_id );
// If the order status is 'failed' we stop the function
if( $order->has_status( 'failed' ) ) return;
// HERE set in the array for each product ID the coresponding url final path
$product_id_url_paths = array(
'1234' => '/your-path/'
);
// Iterating through each order items
foreach( $order->get_items() as $item){
// echo $item_id;
// The Product ID
$product_id = $item['product_id'];
foreach( $product_id_url_paths as $key_id => $url_path ){
if( $key_id == $product_id ){
// Product is found and ID match: we got our path url. We redirect
wp_redirect( home_url( $url_path ) );
exit(); // always exit
}
}
}
}
}
I am overriding the AJAX function to add a product using WooCommerce so I can send attributes to the cart as well (which doesn't work out of the box).
I followed the instructions on Update WooCommerce Cart After Adding Variable Product Via AJAX - which does what I want - but it doesn't work completely.
Everything is good when I am logged out. But when I log into Wordpress the PHP override doesn't work/gets ignored. I get no errors and no product is added to the cart. I tried many different approaches, but nothing helps.
function ajax_add_to_cart_script() {
$vars = array( 'ajax_url' => admin_url( 'admin-ajax.php' ) );
wp_enqueue_script( 'wc-variation-add-to-cart', get_template_directory_uri() . '/js/jquery.add-to-cart.js', array( 'jquery' ), null, true);
wp_localize_script( 'wc-variation-add-to-cart', 'WC_VARIATION_ADD_TO_CART', $vars );
}
add_action( 'wp_enqueue_scripts', 'ajax_add_to_cart_script' );
add_action( 'wp_ajax_nopriv_woocommerce_add_variation_to_cart', 'so_27270880_add_variation_to_cart' );
function so_27270880_add_variation_to_cart() {
ob_start();
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
$quantity = empty( $_POST['quantity'] ) ? 1 : wc_stock_amount( $_POST['quantity'] );
$variation_id = isset( $_POST['variation_id'] ) ? absint( $_POST['variation_id'] ) : '';
$variations = ! empty( $_POST['variation'] ) ? (array) $_POST['variation'] : '';
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) {
do_action( 'woocommerce_ajax_added_to_cart', $product_id );
if ( get_option( 'woocommerce_cart_redirect_after_add' ) == 'yes' ) {
wc_add_to_cart_message( $product_id );
}
// Return fragments
WC_AJAX::get_refreshed_fragments();
} else {
// If there was an error adding to the cart, redirect to the product page to show any errors
$data = array(
'error' => true,
'product_url' => apply_filters( 'woocommerce_cart_redirect_after_error', get_permalink( $product_id ), $product_id )
);
wp_send_json( $data );
}
die();
}
I am making sure that add_action( 'wp_ajax_nopriv_woocommerce_add_variation_to_cart', 'so_27270880_add_variation_to_cart' ); is added before the snippet to make sure it gets fired, which works when I am logged out - but not when I am logged in.
Anyone got any clue why?
Ping #helgatheviking
An update, it seems to work if I add the following to my functions.php
add_action( 'wp_ajax_nopriv_woocommerce_add_variation_to_cart', 'so_27270880_add_variation_to_cart' );
add_action( 'wp_ajax_woocommerce_add_variation_to_cart', 'so_27270880_add_variation_to_cart' );
Meaning, that one is for logged in admins and one is for normal users. Not sure why I need both because every example I have seen with this kind of extension/override only mentions the wp_ajax_nopriv_$function
Hope this helps anyone who have the same problem as me. And if anyone could explain to me why this is needed, I would be happy to hear it.