WooCommerce Pre-Orders Plugin

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.

Read More

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;
        }
    }

Related posts

Leave a Reply

4 comments

  1. 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.

  2. 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

  3. 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

  4. 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;
    }