How to get the variation shipping class in Woocommerce - php

I would like to display variable products shipping class set for each variant.
I realize that I may need to have a mix of php and Javascript but I would like to get the PHP side right first.
I am guessing the best way to start is to use:
if( $product->is_type( 'simple' ) ) {
$product = wc_get_product();
$shipping_class = $product->get_shipping_class();
} elseif( $product->is_type( 'variable' ) ) {
$product = wc_get_product();
$shipping_class = $product->get_shipping_class();
}
But I am not sure how to get the product variant shipping class or if I am doing this correctly. Looking into wc_get_product_variation or variation to see if it has the answer.
Any help would be appreciated possibly display all as an array and use javascript to hide the selected.
How do I get the variant shipping class?

To get the variations shipping classes of a defined variable product Id, two ways:
1) Using wp_get_post_terms() function for product_shipping_class taxonomy:
// Get the WC_Product_Variable instance Object (if needed)
$product = wc_get_product( $product_id );
// Initializing
$shipping_classes = array();
// Loop through the visible variations IDs
foreach ( $product->get_visible_children() as $variation_id ) {
// Get the variation shipping class WP_Term object
$term = wp_get_post_terms( $variation_id, 'product_shipping_class' );
if( empty($term) ) {
// Get the parent product shipping class WP_Term object
$term = wp_get_post_terms( $product->get_id(), 'product_shipping_class' );
// Set the shipping class slug in an indexed array
$shipping_classes[$variation_id] = $term->slug;
}
}
// Raw output (for testing)
var_dump($shipping_classes);
This will give you an array of variation Id / shipping class pairs.
2) Using get_shipping_class_id() WC_Product method:
// Get the WC_Product_Variable instance Object (if needed)
$product = wc_get_product( $product_id );
// Initializing
$shipping_classes = array();
// Loop through the visible variations IDs
foreach ( $product->get_visible_children() as $variation_id ) {
// Get the Product Variation instance Object
$variation = wc_get_product($variation_id);
// Get the shipping class ID
$term_id = $variation->get_shipping_class_id();
// The shipping class WP_Term Object
$term = get_term_by('term_id', $term_id, 'product_shipping_class');
// Set the shipping class slug in an indexed array
$shipping_classes[$variation_id] = $term->slug;
}
// Raw output (for testing)
var_dump($shipping_classes);

Related

Exclude products with specific attributes terms from WooCommerce coupons

I would like to exclude from all WooCommerce coupons the products that have a specific attribute (e.g. attribute_pa_brand => mybrand).
I followed this answer Exclude variations with 2 specific attribute terms from coupon usage in Woocommerce but it seems to apply only to the Variable Product type, while I would only need it for the Simple Product.
I will be grateful for any answer.
The linked code from your question is for product variation type. Now to make it work for simple products and variable products (without targeting specific variations attributes terms), you will use the following:
add_filter( 'woocommerce_coupon_is_valid', 'custom_coupon_validity', 10, 3 );
function custom_coupon_validity( $is_valid, $coupon, $discount ){
// YOUR ATTRIBUTE SETTINGS BELOW:
$taxonomy = 'pa_brand'; // Set the taxonomy (start always with "pa_" + the slug)
$term_names = array('Apple', 'Sony'); // Set your term NAMES to be excluded
$term_ids = array(); // Initializing
// Convert term names to term Ids
foreach ( $term_names as $term_name ) {
// Set each term id in the array
$term_ids[] = get_term_by( 'name', $term_name, $taxonomy )->term_id;
}
// Loop through cart items and check for backordered items
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product = $cart_item['variation_id'] > 0 ? wc_get_product($cart_item['product_id']) : $cart_item['data'];
// Loop through product attributes
foreach( $product->get_attributes() as $attribute => $values ) {
if( $attribute === $taxonomy && array_intersect( $values->get_options(), $term_ids ) ) {
$is_valid = false; // attribute found, coupons are not valid
break; // Stop and exit from the loop
}
}
}
return $is_valid;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works for simple and variable products on last WooCommerce version.

How to get product categories for the current order item?

I am trying to get the product categories for the woocommerce order item at woocommerce_checkout_create_order_line_item hook.
I am able to successfully get the product_id (thanks to help I got here) but now trying to get the product's categories the array comes back empty trying $product->get_categories() and alternatively trying wc_get_product_category_list($product->get_id().
I can't figure out what I am doing wrong.
add_action('woocommerce_checkout_create_order_line_item',
'add_order_item_custom_meta', 10, 4 );
function add_order_item_custom_meta( $item, $cart_item_key, $cart_item, $order ) {
$product = $item->get_product(); // The WC_Product instance Object
$cat_names = $product->get_categories(); // one attempt
$cat_names = wc_get_product_category_list($product->get_id()); // another attempt
$arrlength = count($cat_names);
for($x = 0; $x<$arrlength; $x++) {
$cat_name = $cat_names[$x];
}
$item->update_meta_data( '_raw_product_id', $product->get_id() );
$item->update_meta_data( '_raw_product_name', $cat_name );
}
So the add_action and the function work. The "$product=..." works and I can use it below in the 2nd to the last line of code as $product->get_id() and the correct value is stored as metadata as desired.
So since $product->get_id() works I thought it logical that $product->get_categories() would work. But it returns a null array.
I then read somewhere that it was deprecated and I should use wc_get_product_category_list. So I tried that and also no luck.
So I am now stuck and can't figure out what is wrong with my code. Thanks for any help.
As you mentioned get_categories() method of WC_Product class is deprecated. Instead you can use get_category_ids() method. However this method returns product category IDs, and It seems that you need category names so we can get the names from WP_Term objects.
Final code would be something like this:
add_action('woocommerce_checkout_create_order_line_item', 'add_order_item_custom_meta', 10, 4 );
function add_order_item_custom_meta($item, $cart_item_key, $cart_item, $order)
{
$product = $item->get_product(); // The WC_Product instance Object
$cat_ids = $product->get_category_ids(); // returns an array of cat IDs
$cat_names = [];
foreach ( (array) $cat_ids as $cat_id) {
$cat_term = get_term_by('id', (int)$cat_id, 'product_cat');
if($cat_term){
$cat_names[] = $cat_term->name; // You may want to get slugs by $cat_term->slug
}
}
$item->update_meta_data( '_raw_product_id', $product->get_id() );
$item->update_meta_data( '_raw_product_name', $cat_names );
}
Note: foreach loop is the preferred way of doing this kind of stuff (instead of using a for loop).

Get product category for every item of a WooCommerce order

I can retrieve almost every metadata of the order items but I want to retrieve the category of the items too.
My code now has this:
foreach ($order->get_items() as $item_key => $item_values) {
## Using WC_Order_Item methods ##
// Item ID is directly accessible from the $item_key in the foreach loop or
$item_id = $item_values->get_id();
## Using WC_Order_Item_Product methods ##
$item_name = $item_values->get_name(); // Name of the product
$item_type = $item_values->get_type(); // Type of the order item ("line_item")
$product_id = $item_values->get_product_id(); // the Product id
$product = $item_values->get_product(); // the WC_Product object
## Access Order Items data properties (in an array of values) ##
$item_data = $item_values->get_data();
$product_name = $item_data['name'];
$item_totaal = $item_data['subtotal'];
// Get data from The WC_product object using methods (examples)
$product_type = $product->get_type();
$product_price = $product->get_price();
}
Thought this would work but it doesn't:
$product_category = $product->get_category();
What line do I need?
The WC_Product method get_category() doesn't exist and I remember you that you can have many product categories set for a product.
There is multiple ways to get the product categories set in a product:
1) You can use the method get_catogory_ids() to get the product categories Ids (an array of terms Ids) like:
foreach ($order->get_items() as $item ) {
$product = $item->get_product(); // the WC_Product Object
$product_category_ids = $product->get_category_ids(); // An array of terms Ids
}
2) Or to get the product category names (an array of term names) you can use wp_get_post_terms() like:
foreach ($order->get_items() as $item ) {
$term_names = wp_get_post_terms( $item->get_product_id(), 'product_cat', ['fields' => 'names'] );
// Output as a coma separated string
echo implode(', ', $term_names);
}

Product attribute empty value from order item in Woocommerce 3

I know that there are a lot of questions already for that matter but im not able to figure out how to get a custom product attribute from an woocommerce order. here is what i have try:
$order = wc_get_order( $order_id );
$order_data = $order->get_data();
foreach ($order->get_items() as $item_key => $item_values) {
$product = $item_values->get_product(); // Get the product
$product_id = $item_values->get_product_id(); // the Product id
$tokens = get_post_meta($product_id, 'Tokens', true);
}
I have also try:
$tokens = $product->get_attribute( 'Tokens' );
and
$tokens = array_shift( wc_get_product_terms( $product_id, 'Tokens', array( 'fields' => 'names' ) ) );
My custom product attribute has the name "Tokens" and the value 5000 but im getting an empty return,
what am i doing wrong?
That can happen for a variable product when the product attribute is not set as an attribute for variations.
So when you have a product variation as order item, you need to get the parent variable product to get your product attribute value (if this product attribute is not set as an attribute for variations).
If it is the case for "Tokens" product attribute, try the following:
$attribute = 'Tokens';
$order = wc_get_order( 857 );
// Loop through order line items
foreach ( $order->get_items() as $item_id => $item ) {
$product = $item->get_product(); // Get the WC_Product object
// For Product Variation type
if( $item->get_variation_id() > 0 ){
$parent = wc_get_product($product->get_parent_id());
$term_names = $parent->get_attribute($attribute);
}
// For other Product types
else {
$term_names = $product->get_attribute($attribute);
}
// Testing display (the string of coma separated term names if many)
if( ! empty( $term_name ) )
echo '<p>'.$term_name.'</p>';
}
Tested and works in Woocommerce 3+

Get a specific attribute taxonomy terms slug

I'm trying to get terms slug from a specific attribute taxonomy but I get nothing.
$attr_langs = 'pa_languages';
$attr_langs_meta = get_post_meta('id', 'attribute_'.$attr_langs, true);
$term = get_term_by('slug', $attr_langs_meta, $attr_langs);
Thank you so much in advance!
It's normal that it doesn't work as get_post_meta() first function argument needs to be a numerical value but NOT a text string as 'id' (the post ID)…
So you can't get any value for $attr_langs_meta variable.
You can get the product ID in different ways:
1) From the WP_Post object with:
global $post;
$product_id = $post->ID;
2) From the WC_Product object with:
$product_id = $product->get_id();
Now the correct way for to do it is:
// The defined product attribute taxonomy
$taxonomy = 'pa_languages';
// Get an instance of the WC_Product Object (necessary if you don't have it)
// from a dynamic $product_id (or defined $product_id)
$product = wc_get_product($product_id);
// Iterating through the product attributes
foreach($product->get_attributes( ) as $attribute){
// Targeting the defined attribute
if( $attribute->get_name() == $taxonomy){
// Iterating through term IDs for this attribute (set for this product)
foreach($attribute->get_options() as $term_id){
// Get the term slug
$term_slug = get_term( $term_id, $taxonomy )->slug;
// Testing an output
echo 'Term Slug: '. $term_slug .'<br>';
}
}
}
Or also exclusively for a variable product (similar thing):
// The defined product attribute taxonomy
$taxonomy = 'pa_languages';
// Get an instance of the WC_Product Object (necessary if you don't have it)
// from a dynamic $product_id (or defined $product_id)
$product = wc_get_product($product_id);
// Iterating through the variable product variations attributes
foreach ( $product->get_variation_attributes() as $attribute => $terms ) {
// Targeting the defined attribute
if( $attribute == $taxonomy ){
// Iterating through term slugs for this attribute (set for this product)
foreach( $terms as $term_slug ){
// Testing an output
echo 'Term Slug: ' . $term_slug . '<br>';
}
}
}
This should work for you…

Categories