I have a custom input field in the WooCommerce cart for every cart item. When somebody clicks update cart I want to send the extra data to the server and process that data and add it to the current cart.
I can't find anywhere how to do this. Is this even possible?
I tried:
woocommerce_update_cart_action_cart_updated
in the $_POST variable the custom data is not available
Trough custom javascript
Run a ajax request every time the input field get's changed. But this is interfering with the regular way to update the WooCommerce cart. Lot's of bugs...
A hook before updating the cart
I can't find if there's a hook for sending extra data before updating the cart.
In the end the solution was quite simple. Since the cart is a regular HTML form you can add custom input data. When the cart is updated all the form data is serialised and sent trough with ajax. You just need to set the right name attribute on the input field.
It took the following steps:
Copy the woocommerce cart template.
Add your custom input in the cart item foreach loop
Give it the right name. Like this:
name="cart[<?php echo $cart_item_key; ?>][your_custom_key]"
Use the hook:
woocommerce_update_cart_action_cart_updated
In this hook you can easily access the $_POST['cart'] variable and do your stuff. For example:
$cart = WC()->cart->cart_contents;
// loop over the cart
foreach($_POST['cart'] as $cartItemKey => $values) {
$cartItem = $cart[$cartItemKey];
$yourCustomValue = $values['your_custom_key'];
// process the value, do something with it...
$cartItem['your_custom_key'] = $yourCustomValue;
WC()->cart->cart_contents[$cartItemKey] = $cartItem;
}
Et voilà. Now when you fill in the input field and update the cart, the data is stored in the cart. Now for example you can save the extra cart data on storing a new order or use the data to calculate a fee.
You can use it like this
add_filter( 'woocommerce_update_cart_action_cart_updated', function( $cart_updated ) {
$contents = WC()->cart->cart_contents;
foreach ( $contents as $key => &$item ) {
$contents[$key]['location'] = $_POST['cart'][$key]['location'];
$contents[$key]['pickup_on'] = $_POST['cart'][$key]['pickup_on'];
$contents[$key]['pickup_time'] = $_POST['cart'][$key]['pickup_time'];
$contents[$key]['pickup_day'] = $_POST['cart'][$key]['pickup_day'];
$contents[$key]['pickup_date'] = $_POST['cart'][$key]['pickup_date'];
$contents[$key]['testing'] = 'testing done!';
}
WC()->cart->set_cart_contents( $contents );
return true;
} );
Related
I'm using Wordpress forms (gravity forms plugin) and I'm trying to pass price value to payment platform. I'm using just a hook with code that after form submission passes value to URL and redirects to payment page:
add_action('gform_after_submission', 'link_to_payment', 10, 2);
function link_to_payment($entry, $form) {
$price = $entry['6.2'];
header("Location: http://www.******.***/test.php?price='.$price");
exit();
}
Obviously problem with this is just that any person with webtools can change the value of $entry['6.2'] in html code and get a different price to pay. My question is, is there a safe way to pass value from HTML page to PHP code that user couldn't change in HTML code?
As these are the price of products which is set from the backend, you don't need to get the price from the frontend.
Create a new hidden field which has ID of the product. Let's say the name of field is 6.3.
add_action('gform_after_submission', 'bks_link_to_payment', 10, 2);
function bks_link_to_payment($entry, $form) {
$product_id = $entry['6.3']; // Make sure you change the field to the one you create.
$product = wc_get_product( $product_id ); // get product object from the backend.
// If the product exists.
if ( $product ) {
$price = $product->get_price(); // This would give you the price of the product.
header("Location: http://www.******.***/test.php?price='.$price");
exit();
}
}
So, in case someone changes the id of the product using webtools you are making sure that the product exists and the price is fetched from the database so it can't be altered.
I have created product addons for products in my cart. I am associating each product with an image saved to the filesystem, so when you go to view an order you can see the image that was created with the product.
When an image is saved, the cart item gets a custom key. This custom key is used in a cookie to carry the path to the image through the checkout process
if (!function_exists('force_individual_cart_items')) {
function force_individual_cart_items( $cart_item_data, $product_id ){
$unique_cart_item_key = md5( microtime().rand() );
$cart_item_data['unique_key'] = $unique_cart_item_key;
if (isset($_COOKIE['CustomImagePath'])) {// if image path exists that needs to be saved
$imagePath = $_COOKIE['CustomImagePath']; // get image path
$imagePaths = (isset($_COOKIE['ImagePaths']) ? json_decode(stripslashes(html_entity_decode($_COOKIE['ImagePaths'])), true) : array());
$imagePaths[$unique_cart_item_key] = $imagePath; //asscoiate image path with product cart key
setcookie('ImagePaths', json_encode($imagePaths),0,'/'); // save association in image paths cookie
unset($_COOKIE['CustomImagePath']);
setcookie('CustomImagePath', null, -1, '/');
}
return $cart_item_data;
}
}
add_filter( 'woocommerce_add_cart_item_data','force_individual_cart_items', 10, 2 );
When the order is created I then add a new row into the woocommerce_item_meta table with the meta_key of "Custom Image". The issue I am running into is associating the order item with the cart_item_key.
(in the woocommerce_thankyou hook)
global $wpdb, $wp;
$query = "SELECT order_item_id FROM wp_woocommerce_order_items WHERE order_id = $order_id";
$result = $wpdb->get_results($query, true);
$imagePaths = json_decode(stripslashes(html_entity_decode($_COOKIE['ImagePaths'])), true);
foreach ($result as $order_item) {
$item_id = $order_item->order_item_id;
}
$cart_item_custom_key = NOT AVAILABLE IN THE ORDER ITEM
$filePath = $_COOKIE[$cart_item_custom_key];
$wpdb->insert('wp_woocommerce_order_itemmeta', array('order_item_id'=>$post->ID, "meta_key"=>'Custom Image', 'meta_value'=>$filePath))
For example let's say a user selects 3 images. In the cart the first product will have a custom key of 1, the second will have a custom key of 2, and the third a custom key of 3. Using
$woocommerce->cart->get_cart_contents()[cart_item_key]['unique_key'];
I can get that unique key while I have access to the cart. Once the order is created however, order_item does not have that key. Order one, two, and three no longer have custom keys. So I cannot get the image from the cookie with the associated key.
$filePath = $_COOKIE[ ? KEY NO LONGER EXISTS ? ];
$wpdb->insert('wp_woocommerce_order_itemmeta', array('order_item_id'=>$post->ID, "meta_key"=>'Custom Image', 'meta_value'=>$filePath));
is there a way to retrieve the key that that cart item had, because the order item does not seem to have it?
If you just need to get cart item key, save it as custom hidden order item meta data using:
add_action('woocommerce_checkout_create_order_line_item', 'save_cart_item_key_as_custom_order_item_metadata', 10, 4 );
function save_cart_item_key_as_custom_order_item_metadata( $item, $cart_item_key, $values, $order ) {
// Save the cart item key as hidden order item meta data
$item->update_meta_data( '_cart_item_key', $cart_item_key );
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
To get this cart item key from the order item you will use something like:
// Get the WC_Order Object from order ID (if needed)
$order = wc_get_order( $order_id );
// Loop though order items
foreach ( $order->get_items() as $item ){
// Get the corresponding cart item key
$cart_item_key = $item->get_meta( '_cart_item_key' );
}
My opinion: You are making things much more complicated than they should be:
Instead of using cookies, you should better use WC_Sessions (if this is really needed). But it should be better to add all required data in hidden input fields on the product page…
You should better set all required data as custom cart item data when the product is added to cart with woocommerce_add_cart_item_data hook (so no need of cookie or something else).
Also you should not use woocommerce_thankyou action hook to add order item custom metadata for many reasons as there is specifically dedicated hooks for that: Once the order is created you can use woocommerce_checkout_create_order_line_item action hook, to save your custom cart item data as order item meta data.
With your provided code I can't help more than that for instance.
I have setup a local Wordpress environment with WooCommerce. The goal is a buy-one-get-one of equal or lesser value scenario.
I have the cart displaying a single item per line. I have isolated the cart products by 'key' not 'product_id' which is necessary for the equal or lesser portion of the requirements. I have created an array of necessary 'key' and am matching that against the cart contents by 'key'. If the keys match, 'set_price('0.00');'
This works on the cart page and checkout page. It all works beautifully until I process the order (currently using COD option only). Then all of the prices reset to the regular price as it appears on the product page (the "regular price"). So the orders do not reflect the actual cost.
Below is the code I have:
function resetPrice( $cart_obj ) {
global $allFreeItems; //all items in cart (and relevant data) that need to be free
$comparison_ids = array(); //isolate keys for comparison
foreach ($allFreeItems as $key => $value) {
$comparison_ids[] = $allFreeItems[$key][1]; //get unique key for each line item
}
foreach ( $cart_obj->get_cart() as $cart_item ) {
// The corresponding product key of line item
$product_key = $cart_item['key'];
// Compare value of above to array of key's and change value
if (in_array($product_key, $comparison_ids)) {
$cart_item['data']->set_price( 0.00 );
}
// else
// {
// $cart_item['data']->get_price();
// }
}
add_action( 'woocommerce_after_checkout_form', 'resetPrice');
add_action( 'woocommerce_before_calculate_totals', 'resetPrice');
I thought perhaps I wasn't using the correct hook, but all examples point to woocommerce_before_calculate_totals. The only difference I see is the everyone keeps using ['product_id'] rather than how I am doing it by [key] Is there something that happens when I click the "place order" button that I am not seeing? Anyone know a way around this?
I want to get the value of _product_id on the payout page (thankyou.php), can somebody help me with this.
I have attached an image of the field I need exactly that value
You can use woocommerce_thankyou hook to get the product ID's in
thankyou page
function wh_getProductIds($order_id)
{
//getting order object
$order = wc_get_order($order_id);
$product_id_arr = [];
//getting all line items
foreach ($order->get_items() as $item)
{
$product = $item->get_product();
$product_id_arr = $product->get_id(); //storing the product ID
//$product_sku = $product->get_sku();
}
//$product_id_arr has all the order's product IDs
//now you can do your stuff here.
}
add_action('woocommerce_thankyou', 'wh_getProductIds', 10, 1);
Code goes in functions.php file of your active child theme (or theme). Or also in any plugin php files.
Code is tested and works. version 3.x or above
Related:
Woocommerce Get Orders on Thank you page and pass data javascript snippet
WooCommerce Conversion Tracking Script for two Pixel
woocommerce_thankyou hook not working
Hope this helps!
Problem I am having here is that people go to a Product page, set a quantity on how much they want of that product and add to cart (which than takes them to the cart page). Client wants the ability to go back to the shop/product page if they want to make further changes to that product (honestly this is strange, since they can do this on the cart page, but whatever). But when people go to update the quantity on the product page, instead of updating the quantity, it adds to the existing quantity for that product.
How to get it to update the existing quantity when the quantity has been submitted more than once on the product page? Is there a woocommerce loop that I can take advantage of here?
Thanks guys, I have dug through the plugin and coded the solution below:
add_action('woocommerce_add_to_cart_handler', 'update_product_in_cart', 11, 2);
function update_product_in_cart($p, $q) {
global $woocommerce;
$cartItem = $woocommerce->cart->cart_contents;
$currentProductId = $q->id;
$wCart = $woocommerce->cart->get_cart();
// If cart already exists, and product exists, than remove product, and add the new product to it.
if ($wCart)
{
$cart_item_keys = array_keys($wCart);
foreach($cart_item_keys as $key)
{
foreach($cartItem as $item)
{
$productItemId = $item['product_id'];
if ($productItemId == $currentProductId)
{
// If you want to empty the entire cart...
// $woocommerce->cart->empty_cart();
// If you want to remove just the product from the cart...
$woocommerce->cart->set_quantity($key, 0);
}
}
}
}
// This adds the product to the cart...
return $q;
}
This gets added to functions.php, and basically, if the product id exists in the cart, it removes the product and the return of $q adds in the new product info.
Works a charm!