Reputation: 3265
I've made a custom plugin fo WooCommerce. I am trying to limit the number of products a customer can buy from a specific category. Most of it works, but I cannot get it to fire the redirect function once the condition is met.
Here is my code:
add_action( 'wp', 'check_limited_products_in_cart');
function check_limited_products_in_cart () {
// holds checks for all products in cart to see if they're in our category
$category_checks = array();
$limited_product_count = 1;
// check each cart item for our category
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$product_in_cat = false;
// replace 'instant-print' with your category's slug
if ( has_term( 'instant-print', 'product_cat', $product->id ) ) {
$product_in_cat = true;
}
array_push( $category_checks, $product_in_cat );
}
$filtered_array = count(array_filter($category_checks));
if ($filtered_array >= $limited_product_count) {
redirect_limited_products_page(); // this bit seems to be failing
}
}
function redirect_limited_products_page () {
$error_page = '/error';
$target_url = $error_page; // construct a target url
wp_redirect($target_url, 301); // permanent redirect
exit();
}
My second function is throwing too many redirects I think. The page is just churning so I am never seeing any useful console information.
I've tried various iterations of this, like trying to run the entire function in one block (which threw the same error), and then hoisting $filtered_array
as a global variable so I could access it from the second function, but I could not get that to work either.
Any help much appreciated.
EDIT
OK a little progress.
I am now returning:
add_action( 'woocommerce_before_cart', 'check_limited_products_in_cart');
function check_limited_products_in_cart () {
// holds checks for all products in cart to see if they're in our category
$category_checks = array();
$limited_product_count = 1;
// check each cart item for our category
if( ! is_admin() ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$product_in_cat = false;
// replace 'instant-print' with your category's slug
if ( has_term( 'instant-print', 'product_cat', $product->id ) ) {
$product_in_cat = true;
}
array_push( $category_checks, $product_in_cat );
}
}
$filtered_array = count(array_filter($category_checks));
if ($filtered_array >= $limited_product_count) {
echo '<p>condition met</p>';
redirect_limited_products_page();
}
}
function redirect_limited_products_page () {
echo '<p>Redirect page</p>';
$error_page = '/error';
$target_url = $error_page; // construct a target url
wp_redirect($target_url, 301); // permanent redirect
exit();
}
Before I was making a global wp function which rendered everywhere and probably explained the redirect loop.
So now when I add another product to the cart, I am seeing condition met
as well as Redirect page
but with the following error:
Warning: Cannot modify header information - headers already sent by (output started at my-site-url\wp-includes\class.wp-styles.php:290) in my-site-url\wp-includes\pluggable.php on line 1296
Warning: Cannot modify header information - headers already sent by (output started at my-site-url\wp-includes\class.wp-styles.php:290) in my-site-url\wp-includes\pluggable.php on line 1299
So this feels much closer.
** FURTHER UPDATE **
After reading about the issues with headers, I tried to tidy up my file, make sure there was no white space, malformed tags. I removed the closing php tag and checked my linting. I think the main culprit was an exho statement in the redirect function which was throwing the header issue. You can see here.
I am checking the current limited product count compared to the current number of limited products in the basket. It seems now the redirect never fires, so my assumption is that
add_action( 'woocommerce_before_cart', ...)
Might need to be
add_filter ('woocommerce_add_to_cart_validation', ...)
This also did not appear to work. The items get added to the cart item, even though the condition is showing as met and the redirect does not get fired. So I am not sure if I am trying to hook to the wrong function.
<?php
$error_page = '/product-limit-reached';
add_action( 'woocommerce_before_cart', 'check_limited_products_in_cart');
function check_limited_products_in_cart () {
// holds checks for all products in cart to see if they're in our category
$category_checks = array();
$limited_product_count = 1;
// check each cart item for our category
if( ! is_admin() ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$product_in_cat = false;
// replace 'instant-print' with your category's slug
if ( has_term( 'instant-print', 'product_cat', $product->id ) ) {
$product_in_cat = true;
}
array_push( $category_checks, $product_in_cat );
}
}
$filtered_array = count(array_filter($category_checks));
if ($filtered_array >= $limited_product_count) {
echo '<p>condition met</p><p>Limited product count: ' . $limited_product_count. '</p><p>Limited products in cart: ' . $filtered_array. '</p>';
redirect_limited_products_page();
}
}
function redirect_limited_products_page () {
$target_url = $error_page; // construct a target url
wp_redirect($target_url, 301); // permanent redirect
// exit();
}
Upvotes: 2
Views: 270
Reputation: 547
Yes, you need to use woocommerce_add_to_cart_validation hook. We can make a check when adding an item to cart. If the check fails, the item doesn't go to cart, and the user is shown an error. Just like that:
function filter_woocommerce_add_to_cart_validation( $true, $product_id, $request_quantity, $variation_id = '', $request_variation = '' ) {
// holds checks for all products in cart to see if they're in our category
$category_checks = 0;
$limited_product_count = 1;
$limited_slug = 'instant-print'; //replace 'instant-print' with your category's slug
// check each cart item for our category
if( ! is_admin() ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
if ( has_term( $limited_slug, 'product_cat', $product->id ) ) {
$category_checks += $cart_item['quantity'];
}
}
}
// We also check the item that the user is trying to add to cart
if ( has_term( $limited_slug, 'product_cat', $product_id ) ) {
$category_checks += $request_quantity;
}
if ($category_checks >= $limited_product_count) {
$notice = '<p>condition met</p><p>Limited product count: ' . $limited_product_count. '</p><p>Limited products in cart: ' . $category_checks. '</p>';
wc_add_notice( __( $notice, 'textdomain' ), 'error' );
return false;
}
return $true;
};
add_filter( 'woocommerce_add_to_cart_validation', 'filter_woocommerce_add_to_cart_validation', 10, 3 );
Upvotes: 2