WooCommerce custom sales page – cookies and cart not saved

I have set up a custom sales page on which I want to perform add_to_cart operations and/or update_cart quantities of two different products, from the same input value and a single form POST. The reason for doing this with custom code is to focus on just a few products, and to allow both adding and updating quantities using just one submit button.

It is working well if a user is logged in or already has the cart cookies set up. I need help to get it working for new visitors.

I have put example code for one product below. It works if I have cookies set or a product in the cart.

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

// shortcode [question_code]
function question_code_shortcode() 
{
    // check to enable saving pages which use this shortcode
    if ( (! is_admin()) && is_object(WC()->cart) ) 
    {

        ob_start();

        $stdbox_id = 30;
        unset($qty_in_cart_stdbox);
        $cart_updated = false;  // unused flag which might be useful

        $cart_items = WC()->cart->get_cart();
        foreach ($cart_items as $cart_item_key => $cart_item)
        {
            if ( $cart_item['product_id'] == $stdbox_id ) {
                $qty_in_cart_stdbox = $cart_item['quantity'];
                $stdbox_cart_key = $cart_item_key;
            }
        }

        if ( (is_object(WC()->cart)) && ($_SERVER["REQUEST_METHOD"] == "POST") && (isset($_POST['qty-stdbox'])) )
        {
            $qty_stdbox = (0 < intval($_POST['qty-stdbox'])) ? intval($_POST['qty-stdbox']) : 0;
            echo 'a) qty_stdbox = ' . $qty_stdbox . '<br>';

            if (isset($qty_in_cart_stdbox)) {
                echo 'b) quantity before update = ' . $qty_in_cart_stdbox . '<br>';
                WC()->cart->set_quantity( $stdbox_cart_key, $qty_stdbox, true );
                $qty_in_cart_stdbox = $qty_stdbox;
                echo 'c) updated quantity = ' . $qty_in_cart_stdbox . '<br>';
                $cart_updated = true;
            } elseif ($qty_stdbox > 0) {
                echo 'd) quantity to be added = ' . $qty_stdbox . '<br>';
                WC()->cart->add_to_cart( $stdbox_id , $qty_stdbox);
                $qty_in_cart_stdbox = $qty_stdbox;
                echo 'e) newly added quantity = ' . $qty_in_cart_stdbox . '<br>';
                $cart_updated = true;
            }
        }

        ?>
        <div style="text-align: center;">
        <form name="question-action" action="./" method="POST">

        <label for="qty-stdbox">Choose how many boxes</label>
        <br>
        <!-- set value to the value just submitted -->
        <input name="qty-stdbox" type="number" min="0" value="<?php echo isset($qty_in_cart_stdbox) ? esc_html($qty_in_cart_stdbox) : ''; ?>"/>
        <br>
        <br>

        <input type="submit" name="iself-boxes" value="Choose storage"/>

        </form>
        </div>

        <?php

        /**
         * Print selected fields within the cart contents
         * after the form submit has been processed, showing
         * that the cart picks up the values added, but only updates
         * the cart if there is already a product in the cart.
         */
        function print_cart_contents($cart_contents)
        {
            echo '<pre>';
            echo 'Cart contents: product_id, quantity, key and data_hash<br>';
            print_r(wp_list_pluck($cart_contents, "product_id"));
            print_r(wp_list_pluck($cart_contents, "quantity"));
            print_r(wp_list_pluck($cart_contents, "key"));
            print_r(wp_list_pluck($cart_contents, "data_hash"));
            // Alternative print
            // echo 'Cart contents<br>';
            // print_r($cart_contents);
            echo '</pre>';
            return $cart_contents;
        } 

        $cart_items = WC()->cart->get_cart();
        print_cart_contents($cart_items);

        $temp_content = ob_get_contents();
        ob_end_clean();

        return $temp_content;
    }
}

add_shortcode( 'question_code', 'question_code_shortcode' );

?>

I have set it up with:

  • file saved as question-shortcode.php in the activated child theme folder;
  • product_id set to a number which matches a product in my WooCommerce test site;
  • a line in functions.php to load it:

    require(realpath(__DIR__) . '/question-shortcode.php');
    
  • the shortcode [question_code] added as the only entry on a new page.

Explantation of the code

A simple form returns the quantity number. I am using a fixed product_id, in my case 30.

I am processing the POST from the form following ideas from
add_to_cart_action() and update_cart_action().
I am working with simple products, so I am using

WC()->cart->add_to_cart( $product_id, $quantity );

as per add_to_cart_handler_simple() just below it add_to_cart_action(), and

WC()->cart->set_quantity( $cart_item_key, $quantity, true );

The code for the methods in WC_Cart is here: add_to_cart() and set_quantity().

I am using

$cart_items = WC()->cart->get_cart();

to get the existing $cart_items and the $cart_item_key for set_quantity() if the cart already exists.

In order for it to work, I see that I should already have the following cookies set:

woocommerce_cart_hash
woocommerce_items_in_cart
wp_woocommerce_session_

Ideas to get it working

I am clearly missing something.

I would appreciate any ideas to help to get it working for a new visitor to the site, who doesn’t have any cart cookies set when they arrive at the page.

Other things I have been trying

I have been looking at the methods in WC_Cart_Session, the file for which is included in class-wc-cart.php. I have tried adding:

WC()->cart->session->set_cart_cookies() and
WC()->cart->session->maybe_set_cart_cookies()

but they cause ‘Fatal errors’.

I can add_to_cart as a visitor with

<a href="./?add-to-cart=30&quantity=4" class="btn" role="button">Add to cart directly</a>

and I have a variant of this working with a separate form POST, and I can do this with more than one product with this idea which I found on StackOverflow. However I also want to update quantities, rather than only have the ability to change the cart contents on the cart page.

I can see that, rather than code my form processing in the shortcode or a page I redirect this page to, I could easily use add_action() to load it as WC_Form_Handler does in its init() method.

While I am waiting for help, I am going to try reproducing/examining the add_to_cart_action() form processing more closely. If I have any success, I will post my results here.

Many thanks,

Nicholas

Leave a comment

Your email address will not be published. Required fields are marked *

Skip to toolbar