This question already has an answer here:
Get in WooCommerce cart the product ID of a cart item
(1 answer)
Closed 4 years ago.
I try all of code from google, but none of them works.
such as:
$items = WC()->cart->get_cart();
$product_id = end($items)['data']->post->ID;
For example,
shoes have two different colors: black and gray. I added black shoes, then gray shoes, I order black shoes in the end.
It should return black shoes's ID, but the code on the top will shows gray shoes's id.
I want last added product, not the last position product.
You can put the products into an array and pick the last one using the php end() function as follows:
global $woocommerce;
//get cart items
$items = $woocommerce->cart->get_cart();
$ids = array();
foreach($items as $item => $values) {
$_product = $values['data']->post;
//push each id into array
$ids[] = $_product->ID;
}
//get last product id
$last_product_id = end($ids);
//get product variation details
$variations = get_variation_data_from_variation_id( $last_product_id );
Then define get_variation_data_from_variation_id($item_id) as follows:
//function to get product variation
function get_variation_data_from_variation_id( $item_id ) {
$_product = new WC_Product_Variation( $item_id );
$variation_data = $_product->get_variation_attributes();
//return variation detail
return woocommerce_get_formatted_variation( $variation_data, true );
}
That means you probably access the cart Object before It's created, You will need to place that code inside 'wp' hook for example.
add_action('wp', function(){
$product_id = end( WC()->cart->cart_contents)['product_id'];
});
Edited
I think you were looking for product attribute IDs? Like green or blue etc.
$cart = WC()->cart->get_cart();
$variation = end($cart)['variation'];
// This will have ID, slug, count, etc.
echo json_encode( get_term_by( 'name', end($variation) , str_replace( "attribute_", "", key($variation))) );
If you are specific about you attribute like just size change it like this based on your ta
$cart = WC()->cart->get_cart();
$variation = end($cart)['variation']['attribute_pa_size'];
// This will have ID, slug, count, etc.
echo json_encode( get_term_by( 'name', $variation , 'pa_size') );
Related
I'm really stuck on this and I'd really appreciate any help with this.
The goal is to count the number of items in each category on a Woocommerce order so that each section can be headed by the category name and number of products. eg:
Burgers x 5
Below this will then be a list of all the burgers on that order.
Now I thought I had this working with this code:
$categories = [];
foreach ($order->get_items() as $item) {
$product_id = $item['product_id'];
$meta = $item['item_meta'];
$meta = array_filter($meta, function ($key) {
return !in_array($key, Order::getHiddenKeys());
}, ARRAY_FILTER_USE_KEY);
$terms = get_the_terms($product_id, 'product_cat');
$cat_id = $terms[0]->term_id;
$categories[$cat_id][] = $item;
$cat_name = $terms[0]->name;
}
foreach($categories as $category => $items){
?>
<tr>
<td colspan="3">
<h4>
<?php
if( $term = get_term_by( 'id', $category, 'product_cat' ) ){
echo $term->name.' ('.$term->count.')';
echo " × ";
echo count($items);
}
?>
</h4>
</td>
</tr>
<?php
But I've realised that this simply counts the number of products that have been ordered in that category, not the quantity. So if one of there was more than one of the same product, it would not count it. So for example, if the category contained these three items:
Cheeseburger x 2
Hamburger x 1
Would return two instead of three.
I've been looking through the categories and terms arrays but can't seem to find anything that's going to work. I'm sure I'm missing something but I'm just at a loss right now.
Can anyone point me in the right direction please?
(Also, if it's of any use, this is an indirect follow on from a previous question Filtering the Woocommerce $order items By Category (Term))
You can do this in two ways:
Adds up the quantities of the products ordered based on the product category obtained from the product (so it must be only 1)
Set up a list of specific product categories for which you want to obtain a count of the quantities of products purchased
SOLUTION #1
You can use the get_the_terms() function to get the product category.
The function parameter must be the ID of the order to be counted.
Note that only the first product category returned by the get_the_terms() function will be checked. If a product has more than one you may have unexpected results.
// gets an array with the quantities of the ordered products grouped by product categories
function gets_the_quantities_of_products_ordered_grouped_by_product_categories( $order_id ) {
// initializes the array that will contain the product categories with the ordered quantities of each
$count_by_cat = array();
// get the order object
$order = wc_get_order( $order_id );
// for each product ordered
foreach ( $order->get_items() as $item ) {
$product = $item->get_product();
// get product categories
$terms = get_the_terms( $product->get_id(), 'product_cat' );
foreach ( $terms as $term ) {
$cat_name = $term->name;
// if the product category is already present in the array, add the quantities
if ( array_key_exists( $cat_name, $count_by_cat ) ) {
$count_by_cat[$cat_name] += $item->get_quantity();
// otherwise it adds the category and quantity to the array
} else {
$count_by_cat[$cat_name] = $item->get_quantity();
}
break;
}
}
return $count_by_cat;
}
SOLUTION #2
In this case you will have to initialize an array with the list of names of the product categories you want to get the number of products ordered.
With the has_term() function you can check if the product belongs to a specific product category.
The function parameter must be the ID of the order to be counted.
// gets an array with the quantities of the ordered products grouped by product categories
function gets_the_quantities_of_products_ordered_grouped_by_product_categories( $order_id ) {
// initializes the array that will contain the product categories with the ordered quantities of each
$count_by_cat = array();
// set the product categories you want to get counts for
$categories = array(
'Clothes',
'Shoes',
'Pants',
'Jackets',
'Hats'
);
// get the order object
$order = wc_get_order( $order_id );
// for each product ordered
foreach ( $order->get_items() as $item ) {
$product = $item->get_product();
// for each product category
foreach ( $categories as $cat_name ) {
// check if the product belongs to one of the product categories
if ( has_term( $cat_name, 'product_cat', $product->get_id() ) ) {
// if the product category is already present in the array, add the quantities
if ( array_key_exists( $cat_name, $count_by_cat ) ) {
$count_by_cat[$cat_name] += $item->get_quantity();
// otherwise it adds the category and quantity to the array
} else {
$count_by_cat[$cat_name] = $item->get_quantity();
}
break;
}
}
}
return $count_by_cat;
}
Both functions will return an array similar to this:
$count_by_cat = array(
'Shoes' => 4,
'Pants' => 2,
'Hats' => 11
)
So you could print an HTML code similar to:
// print the counts for each product category
foreach ( $count_by_cat as $category_name => $count ) {
echo "<p><strong>" . $category_name . ":</strong> " . $count . "</p>";
}
Both codes have been tested and work. Add them to your active theme's functions.php.
I am creating a 'Build Your Own' page. After selecting 4 products from the options, 1 main product gets added to the basket with 4 of the selected products being added as meta_data under that main product.
You can see below the main product with 4 selected products (IDs).
After paying for this item, I need to add each selected product to the order, so that they are within the order on the backend. I'm having to do it like this, because I need the stock of the selected product to go down, eventually pulling into a stock management system we use (veeqo)
Any help is appreciated. The code below allows me get the some meta_data for woocommerce_thankyou but I am not sure if it will work then...
add_action('woocommerce_thankyou', 'BuildYourOwn', 10, 1);
function BuildYourOwn( $order_id ) {
if ( !$order_id ){
return;
}
$firstTime = get_post_meta( $order_id, '_thankyou_action_done', true );
// Allow code execution only once
if( !$firstTime ) {
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
$exItems = '';
// Loop through order items
foreach ( $order->get_items() as $item_id => $item ) {
//print_r($item);
// Get the product object
$product = $item->get_product();
// Get the product sku
$product_sku = $product->get_sku();
// Get the product name
$product_id = $product->get_name();
$extras = $item->get_formatted_meta_data('_', true);
$exItems.=$product_sku;
if(!empty($extras)){
$exItems.=$product_sku.' -';
foreach($extras as $extra){
$exItems.= ' ['.$extra->key.' : '. preg_replace("/[^A-Za-z0-9?#,.&%!\s]/","",$extra->value).'] ';
}
}
$exItems.="\n";
}
var_dump($exItems);
Maybe I worded the question wrong - But I figured it out:
I used the code below to get the meta_data which I then looped through and got individual item id and added it to the basket this way.
// Get the product meta data
$extras = $item->get_formatted_meta_data('_', true);
if ($product_id == 60023){
if(!empty($extras)){
$args = array(
'subtotal' => 0,
'total' => 0,
);
foreach($extras as $extra){
$mini_name = $extra->value;
$mini = get_page_by_title( $mini_name, OBJECT, 'product' );
$mini_id = $mini->ID;
$order->add_product( wc_get_product($mini_id), 1, $args); // Add Minis
}
}
}
The only slight issue is woocommerce_thankyou hook not firing if paypal users don't come back to the site after paying.
I'm creating a Woocommerce webshop for a client who is selling different types of breakfasts. Each breakfast has several variations based on the amount of persons.
For example:
Breakfast x (product)
- 1 person (variation)
- 2 persons (variation)
- 3 persons (variation)
- 4 persons (variation)
Each variation contains (different) meta data.
Basically the meta data contains the articles needed to create a breakfast and needs to be added to the order line items in woocommerce when an order is created. The composition of the meta data is different for each variation.
Now I'm able to add meta data to the order item, but somehow meta data gets mixed up when adding two or more products.
Below is my code and output in Woocommerce.
When I use the function just to print the variation meta data instead of adding it to the woocommerce order, I can see that the meta data is correct and the most inner for loop is executed one variation after another. I don't know if wc_add_order_item_meta is causing an issue or maybe the hook I'm calling.
function oc_line_item_metadata( $item_id, $item, $order_id ) {
$order = new WC_Order( $order_id );
$items = $order->get_items();
foreach ($items as $item) {
$variation_id = $item['variation_id'];
$product_variation = new WC_Product_Variation( $variation_id );
$meta_data = $product_variation->get_meta_data();
for ($i=0; $i < count($meta_data); $i++) {
$article = ($meta_data[$i]->get_data());
$article_id = $article['id'];
$article_key = $article['key'];
$article_value = $article['value'];
wc_add_order_item_meta( $item_id, $article_key, $article_value );
}
}
}
add_action( 'woocommerce_new_order_item', 'oc_line_item_metadata', 10, 3 );
You can find the output via this link:
https://image.ibb.co/mtsnrb/order.png
Yesterday I found some more information that helped me solve the issue. It seems I'm not using the correct method to get the order_id and variation_id.
Below the correct code that solved my issue:
function oc_line_item_metadata( $item_id, $item, $order_id ) {
$order = wc_get_order( $order_id );
foreach ($order->get_items() as $item_id => $item_obj) {
$variation_id = $item_obj->get_variation_id();
}
$product_variation = new WC_Product_Variation( $variation_id );
$meta_data = $product_variation->get_meta_data();
for ($i=0; $i < count($meta_data); $i++) {
$article = ($meta_data[$i]->get_data());
$article_id = $article['id'];
$article_key = $article['key'];
$article_value = $article['value'];
wc_add_order_item_meta( $item_id, $article_key, $article_value );
}
}
I'm trying to get the names of the ordered products through my functions.php file with a loop. Heres's my code:
global $woocommerce;
$items = $woocommerce->cart->get_cart();
foreach($items as $item => $values) {
$_product = $values['data']->post;
}
And then i call the title like this:
$_product->post_title
This works, it returns me the name of the product I ordered. The thing is when i have 2 or more products it still returns me 1 name. How can i make it so it returns all the names in the cart.
The new syntax in woocommerce relative to cart is made with WC() without any need of calling global woocommerce;
So your code will be this:
$products_in_cart= array();
$products_post_title_in_cart = array();
$products_ids_in_cart= array();
foreach(WC()->cart->get_cart() as $cart_item) {
$products_in_cart[] = $cart_item['data']->post;
$products_post_title_in_cart[] = $cart_item['data']->post->post_title;
$products_ids_in_cart[] = $cart_item['product_id'];
}
// The first product (or item of the cart)
$_product = $products_in_cart[0]; // product post data
$product_id = $products_ids_in_cart[0]; // product ID
$products_post_title_in_cart[0] // product post title
// The Second product (or item of the cart)
$_product = $products_in_cart[1]; // product post data
$product_id = $products_ids_in_cart[1]; // product ID
$products_post_title_in_cart[1] // product post title
// etc … for all other products you increase the key of the arrays to get the correct values
<?php
global $woocommerce;
$items = $woocommerce->cart->get_cart();
$arr_product=array();
foreach($items as $item => $values) {
$arr_product[]= $_product->post_title;
}
print_r($arr_product,true); // echo print_r(); thats why get 1
?>
Try this code, Its returns all the names in the cart.
global $woocommerce;
$cart_item = $woocommerce->cart->get_cart();
echo "<pre>";
print_r($cart_item);
exit();
I have a trying to make a pice of code that i can put in my functions.php
It needs to check what the selected attributes of the first product in the cart is. After that it needs to block all other product with an OTHER attributes than the selected one in the cart.
In my case:
Product 1 has attribute: color, attribute: height.
Product 2 has attribute: color, attribute: height.
etc..
IF
product 1 is added in the cart with color black.
THEN
all the other products in the shop can only be added with color black.
I have several try's with editing existing code but none of them work :S
function check_if_cart_has_product( $valid, $product_id, $quantity ) {
if(!empty(WC()->cart->get_cart()) && $valid){
foreach (WC()->cart->get_cart() as $cart_item_key => $values) {
$_product = $values['data'];
if( $product_id == $_product->id ) {
wc_add_notice( 'The product is already in cart', 'error' );
return false;
}
}
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'check_if_cart_has_product', 10, 3 );
This will allow only one product in cart and blocks the rest, it only needs the check for the right conditons...
I try to combine it with this pice of code without success
function get_variation_data_from_variation_id( $item_id ) {
$_product = new WC_Product_Variation( $item_id );
$variation_data = $_product->get_variation_attributes();
$variation_detail = woocommerce_get_formatted_variation( $variation_data, true ); // this will give all variation detail in one line
// $variation_detail = woocommerce_get_formatted_variation( $variation_data, false); // this will give all variation detail one by one
return $variation_detail; // $variation_detail will return string containing variation detail which can be used to print on website
// return $variation_data; // $variation_data will return only the data which can be used to store variation data
}