25

During the add_to_cart function, there is a filter to add "cart item data". The filter is woocommerce_add_cart_item_data. I expected to store my custom plugin data in this, so that the data is stored relative to the item and multiple products can be added with different data.

This all seemed to work, but I am not able to retrieve the data. I can't figure it out. The data is there, I can see it in a serialized string, but I can't pull it out.

echo '<pre>';
var_dump( WC() );

foreach( WC()->cart->get_cart() as $cart_item ) {
  var_dump( $cart_item );
  var_dump( WC()->cart->get_item_data( $cart_item ) );
}
echo '</pre>';

The first dump of WC() has a property: session->_data->cart->(serialized data). The _data property is protected, though, but I can see my custom field inside the serialized data.

The $cart_item is an array with product_id and some other data, but it does not include my custom data :(

Finally, using the get_item_data() method I thought I had it all figured out. I passed in the cart item object, and... an empty string. Same if I pass the key, rather than the cart item itself.

How am I supposed to access the cart item data?


Here is the "Add cart item data" function, which works (or at least seems to work):

function save_class_menu_selection( $cart_item_data, $product_id, $variation_id ) {
  if ( !product_is_class( $product_id ) ) return $cart_item_data;

  // Save the date, or give a fatal warning. Date is required.
  if ( !empty($_REQUEST['class-date']) ) {
    $cart_item_data['class-date'] = stripslashes($_REQUEST['class-date']);
    return $cart_item_data;
  }else{
    wp_die('<h2>Invalid Class Date Selected</h2><p>You tried to add a class to your cart, but the date selected was invalid. Please try again.</p>');
    exit;
  }
}
add_filter( 'woocommerce_add_cart_item_data', 'save_class_menu_selection', 10, 3 );
Radley Sustaire
  • 3,382
  • 9
  • 37
  • 48

2 Answers2

55

I was in the same situation today and stumbled over this question after some research. After some reverse engineering I found the problem and want to provide a solution for other which may also stumble over this question.

The problem is that the data gets sanitized when the cart items get restored from the session. So the extra cart item data IS stored into the session but on the next request it does not get restored.

There is a filter "woocommerce_get_cart_item_from_session". As first parameter you get the sanitized cart item (without extra data) and as second all data which got stored into the session (including extra data).

The solution is to hook in there and also restore your custom cart item data.

Example Code:

add_filter( 'woocommerce_add_cart_item_data', function ( $cartItemData, $productId, $variationId ) {
    $cartItemData['myCustomData'] = 'someCustomValue';

    return $cartItemData;
}, 10, 3 );

add_filter( 'woocommerce_get_cart_item_from_session', function ( $cartItemData, $cartItemSessionData, $cartItemKey ) {
    if ( isset( $cartItemSessionData['myCustomData'] ) ) {
        $cartItemData['myCustomData'] = $cartItemSessionData['myCustomData'];
    }

    return $cartItemData;
}, 10, 3 );

To also show the data at the cart/checkout page you can use the following code:

add_filter( 'woocommerce_get_item_data', function ( $data, $cartItem ) {
    if ( isset( $cartItem['myCustomData'] ) ) {
        $data[] = array(
            'name' => 'My custom data',
            'value' => $cartItem['myCustomData']
        );
    }

    return $data;
}, 10, 2 );

The final thing now is to save the data when the order is made:

add_action( 'woocommerce_add_order_item_meta', function ( $itemId, $values, $key ) {
    if ( isset( $values['myCustomData'] ) ) {
        wc_add_order_item_meta( $itemId, 'myCustomData', $values['myCustomData'] );
    }
}, 10, 3 );

You dont have to do anything else the show the data inside the backend, all order item meta data gets display automatically.

Stefan
  • 566
  • 5
  • 3
  • 1
    Thanks for this Stefan. It sounds like this is very similar to a "query var" in WordPress. That is, any data passed via POST/GET does not register as a query_var unless you specifically tell WordPress to do so. Do you know if this session data gets saved when the cart data is converted into an order? (eg, when a payment is made) – Radley Sustaire Sep 01 '15 at 16:32
  • 1
    The data does not get saved automatically but I have added some code examples to my answer on how to do this. – Stefan Sep 09 '15 at 12:09
  • I'm going to make this the accepted answer as my solution was a workaround. This looks more properly implemented. I haven't actually tested it myself, though. – Radley Sustaire Sep 09 '15 at 17:11
  • This answer was EXTREMELY helpful! Thank you for taking the time to post. Might you be able to clarify how to also show this custom data within customer payment emails? – dcolumbus Mar 16 '16 at 16:07
  • This was really helpful. Now I am trying to figure out how to make changes in the item price based on the custom value. Anyone interested to help? – aslamdoctor Apr 19 '17 at 05:18
  • could you please help https://stackoverflow.com/questions/47646781/woocommerce-hook-and-filters-for-changing-product-price-when-adding-to-cart – Abilash Erikson Dec 05 '17 at 07:08
  • Thought I would point out that you do not need the "woocommerce_add_cart_item_data" hook if you are adding the product to the cart with PHP. The function `WC()->cart->add_to_cart()` has a 5th parameter that accepts cart item data. The other hooks are still necessary. – Radley Sustaire Oct 24 '18 at 09:23
5

I could not get the default cart item data to work, unfortunately. I feel it may not be properly implemented, or may even be deprecated, as there is a lack of support and documentation.

Instead, I used a cart session variable to accomplish the same thing. It's simply an array where each key is the cart_item_key. The value of each array is yet another array, containing a key-value pair of custom fields. So it's essentially the same thing as the built-in cart item data, except stored as cart session data instead.

Here is a Gist containing some utility functions to make it easy:

https://gist.github.com/RadGH/e3444fc661554a0f8c6f


Or if you want to build it yourself, the magic is in WC()->session. Here are the two key functions for this to work:

WC()->session->get('_my_cart_item_data');
WC()->session->set('_my_cart_item_data', $cart_item_data_array);

These are the action hooks you will need:

<<<EXAMPLES
action: woocommerce_add_to_cart
desc: When an item is added to the cart. 
args: $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data

action: woocommerce_add_order_item_meta
desc: When a cart item is converted to an order item, save metadata to the order item
      using the function "wc_add_order_item_meta( $item_id, $key, $value )"
args: item_id, $values, $cart_item_key
Radley Sustaire
  • 3,382
  • 9
  • 37
  • 48