lharby
lharby

Reputation: 3265

Custom function to redirect to page if condition met (too many limited products in cart) Woocommerce

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.

enter image description 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

Answers (1)

twofed
twofed

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

Related Questions