0

I’m using this plugin - Woocommerce PDF Vouchers - and it works great out of the box. However, after customizing my theme's 'add to cart' to AJAXm it’s not displaying the custom data in both the mini cart and cart page. It works fine if i revert to the default add to cart though so there’s definitely smth wrong with my AJAX callback. This is what I’m using:

// JS
$add_to_cart.on(‘click’, function(e) {
    e.preventDefault();
    var var_id = $(this).siblings(‘.variation_id’).val();
    var prod_id = $(this).siblings(‘input[name=“product_id”]‘).val();
    var item = {};
    var $variation_form = $( this ).closest( ‘.variations_form’ );
    var variations = $variation_form.find( ‘select[name^=attribute]’ );
    var mini_cart = $(‘.mini-cart-menu-item’);
    var mini_cart_contents = $(‘.widget_shopping_cart’);
    var url = ajax_obj.ajax_url;
    var data = {
        action: ‘nerb_ajax_add_to_cart_woo’,
        ‘product_id’: prod_id,
        ‘variation_id’: var_id,
        ‘variation’: item
    }

    variations.each( function()  {
        var $this = $(this);
        attributeName = $this.attr( ‘name’ );
        attributevalue = $this.val();
        item[attributeName] = attributevalue;
    });

    $.post( url, data, function(response) {         
        if (response) {
            mini_cart.html(response.fragments['a.cart-contents']);
            mini_cart_contents.html(
             response.fragments['div.widget_shopping_cart_content']
            );
        }       
    });
})

//PHP AJAX Callback
function nerb_ajax_add_to_cart_woo() {
    $product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
    $product = wc_get_product( $product_id );
    $quantity = empty( $_POST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_POST['quantity'] );
    $variation_id = $_POST['variation_id'];
    $variations  = $_POST['variation'];
    $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations, $cart_item_data );

    if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) {
        do_action( 'woocommerce_ajax_added_to_cart', $product_id );
        if ( get_option( 'woocommerce_cart_redirect_after_add' ) == 'yes' ) {
            wc_add_to_cart_message( $product_id );
        }
        // Return fragments
        WC_AJAX::get_refreshed_fragments();
    } 
    die();  
}

add_action( 'wp_ajax_nerb_ajax_add_to_cart_woo', 'nerb_ajax_add_to_cart_woo' );
add_action( 'wp_ajax_nopriv_nerb_ajax_add_to_cart_woo', 'nerb_ajax_add_to_cart_woo' );

I believe it’s smth to do with ‘var item = {}’ in my JS function. I guess I could select the custom fields and assign the value to the variable but i think it doesnt make sense to have to re-do again if I add new custom fields in the future. So I’m not sure what values to assign to ‘var item’

0

I had the same problem and just happened to have figured out a way - probably not the best but works for now.

These are the steps I took to see how it was done behind the scenes without doing any AJAX:

  1. I first I had to dump $_POST on the woocommerce_add_to_cart_validation hook to see how the plugin was sending its data. It was doing something like:

    [recipient_name] => Array
    (
        [12345] => 
        [67890] => John Smith
    )
    
    [recipient_email] => Array
    (
        [12345] => 
        [67890] => john@smith.com
    )
    
    [message] => Array
    (
        [12345] => 
        [67890] => Enjoy your voucher!
    )
    

The number keys are the variation IDs.

  1. Then I dumped the cart data to see how it had been saved to the cart:

    add_action( 'woocommerce_after_cart', 'but_whats_in_the_cart' );
    function but_whats_in_the_cart() {
        $cart = WC()->cart->get_cart();
        echo '<pre>';
        print_r($cart);
        echo '</pre>';
    }
    

    And it gave me this:

    Array
        (
        [825d53934cc8498d59e3e553a5afa896] => Array
        (
            [voucher_template_id] => 27
            [voucher_image_id] => 378932
            [voucher_random] => voucher_5bc8babc5dee6
            [voucher_item_meta_data] => Array
            (
                [recipient_name] => John Smith
                [recipient_email] => john@smith.com
                [message] => Enjoy your voucher!
            )
    ... array continues.
    
  2. So on my AJAX call I made sure I sent those three pieces of data and then formatted and put them in an array with key [voucher_item_meta_data].

The whole 'Add to cart' bit on the site I'm building is quite specific because instead of showing the variations in the standard WooCommerce style (in a select element), I have them in a list and users just check the variations they want, their quantity and add them all to the cart at once. All the data I'm passing is on data attributes and the PDF Voucher form is custom. Basically, I'm not using the WooCommerce add to cart form at all.

But in your example you'll need to grab the PDF Voucher form data and send it via AJAX, maybe like this?

var recipient_name = $('#selector_for_name').val();
var recipient_email = $('#selector_for_email').val();
var message = $('#selector_for_message').val();

Then, the WP AJAX is the tricky bit. I could not find a "proper" way to pass data to the cart via AJAX. NOT data for a product, but cart data for each cart key.

I found some post about having to loop through the cart keys and add data this way so I gave it a try and it worked.

So, having passed your form data as above, you can then do this:

function nerb_ajax_add_to_cart_woo() {
// declare global
global $woocommerce;

$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
$product = wc_get_product( $product_id );
$quantity = empty( $_POST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_POST['quantity'] );
$variation_id = $_POST['variation_id'];
$variations  = $_POST['variation'];
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations, $cart_item_data );

// pdf voucher form data
$pdf_form_data['recipient_name'] = $_POST['recipient_name'];
$pdf_form_data['recipient_email'] = $_POST['recipient_email'];
$pdf_form_data['message'] = $_POST['message'];

if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) {
    do_action( 'woocommerce_ajax_added_to_cart', $product_id );

    /* HERE IS THE BIT THAT DOES THE TRICK */
    // you need to cycle the cart replace the meta of the correspondant key
    $cart = $woocommerce->cart->cart_contents;
    foreach ($cart as $key => $item) {
        // check if voucher meta already exists for an item, and if so, skip
        if($item['voucher_item_meta_data']) {
            continue;
        } else {
          // make sure we only add voucher data to the variation just added and only if data isn't there already so we don't override previously added ones
            if( $item['variation_id'] === $variation_id && !isset($item['voucher_item_meta_data']) ) {
                $woocommerce->cart->cart_contents[$key]['voucher_item_meta_data'] = $pdf_form_data;
            }
        }
    }

    // This is the magic: With this function, the modified object gets saved.
    $woocommerce->cart->set_session();

    
    if ( get_option( 'woocommerce_cart_redirect_after_add' ) == 'yes' ) {
        wc_add_to_cart_message( $product_id );
    }
    // Return fragments
    WC_AJAX::get_refreshed_fragments();
} 
die();  
}

add_action( 'wp_ajax_nerb_ajax_add_to_cart_woo', 'nerb_ajax_add_to_cart_woo' );
add_action( 'wp_ajax_nopriv_nerb_ajax_add_to_cart_woo', 'nerb_ajax_add_to_cart_woo' );

I have not tested this code with your current set up, but this is more or less what I have done and it has worked for me.

UPDATE - 19 Oct 2018

I found a bug and have updated the PHP code above. Since we're first adding the product and then adding the voucher meta to the cart, when adding a second product the code was replacing the voucher meta data of the first product with the one from the second one (and so on). So we just need to check for the array key voucher_item_meta_data and if it exists, skip it:

// check if voucher meta already exists for an item, and if so, skip
if($item['voucher_item_meta_data']) {
    continue;
} else {
    // make sure we only add voucher data to the variation just added and only if data isn't there already so we don't override previously added ones
    if( $item['variation_id'] === $variation_id && !isset($item['voucher_item_meta_data']) ) {
        $woocommerce->cart->cart_contents[$key]['voucher_item_meta_data'] = $cart_item_data;
    }
}
2
  • Thanks for this! I'll give your code a spin and update u! – Edmund Chan Oct 23 '18 at 8:31
  • No worries, let me know how it goes. You'll probably come back here and see that I add more updates, because I'm literally trying to figure out things myself :) – elmediano Oct 23 '18 at 15:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.