I'm working on a site that lets a user enter data from a form and have it attached to a product. I was originally using:
$cart_item_data ['Entry Link'] = $formUrl;
$woocommerce->cart->add_to_cart($productID,$quantity,0,$cart_item_data);
With $formUrl being a link to the form data. Whenever a user made an order, under the product would be 'Entry Link' with the url.
We later had to add variations to the product so the line looked like:
$woocommerce->cart->add_to_cart($productID,$quantity,$typeID,$cart_item_data);
With $typeID being the variation ID. Once I added the $typeID, only the variation showed up on the order in the backend and not the 'Entry Link'.
If I reset $typeID to '0', the entry link shows up when an order is made. I also tried using the variation id in place of the product id but was still getting the same issue. I looked at the documentation and it should be working.
I need both the variation and the 'Entry Link' to be entered and visible from the backend.
This was the part requested by Vincenzo Di Gaetano in the comments
$formUrl = $_SERVER['SERVER_NAME'].'/wp-admin/admin.php?page=gf_entries&view=entry&id='.$formID.'&lid='.$entryID;
$cart_item_data['Entry Link'] = $formUrl;
$variationAttributes['Per'] = 1000;
$woocommerce->cart->add_to_cart($productID,$quantity,$typeID,$variationAttributes,$cart_item_data);
I added variationAttributes to it with 'Per' lining up with the attribute name, '1000' represents the value of that attribute. I hardcoded it in for testing. When I echo just the $formUrl, it does return the correct url
You are setting only 4 arguments instead of 5 for the add_to_cart method of the WC_Cart class.
Try replacing this:
$woocommerce->cart->add_to_cart( $productID, $quantity, $typeID, $cart_item_data );
with:
$woocommerce->cart->add_to_cart( $productID, $quantity, $typeID, $variation, $cart_item_data );
Here is an example of how to add a variation to the cart:
WordPress WooCommerce - Add a variable product to cart using the WC_Cart class
This will not be enough to display the cart item data as the meta of the order item.
Based on this question Save and display product custom meta on WooCommerce orders and emails you will need to save the value as a order item meta data:
// save the cart item data as custom order item meta data
add_action( 'woocommerce_checkout_create_order_line_item', 'save_cart_item_data_as_order_item_meta_data', 20, 4 );
function save_cart_item_data_as_order_item_meta_data( $item, $cart_item_key, $values, $order ) {
if ( isset( $values['Entry Link'] ) ) {
$item->update_meta_data( __( 'Entry Link'), $values['Entry Link'] );
}
}
The code has been tested and works. Add it to your active theme's functions.php.
Here is the result:
Related
I have only one product ('testare-psihologica'). When the buyer buys it, he must associate this product with additional information (specific 'test' title) that will influence the price. I do not want to use variable products because those 'test' titles will be a lot, so variable products are not very convenient for me. In this situation, I chose to add this product multiple times as separate items but with different 'test' titles.
add_filter( 'woocommerce_add_cart_item_data', 'add_cart_simple_product_custom_price', 20, 2 );
function add_cart_simple_product_custom_price( $cart_item_data, $product_id ) {
//add selected test ID to 'testare-psihologica' cart item
if( isset( $_GET['test'] ) ) {
$test_id = get_page_by_path( $_GET['test'], OBJECT, 'tests' )->ID;
$test_title = get_post_field( 'post_title', $test_id );
$cart_item_data['test_title'] = $test_title;
}
// add product to cart multiple times, but as different items
$unique_cart_item_key = md5( microtime() . rand() );
$cart_item_data['unique_key'] = $unique_cart_item_key;
return $cart_item_data;
}
After this, the 'test' titles will be displayed in the cart and checkout pages under the product name, and then they will be added to the order as metadata (with other code).
The only disadvantage of this approach is that when the product is added to the cart several times but with the same (identical) 'test' title, it also appears as separate items, but I would like these items to appear grouped as one and only increase their quantity. So, instead of this:
I want this:
And I want to do this programmatically. How can this be achieved?
It seems that the following lines of code are redundant:
$unique_cart_item_key = md5( microtime() . rand() );
$cart_item_data['unique_key'] = $unique_cart_item_key;
So to answer your question you can just delete those lines
Because I don't have the same get data that you use in your answer, I made a proof of concept, divided into 3 steps:
1. Add input field before the add to cart button on the single product page
function action_woocommerce_before_add_to_cart_button() {
// Add a new input field, allowing the customer to set "test"
echo '<div class="my-div"><input type="text" id="test" name="test"></div>';
}
add_action( 'woocommerce_before_add_to_cart_button', 'action_woocommerce_before_add_to_cart_button' );
2. Add 'test' value to cart item
function filter_add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
// Add test to cart item
if ( ! empty ( $_POST[ 'test' ] ) ) {
$cart_item_data['test_title'] = sanitize_text_field( $_POST['test'] );
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'filter_add_cart_item_data', 10, 3 );
3. Optionally display custom data in cart and checkout pages
// Optionally display custom data in cart and checkout pages
function filter_woocommerce_get_item_data( $cart_data, $cart_item = null ) {
if ( isset( $cart_item['test_title'] ) ) {
$cart_data[] = array(
'name' => 'Test title',
'value' => $cart_item['test_title']
);
}
return $cart_data;
}
add_filter( 'woocommerce_get_item_data', 'filter_woocommerce_get_item_data', 99, 2 );
Then apply the following steps on the first step:
Insert group1 as value and press the add to cart button
Insert group2 as value and press the add to cart button
Insert group1 as value and press the add to cart button
The product with value group1 will automatically be grouped based on the corresponding value:
We have created a site using WooCommerce and WordPress with predefined products.
However, Product A must have variations, to resolve this, we added custom fields such as Colors, Dimensions, etc...
Now once the end-users are navigating to the product, we are able to fetch the custom field values. We also modified the UI so that users can pick and choose from these custom fields. (We have a preview of the modifications done via JS/CSS), so for instance, if they choose a green color we use JS to add a layer of green so that the preview is real time.
Now, we have one challenge.
-> What is the best way to go about adding this product PLUS all modifications done to the cart?
So for instance Product A was modified (on the front-end) using data pulled from the custom fields to include Color: Green and Size: 100x100 instead of defaults values. How do we store this and pass the customized product to the cart?
Appreciate the help!. Glad to add more details if something is not clear.
(There are plugins out there that can provide this functionality; Things similar to WooCommerce Product Add-On, etc... However, we have to custom develop the feature.)
It requires some steps.
1). For your product page:
First you might need to add hidden fields to the add to cart form for each custom field like (example):
add_action( 'woocommerce_before_add_to_cart_button', 'add_hidden_empty_input_fields' );
function add_hidden_empty_input_fields() {
?>
<input type="hidden" name="hidden_color" id="hidden_color" value="">
<input type="hidden" name="hidden_dimensions" id="hidden_dimensions" value="">
<?php
}
Then you will have to make some changes to your Javascript code to set the custom fields chosen values in those hidden fields.
2). Pass the custom fields selected values as custom cart item data (example):
add_filter('woocommerce_add_cart_item_data', 'add_custom_field_data', 10, 3 );
function add_custom_field_data( $cart_item_data, $product_id, $variation_id ) {
if ( isset($_POST['hidden_color']) && ! empty($_POST['hidden_color']) ) {
$cart_item_data['color'] = esc_attr($_POST['hidden_color']);
}
if ( isset($_POST['hidden_dimensions']) && ! empty($_POST['hidden_dimensions']) ) {
$cart_item_data['dimensions'] = esc_attr($_POST['hidden_dimensions']);
}
return $cart_item_data;
}
And optionally display values on cart items (example):
add_filter( 'woocommerce_get_item_data', 'display_custom_cart_item_data', 10, 2 );
function display_custom_cart_item_data( $cart_data, $cart_item ) {
if ( isset($cart_item['color']) ) {
$cart_data[] = array( "name" => __("Color"), "value" => $cart_item['color'] );
}
if ( isset($cart_item['dimensions']) ) {
$cart_data[] = array( "name" => __("Dimensions"), "value" => $cart_item['dimensions'] );
}
return $cart_data;
}
3). Save the custom cart item data as custom order item meta data (example):
add_action( 'woocommerce_checkout_create_order_line_item', 'save_custom_order_item_meta_data' , 10, 4 );
function save_custom_order_item_meta_data( $item, $cart_item_key, $values, $order ) {
if ( isset($values['color']) ) {
$item->add_meta_data( __("Color"), $values['color'] );
}
if ( isset($values['dimensions']) ) {
$item->add_meta_data( __("Dimensions"), $values['dimensions'] );
}
}
Note: The data is going to be displayed on everywhere on orders and email notifications.
Code goes in functions.php file of the active child theme (or active theme). It should work.
The variations have a post_id, you would just use the variation post_id instead of the main product one.
I've a single piece of custom metadata to a WooCommerce order and now I want to display this on the thank you page after checkout, however, the data isn't available. The data is saved and available in the admin, I just can't seem to access it.
function custom_order_item_meta( $item_id, $values ) {
if ( ! empty( $values['custom_option'] ) ) {
woocommerce_add_order_item_meta( $item_id, 'custom_option', $values['custom_option'] );
}
}
add_action( 'woocommerce_add_order_item_meta', 'custom_order_item_meta', 10, 2 );
But when I dump out the wc_get_order my meta data isn't there.
I'm using;
woocommerce_add_order_item_meta()
to save the data but dumping out var_dump(wc_get_order( $order->id )); also doesn't show my custom meta field
is there another hook I should be using to access this data?
The data that you are looking for is not order meta data, but order item meta data and is located in wp_woocommerce_order_itemmeta database table (see below how to access this data).
Since woocommerce 3, a much better hook replace old woocommerce_add_order_item_meta hook.
Displayed and readable order item meta data:
To make custom order item meta data displayed everywhere, the meta key should be a readable label name and without starting by an underscore, as this data will be displayed under each order item.
The code:
add_action( 'woocommerce_checkout_create_order_line_item', 'custom_order_item_meta', 20, 4 );
function custom_order_item_meta( $item, $cart_item_key, $values, $order ) {
if ( isset( $values['custom_option'] ) ) {
$item->update_meta_data( __('Custom option', 'woocommerce'), $values['custom_option'] );
}
}
In "Order received" (thankyou) page, you will get something like:
This will be displayed too in backend and email notifications.
To access this order item data you need to get items from the order object in a foreach loop:
foreach( $order->get_items() as $item_id => $item ){
$custom_data = $item->get_meta( 'Custom option' );
}
To Get the first order item (avoiding a foreach loop), you will use:
$items = $order->get_items(); // Order items
$item = reset($items); // The first Order item
$custom_data = $item->get_meta( 'Custom option' ); // Your custom meta data
Related: Replace woocommerce_add_order_item_meta hook in Woocommerce 3.4
I am trying to redirect my custom shop page to cart page after user select custom attributes (liability and hours) and then clicks the purchase button.
I have written custom JS code which retrieves the variation_id and attributes value and append it to the URL so that it automatically gets added to cart and get's redirected to cart page.
href="yourdomain.com/?add-to-cart=47&variation_id=88&quantity=3&attribute_pa_colour=blue&attribute_pa_size=m"
This is the URL format which I have found in a blog: (https://businessbloomer.com/woocommerce-custom-add-cart-urls-ultimate-guide/) and I made my link in this format.
My link is:
localhost/wordpress/cart/?add-to-cart=1185&variation_id=1641&quantity=1&attribute_pa_liability=2_million&attribute_pa_hours=500_hours
Where liability and hours is my custom attribute which has values as 1 million, 2 million and 500 hours, 750 hours respectively.
But when it get's redirected to cart page woocommerce give me an error and shows it's alert box which shows the error message as "liability and hours are required fields".
I think woocommerce is unable to get the attribute values through my URL.
Can anyone explain why is this happening and what is the error if there is any?
Updated
This "Business Bloomer" guide is a little outdated… You need 2 things:
1). The correct URL
You don't need to addto cart the product and the variation Id with all related attributes. You just need to add to cart the variation ID + your custom attributes like this: localhost/wordpress/cart/?add-to-cart=1641&quantity=1&pa_liability=2_million&pa_hours=500_hours
2). Registering (and display) your custom attributes:
// Store the custom data to cart object
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_product_data', 10, 2 );
function save_custom_product_data( $cart_item_data, $product_id ) {
$bool = false;
$data = array();
if( isset( $_REQUEST['pa_liability'] ) ) {
$cart_item_data['custom_data']['pa_liability'] = $_REQUEST['pa_liability'];
$data['pa_liability'] = $_REQUEST['pa_liability'];
$bool = true;
}
if( isset( $_REQUEST['pa_hours'] ) ) {
$cart_item_data['custom_data']['pa_hours'] = $_REQUEST['pa_hours'];
$data['pa_hours'] = $_REQUEST['pa_hours'];
$bool = true;
}
if( $bool ) {
// below statement make sure every add to cart action as unique line item
$cart_item_data['custom_data']['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'custom_variations', $data );
}
return $cart_item_data;
}
// Displaying the custom attributes in cart and checkout items
add_filter( 'woocommerce_get_item_data', 'customizing_cart_item_data', 10, 2 );
function customizing_cart_item_data( $cart_data, $cart_item ) {
$custom_items = array();
if( ! empty( $cart_data ) ) $custom_items = $cart_data;
// Get the data (custom attributes) and set them
if( ! empty( $cart_item['custom_data']['pa_liability'] ) )
$custom_items[] = array(
'name' => 'pa_liability',
'value' => $cart_item['custom_data']['pa_liability'],
);
if( ! empty( $cart_item['custom_data']['pa_hours'] ) )
$custom_items[] = array(
'name' => 'pa_hours',
'value' => $cart_item['custom_data']['pa_hours'],
);
return $custom_items;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works
You will need to add this data to the order items too
First uncheck the ajax add to cart option from admin panel
Then you need to make variation with your attributes then find out product id, quantity, attribute slug and attribute name(used to show in cart) and variation id and then make your cart url like given below.
The add to cart link with attribute is : https://www.your-domain.com/?add-to-cart=(product id)&quantity=(numeric quantity)&attribute_pa_(attribute slug)=(attribute name)&variation_id=(variation id)
For more details you can visit http://www.codemystery.com/wordpress-woocommerce-add-cart-link-variations/
The other answers are correct in regards to the add to cart url format (should be: /add-to-cart=product_id&my_custom_attr=whatever&my_custom_attr2=somthing)
Then there is a very good plugin to handle this type of functionality for storing the custom product attributes called WC Fields Factory.
And the writer of the plugin also has a great article on how to do this w/o need of a plugin. As well as an answer on a similar question here.
I have found similar solutions to this, for example: "How to limit orders to one category". I have tried to modify the code but it's not specific enough.
In my case, each Vendor is defined by a product attribute value, 8 Terms at all. If the cart contains products from more than 3 different Terms, I need to set up a message that says "Sorry, you may only order from 3 different Vendors at a time".
This is what I'm using as a starting point:
add_action( 'woocommerce_add_to_cart', 'three_vendors' );
function three_vendors() {
if ATTRIBUTE = SELECT A VENDOR; NUMBER OF TERMS > 3 {
echo "Sorry! You can only order from 3 Vendors at a time.”;
}
}
The middle line is me filling in the blanks using non-php language.
I am looking for a way to define the amount of variations in the cart. If this is not possible to do with Attributes, I am open to use Categories instead.
Does anyone know how to do this?
Update: Is not possible to manage variations with woocommerce_add_to_cart_valisation hook
Instead we can use a custom function hooked in woocommerce_add_to_cart filter hook, removing the last added cart item when more than 3 vendors (items) are in cart:
// Remove the cart item and display a notice when more than 3 values for "pa_vendor" attibute.
add_action( 'woocommerce_add_to_cart', 'no_more_than_three_vendors', 10, 6 );
function no_more_than_three_vendors( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
// Check only when there is more than 3 cart items
if ( WC()->cart->get_cart_contents_count() < 4 ) return;
// SET BELOW your attribute slug… always begins by "pa_"
$attribute_slug = 'pa_vendor'; // (like for "Color" attribute the slug is "pa_color")
// The current product object
$product = wc_get_product( $variation_id );
// the current attribute value of the product
$curr_attr_value = $product->get_attribute( $attribute_slug );
// We store that value in an indexed array (as key /value)
$attribute_values[ $curr_attr_value ] = $curr_attr_value;
//Iterating through each cart item
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// The attribute value for the current cart item
$attr_value = $cart_item[ 'data' ]->get_attribute( $attribute_slug );
// We store the values in an array: Each different value will be stored only one time
$attribute_values[ $attr_value ] = $attr_value;
}
// We count the "different" values stored
$count = count($attribute_values);
// if there is more than 3 different values
if( $count > 3 ){
// We remove last cart item
WC()->cart->remove_cart_item( $cart_item_key );
// We display an error message
wc_clear_notices();
wc_add_notice( __( "Sorry, you may only order from 3 different Vendors at a time. This item has been removed", "woocommerce" ), 'error' );
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and should works for you. It will check for the attribute values regarding your specific attribute and will remove last added cart item for more than 3 attribute values.
The only annoying thing is that I can't remove the classic added to cart notice for the moment. I will try to find another way…