Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WordPress nonce not verifying WooCommerce cart action

I've built a custom WooCommerce cart where you can change quantities and / or remove items from your cart with AJAX, but it's buggy and I think it's got something to do with WooCommerce and the validity of WordPress nonces.

The problem:

It works when there's a product in your cart and you refreshed the page at least once - after adding the product to your cart.

It doesn't work when it's your first visit, you add a product in your cart and you try to edit the quantities of the product, or try to delete it.

See for yourself at https://staging.noten.nl/noten/ - check on your smartphone please. Add a product to the cart, click on it and change the values (250g more / 250g less / delete product)

PHP - Nonce creation

/*
**  Theme scripts
*/
function scripts() {

    // Enqueue scripts
    wp_enqueue_script( 'noten-nl/js', Assets\asset_path('scripts/main.js?v=' . VERSION), ['jquery-core', 'wp-util'], null, true );

    // Localize script
    wp_localize_script( 'noten-nl/js', 'shop', array(
        'url'           => admin_url( 'admin-ajax.php' ),
        'cart_more'     => wp_create_nonce( 'cart-more-nonce' ),
        'cart_less'     => wp_create_nonce( 'cart-less-nonce' ),
        'cart_delete'   => wp_create_nonce( 'cart-delete-nonce' )
    ));

}
add_action( 'wp_enqueue_scripts', __NAMESPACE__ . '\\scripts', 999 );

Javascript (calls cart_more PHP function below)

/*
**  Edit items in cart
*/
function cartAction(event) {

    // Log
    console.log('cartAction');

    // Variables
    var action = $(event.currentTarget).attr('data-action'),
        product = $('.cart-products-scroll .row.active');

    // Load
    product.children('.cart-row-item-loading').show();

    // AJAX
    wp.ajax.send('cart_' + action, {
        data: {
            nonce:      shop['cart_' + action],
            id:         product.attr('data-product-id'),
            quantity:   product.attr('data-product-quantity'),
            key:        product.attr('data-product-cart-item-key')
        },
        success: function (fragments) {

            // Replace fragments
            $.each(fragments, function (key, value) {
                $(key).replaceWith(value);
            });

        },
        error: function (response) {
            console.log(response);
        }
    });

}

PHP

function cart_more() {

    // Log
    write_log( 'cart_more()' );

    // Variables
    $nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : '';
    $product_id = isset( $_POST['id'] ) ? $_POST['id'] : '';
    $product_quantity = isset( $_POST['quantity'] ) ? $_POST['quantity'] : '';

    // Check data
    if ( wp_verify_nonce( $nonce, 'cart-more-nonce' ) && ! empty( $product_id ) && ! empty( $product_quantity ) ) {

        /*
        ** Removed for readability
        */

        // Send success
        wp_send_json_success( $fragments );

    } else {

        // Send error
        wp_send_json_error( ':\'(' );

    }

}
add_action( 'wp_ajax_nopriv_cart_more', __NAMESPACE__ . '\\cart_more' );
add_action( 'wp_ajax_cart_more', __NAMESPACE__ . '\\cart_more' );

Question

Why does nonce verification only succeed after adding something to my cart?

like image 510
Dave van Hoorn Avatar asked Feb 19 '17 09:02

Dave van Hoorn


1 Answers

In order to make product pages cacheable WooCommerce sessions are not created until a cart is created.1,2

WooCommerce overrides one of the nonce parameters with a value which changes based on whether or not a WooCommerce session has been created.3,4

When you create the nonce for a new user with no cart and no session the nonce is calculated with one set of inputs. When you check the nonce after an item has been added to the cart the check value is generated with a different set of inputs because the WooCommerce session now exists. This causes a different nonce value to be generated and the nonce check against the old nonce value to fail.

One workaround is to proactively create the WooCommerce session before creating the nonces. Note this could impact how your site is cached.

  1. https://github.com/woocommerce/woocommerce/issues/4920#issuecomment-35846419
  2. https://mikejolley.com/2013/12/20/problems-with-cart-sessions-and-woocommerce/
  3. https://developer.wordpress.org/reference/functions/wp_create_nonce/
  4. https://github.com/woocommerce/woocommerce/blob/c16acc6b5104acb0ed082e7df1c63dfd77598459/includes/class-wc-session-handler.php#L224
like image 159
user Avatar answered Sep 30 '22 18:09

user