1
votes

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.

2

2 Answers

1
votes

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

1
votes

Updated: As all your products are available on backorders, the only efficient way is to check in a foreach loop if the stock quantity "is sufficient" for each cart item quantity...

If the stock quantity of the product is smaller than the cart item quantity (WC displays "available on backorder"), then your "shipment note" is displayed.

Here is that code:

function notes_in_cart() {

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

    // Loop that check if cart items have enough stock quantity 
    $is_available_on_backorder = false;
    foreach ( WC()->cart->get_cart() as $item_values ) {

        $stock_qty = $item_values['data']->get_stock_quantity(); // Product stock
        $item_qty = $item_values['quantity']; // Cart Item quantity

        // Testing if the product has enough stock
        if( $stock_qty < $item_qty ){ 
             $is_available_on_backorder = true; // The condition is met
             break; // we stop the loop
        }
    }

    if ( WC()->cart->needs_shipping() && $is_available_on_backorder ){
        ?>
            <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' );

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

This code is tested and works.