Search code examples
phpwordpresswoocommercecheckoutcart

Check if there are out of stock items in cart - WooCommerce


I need to display a section in my checkout order review ONLY IF there is an out of stock item in the cart (b/c our products are available on backorder). Here is the code that displays the section...

Functions.php:

function notes_in_cart() {
    global $woocommerce;
       if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
        return;
    }

    if ( isset( $_POST['post_data'] ) ) {
        parse_str( $_POST['post_data'], $post_data );
    } else {
        $post_data = $_POST; // fallback for final checkout (non-ajax)
    }
    if ( WC()->cart->needs_shipping() ){
        //if cart has items out of stock
        //if (cart has out of stock product) {
        ?>
            <tr class="ceckoutStockMeta">
                <th>Item Shipments</th>

                <td>
                    <p style="color: red;">*You have one or more items in your cart that are currently out of stock. Please select a custom shipping option for your order.</p><br>
                    <form>

                        <input type="radio" name="stockOp" id="stockOption1" value="ship" />
                        <label for="stockOption1">Ship what is available now</label><br>

                        <input type="radio" name="stockOp" id="stockOption2" value="hold" />
                        <label for="stockOption2">Wait and ship together</label>
                    </form>
                </td>
            </tr>

        <?php 

        //}
    }
}
add_action( 'woocommerce_cart_totals_after_order_total', 'notes_in_cart' );
add_action( 'woocommerce_review_order_after_order_total', 'notes_in_cart' );

Right now the section shows all the time. I know I will probably need to call the cart items and loop through with a foreach to determine if one is out of stock, but not sure how.


Solution

  • You can do it like this to check against the "Stock quantity" and the "Allow Backorders?" properties of the products:

    function notes_in_cart() {
         global $woocommerce;
    
        if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
            return;
        }
    
        if ( isset( $_POST['post_data'] ) ) {
            parse_str( $_POST['post_data'], $post_data );
        } else {
            $post_data = $_POST; // fallback for final checkout (non-ajax)
        }
    
        if ( WC()->cart->needs_shipping() ){
    
            // set $out_of_stock_exists to false by default
            $out_of_stock_exists = false;
            foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
                if($values['data']->backorders_allowed()){ //check if backorders are allowed on this product
                    // get the stock quantity - returns the available amount number
                    $stock_info = $values['data']->get_stock_quantity();
    
                    if($stock_info < $values['quantity']){ //thanks to LoicTheAztec for pointing it out in his answer
                        // set $out_of_stock_exists to true and stop foreach execution
                        $out_of_stock_exists = true;
                        break;
                    }
                }
    
            }
    
            //if cart has items out of stock
            if ($out_of_stock_exists) {
                ?>
                <tr class="ceckoutStockMeta">
                    <th>Item Shipments</th>
                    <td>
                        <p style="color: red;">*You have one or more items in your cart that are currently out of stock. Please select a custom shipping option for your order.</p><br>
                        <form>
    
                            <input type="radio" name="stockOp" id="stockOption1" value="ship" />
                            <label for="stockOption1">Ship what is available now</label><br>
    
                            <input type="radio" name="stockOp" id="stockOption2" value="hold" />
                            <label for="stockOption2">Wait and ship together</label>
                        </form>
                    </td>
                </tr>
    
                <?php
    
            }
        }
    }
    add_action( 'woocommerce_cart_totals_after_order_total', 'notes_in_cart' );
    add_action( 'woocommerce_review_order_after_order_total', 'notes_in_cart' );
    

    It can also be done using the get_stock_status() or is_in_stock() methods that returns the value of "Stock status" - 'instock' or 'outofstock' - but that will not allow the checkout using backorders: https://github.com/woocommerce/woocommerce/issues/11187 or https://github.com/woocommerce/woocommerce/issues/10834

    EDIT: More details on why is_in_stock() does not work: The is_in_stock() method is this one:

    public function is_in_stock() {
        return apply_filters( 'woocommerce_product_is_in_stock', 'instock' === $this->get_stock_status(), $this );
    }
    

    That means it checks for "Stock Status" and it returns true if "in stock" and false if "out of stock".

    Now, if you read here: https://conschneider.de/manage-stock-backorders-woocommerce/

    You will find that:

    Backorders only are possible for as long as the stock status is “in stock”. Setting the product to out of stock will again block purchases and display “out of stock”.