I have a snippet I got from https://businessbloomer.com/woocommerce-check-product-category-cart/ which is:
/*
* #snippet Check if Product Category is in the Cart - WooCommerce
* #how-to Watch tutorial # https://businessbloomer.com/?p=19055
* #sourcecode https://businessbloomer.com/?p=72900
* #author Rodolfo Melogli
* #testedwith WooCommerce 3.1.2
*/
add_action('woocommerce_before_cart', 'bbloomer_check_category_in_cart');
function bbloomer_check_category_in_cart() {
// Set $cat_in_cart to false
$cat_in_cart = false;
// Loop through all products in the Cart
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// If Cart has category "download", set $cat_in_cart to true
if ( has_term( 'download', 'product_cat', $cart_item['product_id'] ) ) {
$cat_in_cart = true;
break;
}
}
// Do something if category "download" is in the Cart
if ( $cat_in_cart ) {
// For example, print a notice
wc_print_notice( 'Category Downloads is in the Cart!', 'notice' );
// Or maybe run your own function...
// ..........
}
}
It displays a notice if a product category is in the cart but it display the message via wc_print_notice on the cart page. I would like to display this message on a custom theme page template either via a short-code or any suggestions are welcome.
How about:
// modify the function above
if ( $cat_in_cart )
{
$msg = 'Category Downloads is in the Cart!';
wc_print_notice( $msg, 'notice' );
return $msg;
}
return null;
...
// create a new function for the shortcode
// it can be after the above function
add_shortcode( 'myshortcode', 'myshortcode_func' );
function myshortcode_func( $atts ) {
return (($msg = bbloomer_check_category_in_cart()) !== null)
? '<div class="msg">' . esc_html ($msg) . '</div>'
: ''
;
}
Then just add the shortcode in the page content.
[myshortcode]
Related
I am creating an LMS using LearnDash + WooCommerce. So far so good. Now, I'd like to hide a Product when the logged-in user has already purchased it to a) prevent the user from purchasing it twice, and b) so that I can display a product grid for them without the already purchased item(s).
Another example: if a user who purchased ITEM A goes to the shop, ITEM A should not even be displayed for them.
Thanks so much!
So, I ended up with a nice workaround:
On the product page, I created a CUSTOM FIELD where I can input the COURSE ID.
Then, with PHP, I check the Product and retrieve the custom field for the COURSE ID.
LearnDash has a shortcode for students... so after retrieving the course ID, I can display a message/button for users who have registered already for this course.
This is the code:
<?php
global $product;
$postid = $product->get_id();
$courseid = get_post_meta( $product->get_id(), 'ID_del_curso', true );
$html = '"]<center><div class="alreadyPurchased"><i class="fas fa-graduation-cap paddingRightM"></i> Ya te has registrado</div></center>';
$openIT = '[student course_id="';
$closeIT = '[/student]';
echo do_shortcode( $openIT . $courseid . $html . $closeIT );
?>
Hope it helps!
There is a simpler solution.
Use this LearnDash shortcode...
[visitor]
Hello visitor.
Put your "Buy now" button here.
[/visitor]
/**
* Disables repeat purchase for products / variations
*
* #param bool $purchasable true if product can be purchased
* #param \WC_Product $product the WooCommerce product
* #return bool $purchasable the updated is_purchasable check
*/
function sv_disable_repeat_purchase( $purchasable, $product ) {
// Don't run on parents of variations,
// function will already check variations separately
if ( $product->is_type( 'variable' ) ) {
return $purchasable;
}
// Get the ID for the current product (passed in)
$product_id = $product->get_id();
// return false if the customer has bought the product / variation
if ( wc_customer_bought_product( wp_get_current_user()->user_email, get_current_user_id(), $product_id ) ) {
$purchasable = false;
}
return $purchasable;
}
add_filter( 'woocommerce_is_purchasable', 'sv_disable_repeat_purchase', 10, 2 );
/**
* Shows a "purchase disabled" message to the customer
*/
function sv_purchase_disabled_message() {
global $product; // get the current product to see if it has been purchased
if ( $product->is_type( 'variable' ) ) {
foreach ( $product->get_children() as $variation_id ) {
// Render the purchase restricted message if it has been purchased
if ( wc_customer_bought_product( wp_get_current_user()->user_email, get_current_user_id(), $variation_id ) ) {
sv_render_variation_non_purchasable_message( $product, $variation_id );
}
}
} else {
if ( wc_customer_bought_product( wp_get_current_user()->user_email, get_current_user_id(), $product->get_id() ) ) {
echo '<div class="woocommerce"><div class="woocommerce-info wc-nonpurchasable-message">You\'ve already purchased this product! It can only be purchased once.</div></div>';
}
}
}
add_action( 'woocommerce_single_product_summary', 'sv_purchase_disabled_message', 31 );
/**
* Generates a "purchase disabled" message to the customer for specific variations
*
* #param \WC_Product $product the WooCommerce product
* #param int $no_repeats_id the id of the non-purchasable product
*/
function sv_render_variation_non_purchasable_message( $product, $no_repeats_id ) {
// Double-check we're looking at a variable product
if ( $product->is_type( 'variable' ) && $product->has_child() ) {
$variation_purchasable = true;
foreach ( $product->get_available_variations() as $variation ) {
// only show this message for non-purchasable variations matching our ID
if ( $no_repeats_id === $variation['variation_id'] ) {
$variation_purchasable = false;
echo '<div class="woocommerce"><div class="woocommerce-info wc-nonpurchasable-message js-variation-' . sanitize_html_class( $variation['variation_id'] ) . '">You\'ve already purchased this product! It can only be purchased once.</div></div>';
}
}
}
if ( ! $variation_purchasable ) {
wc_enqueue_js("
jQuery('.variations_form')
.on( 'woocommerce_variation_select_change', function( event ) {
jQuery('.wc-nonpurchasable-message').hide();
})
.on( 'found_variation', function( event, variation ) {
jQuery('.wc-nonpurchasable-message').hide();
if ( ! variation.is_purchasable ) {
jQuery( '.wc-nonpurchasable-message.js-variation-' + variation.variation_id ).show();
}
})
.find( '.variations select' ).change();
");
}
}
Gist snippet got from here - please check
I have added below code to show currency switcher dropdown on the WooCommerce checkout page which is working fine, but I don’t want to show currency switcher field if anyone has added product from "Games" category and use only default store currency
Code 1
add_action('woocommerce_before_checkout_billing_form', 'wps_add_select_checkout_field');
function wps_add_select_checkout_field( $checkout ) {
echo '<label for="payment_option" class="payment_option">'.__('Preferred currency').'</label>';
echo '<div class="own">', do_shortcode('[woocs]'), '</div>';
return $checkout;
}
//* Process the checkout
add_action('woocommerce_checkout_process', 'wps_select_checkout_field_process');
function wps_select_checkout_field_process() {
global $woocommerce;
// Check if set, if its not set add an error.
if ($_POST['payopt'] == "blank")
wc_add_notice( '<strong>Please select a currency</strong>', 'error' );
}
Based on this answer thread: Checking cart items for a product category in Woocommerce
I have tried below code and I think something is missing, If I am using below code it's not showing currency switcher at all even if product is from "Games" or other categories.
Code 2
add_action('woocommerce_before_cart', 'check_product_category_in_cart');
function check_product_category_in_cart() {
// Here set your product categories in the array (can be IDs, slugs or names)
$categories = array('games');
$found = false; // Initializing
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
// If product categories is found
if ( !has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$found = true; // Set to true
break; // Stop the loop
}
}
// If any defined product category is found, run below code
if ( $found ) {
add_action('woocommerce_before_checkout_billing_form', 'wps_add_select_checkout_field');
function wps_add_select_checkout_field( $checkout ) {
echo '<label for="payment_option" class="payment_option">'.__('Preferred currency').'</label>';
echo '<div class="own">', do_shortcode('[woocs]'), '</div>';
return $checkout;
}
//* Process the checkout
add_action('woocommerce_checkout_process', 'wps_select_checkout_field_process');
function wps_select_checkout_field_process() {
global $woocommerce;
// Check if set, if its not set add an error.
if ($_POST['payopt'] == "blank")
wc_add_notice( '<strong>Please select a currency</strong>', 'error' );
}
}
}
Do you have any other suggestion for the same? Where I can add currency switcher on checkout page based on cart product category. Code 1 is working fine on the checkout page but I don't want to run that code if product category is games.
You are not using the correct hook as woocommerce_before_cart action hook is only triggered in cart page, but not in checkout and it can't work this way. Instead try to use the following:
// Utility function that checks if at least a cart items remains to a product category
function has_product_category_in_cart( $product_category ) {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
// If any product category is found in cart items
if ( has_term( $product_category, 'product_cat', $cart_item['product_id'] ) ) {
return true;
}
}
return false;
}
// Add a custom select field in checkout
add_action('woocommerce_before_checkout_billing_form', 'add_custom_checkout_select_field');
function add_custom_checkout_select_field( $checkout ) {
// Here set in the function your product category term ID, slugs, names or array
if ( ! has_product_category_in_cart( 'games' ) && shortcode_exists( 'woocs' ) ) {
echo '<label for="payment_option" class="payment_option">'.__('Preferred currency').'</label>';
echo '<div class="own">' . do_shortcode('[woocs]') . '</div>';
}
}
// Custom Checkout fields validation
add_action('woocommerce_checkout_process', 'custom_checkout_select_field_validation');
function custom_checkout_select_field_validation() {
if ( isset($_POST['payopt']) && empty($_POST['payopt']) )
wc_add_notice( '<strong>Please select a currency</strong>', 'error' );
}
Code goes in function.php file of your active child theme (active theme). Untested but it should works.
In WooCommerce, I am using a function that show an error message and prevent to checkout, if product from one specific category is alone in cart items.
But the error message remain displayed even if cart is empty.
How can I disable this function if cart is empty?
Here is my code:
function sv_wc_prevent_checkout_for_category() {
// set the slug of the category for which we disallow checkout
$category = 'clothing';
// 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;
}
Thanks
To avoid error message showing when cart is empty, you need to add in your first function condition ! WC()->cart->is_empty() this way:
// Check if this category is the only thing in the cart (when cart is not empty)
if ( sv_wc_is_category_alone_in_cart( $category ) && ! WC()->cart->is_empty() ) { // <= <=
So your first function code will be:
function sv_wc_prevent_checkout_for_category() {
// set the slug of the category for which we disallow checkout
$category = 'clothing';
// 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 (when cart is not empty)
if ( sv_wc_is_category_alone_in_cart( $category ) && ! WC()->cart->is_empty() ) { // <==
// 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' );
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?
I'm looking into purchasing WooCommerce Pre Orders and have been looking at a friend's copy to demo. It's a great plugin, but I have an issue I can't seem to solve.
When ordering, you can only order 1 variation of a product at a time. You can edit the quantity of that variation in the cart but you can't add 2 variations of the same product to the same cart at the same time. If you do, it will empty the cart and replace it with the current selection. Since I'd be taking pre-orders for screen printed clothing (similar to teespring), ordering multiple variations (sizes in this instance) at one time is important. Making them make multiple orders from the same product would just drive them away.
I don't want to let customers order from multiple preorders at once since each preordered product has a different release/ship date, but I want to let them order multiple variations, i.e. a Small Tee, a Medium Tee, and a Large Tee, of a particular product since they would all ship at the same time.
I hope all of that made sense.
Here is the code that is responsible for the cart restrictions. Any help is much appreciated.
/**
* When a pre-order is added to the cart, remove any other products
*
* #since 1.0
* #param bool $valid
* #param $product_id
* #return bool
*/
public function validate_cart( $valid, $product_id ) {
global $woocommerce;
if ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $product_id ) ) {
// if a pre-order product is being added to cart, check if the cart already contains other products and empty it if it does
if( $woocommerce->cart->get_cart_contents_count() >= 1 ) {
$woocommerce->cart->empty_cart();
$string = __( 'Your previous cart was emptied because pre-orders must be purchased separately.', 'wc-pre-orders' );
// Backwards compatible (pre 2.1) for outputting notice
if ( function_exists( 'wc_add_notice' ) ) {
wc_add_notice( $string );
} else {
$woocommerce->add_message( $string );
}
}
// return what was passed in, allowing the pre-order to be added
return $valid;
} else {
// if there's a pre-order in the cart already, prevent anything else from being added
if ( $this->cart_contains_pre_order() ) {
// Backwards compatible (pre 2.1) for outputting notice
if ( function_exists( 'wc_add_notice' ) ) {
wc_add_notice( __( 'This product cannot be added to your cart because it already contains a pre-order, which must be purchased separately.', 'wc-pre-orders' ) );
} else {
$woocommerce->add_error( __( 'This product cannot be added to your cart because it already contains a pre-order, which must be purchased separately.', 'wc-pre-orders' ) );
}
$valid = false;
}
}
return $valid;
}
/**
* Add any applicable pre-order fees when calculating totals
*
* #since 1.0
*/
public function maybe_add_pre_order_fee() {
global $woocommerce;
// Only add pre-order fees if the cart contains a pre-order
if ( ! $this->cart_contains_pre_order() ) {
return;
}
// Make sure the pre-order fee hasn't already been added
if ( $this->cart_contains_pre_order_fee() ) {
return;
}
$product = self::get_pre_order_product();
// Get pre-order amount
$amount = WC_Pre_Orders_Product::get_pre_order_fee( $product );
if ( 0 >= $amount ) {
return;
}
$fee = apply_filters( 'wc_pre_orders_fee', array(
'label' => __( 'Pre-Order Fee', 'wc-pre-orders' ),
'amount' => $amount,
'tax_status' => WC_Pre_Orders_Product::get_pre_order_fee_tax_status( $product ), // pre order fee inherits tax status of product
) );
// Add fee
$woocommerce->cart->add_fee( $fee['label'], $fee['amount'], $fee['tax_status'] );
}
/**
* Checks if the current cart contains a product with pre-orders enabled
*
* #since 1.0
* #return bool true if the cart contains a pre-order, false otherwise
*/
public static function cart_contains_pre_order() {
global $woocommerce;
$contains_pre_order = false;
if ( ! empty( $woocommerce->cart->cart_contents ) ) {
foreach ( $woocommerce->cart->cart_contents as $cart_item ) {
if ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $cart_item['product_id'] ) ) {
$contains_pre_order = true;
break;
}
}
}
return $contains_pre_order;
}
/**
* Checks if the current cart contains a pre-order fee
*
* #since 1.0
* #return bool true if the cart contains a pre-order fee, false otherwise
*/
public static function cart_contains_pre_order_fee() {
global $woocommerce;
foreach ( $woocommerce->cart->get_fees() as $fee ) {
if ( is_object( $fee ) && 'pre-order-fee' == $fee->id )
return true;
}
return false;
}
/**
* Since a cart may only contain a single pre-ordered product, this returns the pre-ordered product object or
* null if the cart does not contain a pre-order
*
* #since 1.0
* #return object|null the pre-ordered product object, or null if the cart does not contain a pre-order
*/
public static function get_pre_order_product() {
global $woocommerce;
if ( self::cart_contains_pre_order() ) {
foreach ( $woocommerce->cart->cart_contents as $cart_item ) {
if ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $cart_item['product_id'] ) ) {
// return the product object
return get_product( $cart_item['variation_id'] ? $cart_item['variation_id'] : $cart_item['product_id'] );
}
}
} else {
// cart doesn't contain pre-order
return null;
}
}
I know this post is old. But come to this same problem and i have solved my problem like this.
I have changed validate_cart() function in woocommerce-pre-orders/classes/class-wc-pre-orders-cart.php
It is like this :
public function validate_cart( $valid, $product_id ) {
global $woocommerce;
if ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $product_id ) ) {
if( $woocommerce->cart->get_cart_contents_count() >= 1 ) {
if ( $this->cart_contains_pre_order() ) {
return $valid;
}
$string = __( 'Your cart contains items, please complete that order first and then purchase pre-order items, because pre-orders must be purchased separately.', 'wc-pre-orders' );
// Backwards compatible (pre 2.1) for outputting notice
if ( function_exists( 'wc_add_notice' ) ) {
wc_add_notice( $string );
} else {
$woocommerce->add_message( $string );
}
$valid = false;
return $valid;
}
else
{
return $valid;
}
} else {
// if there's a pre-order in the cart already, prevent anything else from being added
if ( $this->cart_contains_pre_order() ) {
// Backwards compatible (pre 2.1) for outputting notice
if ( function_exists( 'wc_add_notice' ) ) {
wc_add_notice( __( 'This product cannot be added to your cart because it already contains a pre-order, which must be purchased separately.', 'wc-pre-orders' ) );
} else {
$woocommerce->add_error( __( 'This product cannot be added to your cart because it already contains a pre-order, which must be purchased separately.', 'wc-pre-orders' ) );
}
$valid = false;
}
}
return $valid;
}
Note : I know this is not the right way for implementation. Because i
have edit in plugin directly. So when plugin will update, the changes are no longer there. And you can use any 'return $valid' or 'return true' or 'return false' as your choice.
Thank you.
I've been having the same issue and just found an answer (I hope) here:
Pre-orders can only purchase one at a time
I managed to implement hortongroup's plugin fix as described in the comments.
There was a slight error the shortcode line in the description, it should read:
echo do_shortcode('[pre_order_fix]');
It now seems to be working perfectly, I'll have wait for the next update to WooCommerce Pre Orders to see if the plugin fix still works.
Ideally by doing it this way we won't have to alter WooCommerce Pre Orders after every update.
Here's the code I used for the custom plugin:
<?php
/**
* Plugin Name: Woo Pre-Order Fix
* Plugin URI:
* Description: Fix the one item only issue with Woocommerce Pre-Orders
* Version: 1.0
* Author: hortongroup
* Author URI:
* License: GPL12
*/
function pre_order_fix_shortcode() {
if ( in_array( 'woocommerce-pre-orders/woocommerce-pre-orders.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
remove_filter( 'woocommerce_add_to_cart_validation', array( $GLOBALS['wc_pre_orders']->cart, 'validate_cart' ), 15, 2 );
}
}
add_shortcode('pre_order_fix', 'pre_order_fix_shortcode');
?>
Hopefully this will work for you too:)
Kind regards,
JP
I know that it's been a long time but I think this could still be useful for someone. If you have a child theme you can just add this to functions.php:
//remove pre-order limitations --> only one item per order
add_action( 'init', 'remove_validation_cart' );
function remove_validation_cart(){
remove_filter( 'woocommerce_add_to_cart_validation', array( $GLOBALS['wc_pre_orders']->cart, 'validate_cart' ), 15, 2 );
}
This avoids the need of adding a plugin
Since this issue still exists today and my scenario was slightly different, I've used the following filter to fix my issue.
I want pre-orders to be made but not one pre-order item per order, there could be multiple quantities and different pre-order products in one order. The only scenario I want to prevent is that regular products are being mixed with pre-orders (which shouldn't be possible).
Maybe anyone else could use this approach (going to check for something custom in the future which you can add to your child-theme) which would be better since it could now be overwritten with an update.
/**
* When a pre-order is added to the cart, remove any other products
*
* #since 1.0
* #param bool $valid
* #param $product_id
* #return bool
*/
public function validate_cart( $valid, $product_id ) {
global $woocommerce;
if ( WC_Pre_Orders_Product::product_can_be_pre_ordered( $product_id ) ) {
// if a pre-order product is being added to cart, check if the cart already contains other products and empty it if it does
if( $woocommerce->cart->get_cart_contents_count() >= 1 ) {
// count the amount of regular items in the cart
$regularCount = 0;
foreach ($woocommerce->cart->get_cart() as $item) {
// continue of the product is a pre-order product...
if (WC_Pre_Orders_Product::product_can_be_pre_ordered( $item['product_id'] )) {
continue;
}
$regularCount++;
}
// only clear the cart if the current items in it are having regular products...
if ($regularCount > 0) {
$woocommerce->cart->empty_cart();
$string = __( 'Your previous cart was emptied because pre-orders must be purchased separately.', 'wc-pre-orders' );
// Backwards compatible (pre 2.1) for outputting notice
if ( function_exists( 'wc_add_notice' ) ) {
wc_add_notice( $string );
} else {
$woocommerce->add_message( $string );
}
}
}
// return what was passed in, allowing the pre-order to be added
return $valid;
} else {
// if there's a pre-order in the cart already, prevent anything else from being added
if ( $this->cart_contains_pre_order() ) {
// Backwards compatible (pre 2.1) for outputting notice
if ( function_exists( 'wc_add_notice' ) ) {
wc_add_notice( __( 'This product cannot be added to your cart because it already contains a pre-order, which must be purchased separately.', 'wc-pre-orders' ) );
} else {
$woocommerce->add_error( __( 'This product cannot be added to your cart because it already contains a pre-order, which must be purchased separately.', 'wc-pre-orders' ) );
}
$valid = false;
}
}
return $valid;
}