Skip WooCommerce cart for specific subscription products - php

I wish to make multiple specific subscription products skip the cart and go straight to checkout. I found the following code here (only for one product), which skips it for one product using the product ID, but unable to adapt it for multiple products. Tried also various other methods, but none seem to work for Woocommerce 4.51
How to skip cart page on woocomerce for certain products only?
add_filter( 'woocommerce_add_to_cart_redirect', 'woo_redirect_checkout' );
function woo_redirect_checkout() {
global $woocommerce;
$desire_product = '73458';
//Get product ID
$product_id = (int) apply_filters( 'woocommerce_add_to_cart_product_id', $_POST['add-to-cart'] );
//Check if current product is subscription
if ( $product_id == $desire_product ){
$checkout_url = $woocommerce->cart->get_checkout_url();
return $checkout_url;
exit;
} else {
$cart_url = $woocommerce->cart->get_cart_url();
return $cart_url;
exit;
}
}

The woocommerce_add_to_cart_redirect filter gives you access to the product object of the product that was added to the cart. So you can check for the subscription product type:
add_filter( 'woocommerce_add_to_cart_redirect', 'woo_redirect_checkout', 10, 2 );
function woo_redirect_checkout( $url, $product ) {
return $product->get_type() == 'subscription' ? wc_get_checkout_url() : $url;
}
Now all products that are of type subscription get redirected to the checkout instead of the cart.
If you do not want all your subscription products to redirect to the checkout but only subscriptions in certain categories, you can first retrieve the product categories from the product object and see if they match one of the categories defined in the $checkout_cats array:
add_filter( 'woocommerce_add_to_cart_redirect', 'woo_redirect_checkout', 10, 2 );
function woo_redirect_checkout( $url, $product ) {
//Define your categories here
$checkout_cats = array( 'Music', 'Posters' );
if ( $product->get_type() == 'subscription' ) {
$terms = get_the_terms( $product->get_id(), 'product_cat' );
if ( !empty( $terms ) ) {
foreach ( $terms as $term ) {
if ( in_array( $term->name, $checkout_cats ) ) return wc_get_checkout_url();
}
}
}
return $url;
}

Related

WooCommerce after add to cart redirect to checkout

we are using WooCommerce Subscription and we want, that after a subscription is added to the cart redirect the customer to the checkout page. In the past I think there was a setting to set for this but I'm not able to find it. However, now I try to do it via code.
We use AJAX in order to add to the cart. But I think this will not work. And I have to disable ajax add to cart only for some products? Like check for a category?
So I have to disable ajax add to cart only for specific products and then redirect the customer when adding such a product to the cart to checkout. The code below works if I deactivate ajax add to cart for all products and also all product will redirect to the checkout. However, we only need it for specific products.
// redirect customer to checkout page
add_filter( 'woocommerce_add_to_cart_redirect', 'custom_skip_cart_redirect_checkout' );
function custom_skip_cart_redirect_checkout( $url ) {
return wc_get_checkout_url();
}
// Fix for “Sold Individually” Products
add_filter( 'woocommerce_product_add_to_cart_url', 'custom_fix_for_individual_products', 10, 2 );
function custom_fix_for_individual_products( $add_to_cart_url, $product ){
if( $product->get_sold_individually() // if individual product
&& WC()->cart->find_product_in_cart( WC()->cart->generate_cart_id( $product->id ) ) // if in the cart
&& $product->is_purchasable() // we also need these two conditions
&& $product->is_in_stock() ) {
$add_to_cart_url = wc_get_checkout_url();
}
return $add_to_cart_url;
}
// Remove “The product has been added to your cart” message
add_filter( 'wc_add_to_cart_message_html', 'custom_remove_add_to_cart_message' );
function custom_remove_add_to_cart_message( $message ){
return '';
}
Maybe it could help:
add_filter( 'woocommerce_add_to_cart_redirect', 'redirect_to_checkout_if_product_is_subscription', 99, 1 );
function redirect_to_checkout_if_product_is_subscription( $url ) {
if ( ! isset( $_REQUEST['add-to-cart'] ) ) {
return $url;
}
$product_id = intval( $_REQUEST['add-to-cart'] );
if ( $product_id <= 0 ) {
return $url;
}
$product = wc_get_product( $product_id );
if ( WC_Subscriptions_Product::is_subscription( $product ) ) {
$url = wc_get_checkout_url();
}
return $url;
}

WooCommerce Disallow ClearPay Payment for specific product categories

I am trying to disable ClearPay payment method for specific product categories.
I managed to hide the ClearPay options for the shop and product page, but it still allows me to use ClearPay in the cart.
This is the code I have used:
/**
* #param bool $bool_result
* #param WC_Product $product
*/
function clearpay_ips_callback( $bool_result, $product ) {
if( has_term( array( 18, 28 ), 'product_cat' ) ) {
// do something if current product in the loop is in product category with ID 18 or 25
$bool_result = false;
}
return $bool_result;
}
add_filter( 'clearpay_is_product_supported', 'clearpay_ips_callback', 10, 2 );
Can anyone help me to stop ClearPay being available in checkout if we have products that belong to specific product category term Ids
The product Id should be specified in has_term() like:
add_filter( 'clearpay_is_product_supported', 'clearpay_ips_callback', 10, 2 );
function clearpay_ips_callback( $bool_result, $product ) {
if( has_term( array( 18, 28 ), 'product_cat', product->get_id() ) ) {
return false;
}
return $bool_result;
}
You can also try the following for cart items on checkout page:
add_filter( 'woocommerce_available_payment_gateways', 'conditional_hiding_payment_gateway', 1, 1 );
function conditional_hiding_payment_gateway( $available_gateways ) {
// Not in backend (admin)
if( is_admin() )
return $available_gateways;
$is_in_cart = false;
// Iterating through each items in cart
foreach(WC()->cart->get_cart() as $item){
if( has_term( array( 18, 28 ), 'product_cat', $item['product_id'] ) ) {
$is_in_cart = true;
break; // stop the loop
}
}
if( $is_in_cart )
unset($available_gateways['clearpay']);
}
return $available_gateways;
}
Code goes in functions.php file of the active child theme (or active theme). It should better work.

WooCommerce custom checkout page redirection for specific product categories

If you buy a product from product category "Special" you should be redirected from /checkout/ to /newcheckout/.
When I run this code, nothing is redirect/happens so I am not sure where the fault is:
/*
* Redirect payment gateway based on category.
*/
function ace_disable_payment_gateway_category( $gateways ) {
// Categories that'll redorect the payment gateway
$category_slugs = array( 'special');
$category_ids = get_terms( array( 'taxonomy' => 'product_cat', 'slug' => $category_slugs, 'fields' => 'ids' ) );
$url = '/newcheckout/'; // New checkout URL
// Check each cart item for given category
foreach ( WC()->cart->get_cart() as $item ) {
$product = $item['data'];
if (is_page('checkout') {
if ( $product && array_intersect( $category_ids, $product->get_category_ids() ) ) {
wp_safe_redirect( $url ) // Redirect to newcheckout
break;
}
}
}
return $gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'ace_disable_payment_gateway_category' );
The best hook for redirections is template_redirect action hook. Note that filters hooks are note made for redirection. So your code should be:
// Custom checkout page for specific product categories.
add_filter( 'template_redirect', 'product_category_checkout_redirection' );
function product_category_checkout_redirection() {
// Only on checkout page
if ( is_checkout() && ! is_wc_endpoint_url() ) :
// Categories that redirects
$product_categories = array( 'special'); // Product categories (can be a term Id, slug or name)
$new_checkout_url = home_url('/newcheckout/'); // New checkout URL
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( has_term( $product_categories, 'product_cat', $cart_item['product_id'] ) ) {
wp_safe_redirect( $new_checkout_url ); // Redirects to "newcheckout"
exit();
}
}
endif;
}
Code goes on functions.php file of your active child theme (or active theme). Tested and works.

Display a product custom field value in WooCommerce cart and checkout table

In WooCommerce and I have added a custom field "description" for each product.
I was able to find a way to show both, the label name and the value:
add_filter( 'woocommerce_add_cart_item_data', 'save_days_field', 10, 2 );
function save_days_field( $cart_item_data, $product_id ) {
$special_item = get_post_meta( $product_id , 'description',true );
if(!empty($special_item)) {
$cart_item_data[ 'description' ] = $special_item;
// below statement make sure every add to cart action as unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'description', $special_item );
}
return $cart_item_data;
}
// Render meta on cart and checkout
add_filter( 'woocommerce_get_item_data','rendering_meta_field_on_cart_and_checkout', 10, 2 );
function rendering_meta_field_on_cart_and_checkout( $cart_item_data, $cart_item ) {
if( isset( $cart_item['description'] ) ) {
$cart_item_data[] = array( "name" => __( "Description", "woocommerce" ), "value" => $cart_item['description'] );
}
return $cart_item_data;
}
Now I need to display ONLY the value (not the label name "Description") of this custom field in the cart and checkout table. I need to display with <small>, like the attribute I am displaying with this code:
add_filter('woocommerce_cart_item_name', 'wp_woo_cart_attributes', 10, 2);
function wp_woo_cart_attributes($cart_item, $cart_item_key){
$productId = $cart_item_key['product_id'];
$product = wc_get_product($productId);
$taxonomy = 'pa_color';
$value = $product->get_attribute($taxonomy);
if ($value) {
$label = get_taxonomy($taxonomy)->labels->singular_name;
$cart_item .= "<small>$value</small>";
}
return $cart_item;
}
How can I make it for this custom field, displaying the value only?
You don't need to include a product custom field as custom cart item data, as it's directly accessible from the product object (or the product ID).
Note: On a cart item variable $cart_item, the WC_Product Object is included and available using $cart_item['data'].
Try the following to add a custom field after the item name in cart and checkout pages:
// Display in cart and checkout pages
add_filter( 'woocommerce_cart_item_name', 'customizing_cart_item_name', 10, 3 );
function customizing_cart_item_name( $product_name, $cart_item, $cart_item_key ) {
$product = $cart_item['data']; // Get the WC_Product Object
if ( $value = $product->get_meta('description') ) {
$product_name .= '<small>'.$value.'</small>';
}
return $product_name;
}
To display it on orders and email notifications use:
// Display in orders and email notifications
add_filter( 'woocommerce_order_item_name', 'customizing_order_item_name', 10, 2 );
function customizing_order_item_name( $product_name, $item ) {
$product = $item->get_product(); // Get the WC_Product Object
if ( $value = $product->get_meta('description') ) {
$product_name .= '<small>'.$value.'</small>';
}
return $product_name;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Allow checkout only when a product of a mandatory category is in cart

I'd like to stop any customer advancing to the checkout if they do not have a particular product category in their basket. I would also like to tell them with an error message that they need to add a certain product. I've found some code but cannot it to work. I've added it as a code snippet into my Wordpress install but alas it does not function and there are no error messages even though I have debugging switched on. Here is the code that I have found in Github that may need modification in order for this to work:
function sv_wc_prevent_checkout_for_category() {
// set the slug of the category for which we disallow checkout
$category = 'sibling';
// get the product category
$product_cat = get_term_by( 'slug', $category, 'product_cat' );
// sanity check to prevent fatals if the term doesn't exist
if ( is_wp_error( $product_cat ) ) {
return;
}
$category_name = '' . $product_cat->name . '';
// check if this category is the only thing in the cart
if ( sv_wc_is_category_alone_in_cart( $category ) ) {
// render a notice to explain why checkout is blocked
wc_add_notice( sprintf( 'Hi there! Looks like your cart only contains products from the %1$s category – you must purchase a product from another category to check out.', $category_name ), 'error' );
}
}
add_action( 'woocommerce_check_cart_items', 'sv_wc_prevent_checkout_for_category' );
/**
* Checks if a cart contains exclusively products in a given category
*
* #param string $category the slug of the product category
* #return bool - true if the cart only contains the given category
*/
function sv_wc_is_category_alone_in_cart( $category ) {
// check each cart item for our category
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// if a product is not in our category, bail out since we know the category is not alone
if ( ! has_term( $category, 'product_cat', $cart_item['data']->id ) ) {
return false;
}
}
// if we're here, all items in the cart are in our category
return true;
}
So I'm looking to stop checkout (with error message) if the 'sibling' category is the only item in the cart. I have a 'standard' category which must be in the basket before the customer makes it to the checkout. Hope this makes sense.
Here you have a solution that will make the trick. There is especially 2 main functions (the last ones):
The first function (N°3) display your message on cart page, when there is something in cart but not the mandatory product category. Displays also the message on the mandatory product archive pages (useful when customer get redirected from checkout, see below).
The second function (N°4) redirect customer to the product mandatory category archive pages when it tries to checkout and his cart has not that missing mandatory product category.
Define before your mandatory category slug in your_mandatory_category_slug() function.
This is the code:
// Function that define the mandatory product category
function your_mandatory_category_slug(){
// DEFINE HERE the SLUG of the needed product category
$category = 'clothing';
return $category;
}
// Conditional function that returns true if the mandatory product category is in cart
function has_mandatory_category(){
$category_needed = your_mandatory_category_slug();
$has_cat = false;
// Iterrating each item in cart and detecting…
foreach ( WC()->cart->get_cart() as $item ) {
// Detects if the needed product category is in cart items
if ( has_term($category_needed, 'product_cat', $item['product_id'] ) ) {
$has_cat = true;
break;
}
}
return $has_cat;
}
// Function that display a message if there is not in cart a mandatory product category
function mandatory_category_display_message() {
$category_needed = your_mandatory_category_slug();
// check that cart is not empty (for cart and product category archives)
if( !WC()->cart->is_empty() && ( is_cart() || is_product_category( $category_needed ) ) ){
$category_obj = get_term_by( 'slug', $category_needed, 'product_cat' );
if ( is_wp_error( $category_obj ) ) return;
// Display message when product category is not in cart items
if ( !has_mandatory_category() ) {
$category_name = $category_obj->name;
$category_url = get_term_link( $category_needed, 'product_cat' );
// render a notice to explain why checkout is blocked
wc_add_notice( sprintf( __( '<strong>Reminder:</strong> You have to add in your cart, a product from "%1$s" category, to be allowed to check out. Please return here to "%1$s" product page', 'your_theme_domain'), $category_name, $category_url ), 'error' );
}
}
}
add_action( 'woocommerce_before_main_content', 'mandatory_category_display_message', 30 ); // for product mandatory category archives pages
add_action( 'woocommerce_check_cart_items', 'mandatory_category_display_message' ); // for cat page
// Function that redirect from checkout to mandatory product category archives pages
function mandatory_category_checkout_redirect() {
// If cart is not empty on checkout page
if( !WC()->cart->is_empty() && is_checkout() ){
$category_needed = your_mandatory_category_slug();
// If missing product category => redirect to the products category page
if ( !has_mandatory_category() )
wp_redirect( get_term_link( $category_needed, 'product_cat' ) );
}
}
add_action('template_redirect', 'mandatory_category_checkout_redirect');
This goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and fully functional.
I have adapted LoicTheAztec's answer to work with 2 categories. It seems to be working. I did not adapt the text has_mandatory_categorytext function, . If you can follow the code you can diy, but I was focusing on just functionality. There is another answer here but I preferred this answer and the other was not working for me.
// Function that define the 2 mandatory product categories cat1 & cat2
function your_mandatory_category_slug(){ $category = 'cat1'; return $category; }
function your_mandatory_category_slug2(){ $category = 'cat2'; return $category; }
// Conditional function that returns true if the mandatory product category is in cart
function has_mandatory_category1(){
$category_needed = your_mandatory_category_slug();
$has_cat = false;
foreach ( WC()->cart->get_cart() as $item ) {
if ( has_term($category_needed, 'product_cat', $item['product_id'] ) ) {
$has_cat = true;
break;
}
}
return $has_cat;
}
// Conditional function that returns true if the mandatory product category is in cart
function has_mandatory_category2(){
$category_needed = your_mandatory_category_slug2();
$has_cat = false;
foreach ( WC()->cart->get_cart() as $item ) {
if ( has_term($category_needed, 'product_cat', $item['product_id'] ) ) {
$has_cat = true;
break;
}
}
return $has_cat;
}
// Function that redirect from checkout to mandatory product category archives pages
function mandatory_category_checkout_redirect() {
// If cart is not empty on checkout page
if( !WC()->cart->is_empty() && is_checkout() ){
$category_needed = your_mandatory_category_slug();
$category_needed2 = your_mandatory_category_slug2();
if ( !has_mandatory_category1() )
wp_redirect( get_term_link( $category_needed, 'product_cat' ) );
if ( !has_mandatory_category2() )
wp_redirect( get_term_link( $category_needed2, 'product_cat' ) );
}
}
add_action('template_redirect', 'mandatory_category_checkout_redirect');
Works like a charm for my Wordpress installation with Woocommerce v2.6.12.
I would like to add two mandatory product-categories, maybe 3 or 4 in the future. I tried changing:
$category = 'slug1';
to
$category = 'slug1', 'slug2';
and
$category = array('slug1','slug2');
Without success. Is there a way to make this code work with multiple slugs?

Categories