I try to get the active tax-classes in Woocommerce in my custom plugin. When I use the WC_Tax::get_tax_classes(), I get a empty array.
How does WC_tax class work without order details and run by itself?
WC_Tax::get_tax_classes() returns an empty array when there is only the default tax class set in WooCommerce > Tax (tab) settings.
It's used for example in wc_get_product_tax_class_options() function that displays the available tax classes in admin product pages settings:
/**
* Get product tax class options.
*
* #since 3.0.0
* #return array
*/
function wc_get_product_tax_class_options() {
$tax_classes = WC_Tax::get_tax_classes();
$tax_class_options = array();
$tax_class_options[''] = __( 'Standard', 'woocommerce' );
if ( ! empty( $tax_classes ) ) {
foreach ( $tax_classes as $class ) {
$tax_class_options[ sanitize_title( $class ) ] = $class;
}
}
return $tax_class_options;
}
So the default tax class (active tax class) has no entry when using WC_Tax::get_tax_classes().
Then you can use wc_get_product_tax_class_options() function to get all WooCommerce tax classes or the code from this function if you want something more custom.
Related: How to get the available tax rates in WooCommerce
Related
I'm struggling to show the different shipping classes on the product page in Woocommerce. I have found several codes that show the shipping class of simple products. But not codes that show the classes of the different variations on a variable product.
The code should get the shipping class of simple products to show (cause I gave several simple products). But when the product is a variable product it needs to show the shipping classes of the variations instead of the parent shipping class.
I am not capable of coding this, hoping there is someone who is skilled enough and willing to help.
It would be nice if the front end looks like this:
Front end shipping class
One way is to use the variation stock filter woocommerce_get_stock_html() which takes 2 arguments:
$html for displaying the content
$product Product object
You need to set the shipping class to each variation and add this to your functions.php:
/**
* Add shipping class for Product variations.
*
* #param mixed $html Displays stock html content.
* #param WC_Product $product Product Object.
*
* #return mixed $html Updated stock html content.
*/
add_filter( 'woocommerce_get_stock_html', 'amp_woocommerce_get_stock_html', 10, 2 );
function amp_woocommerce_get_stock_html( $html, $product ) {
$shipping_slug = $product->get_shipping_class();
if ( ! empty( $shipping_slug ) ) {
$shipping_name = get_term_by( 'slug', $shipping_slug, 'product_shipping_class' );
$html .= sprintf( '<p class="shipping-class"><strong>%s</strong> %s</p>', __( 'Shipping:', 'text-domain' ), $shipping_name );
}
return $html;
}
I am trying to set up a dimensional weight counting method when the dimensional weight (width x height x length) of the product is greater than the weight (actual weight).
I found Custom Woocommerce product weight calculation from dimensions answer code that works perfectly.
However I would like to make it works only for specific shipping method(s).
Any advice or help?
add_filter( 'woocommerce_product_get_weight', 'custom_get_weight_from_dimensions', 10, 2 );
function custom_get_weight_from_dimensions( $weight, $product ) {
$chosen_shipping = WC()->session->get('chosen_shipping_methods')[0];
// How to restrict to specific shipping methods?
$dim_weight = $product->get_length() * $product->get_width() * $product->get_height() / 5000;
return $dim_weight > $weight ? $dim_weight : $weight;
}
You can use the following targeting specific shipping methods only (see at the end, how to get your shipping method rate ids):
add_filter( 'woocommerce_product_get_weight', 'custom_get_weight_from_dimensions', 10, 2 );
function custom_get_weight_from_dimensions( $weight, $product ) {
if ( ! is_admin() ) {
// Here set your targeted shipping method rate Ids
$targetted_shipping_ids = array( 'flat_rate:12', 'flat_rate:14' );
// Get chosen shipping method(s)
$chosen_shipping_methods = (array) WC()->session->get('chosen_shipping_methods');
$matched_shipping_methods = array_intersect( $chosen_shipping_methods, $targetted_shipping_ids );
if( ! empty($matched_shipping_methods) ) {
$dim_weight = $product->get_length() * $product->get_width() * $product->get_height() / 5000;
}
}
return isset($dim_weight) && $dim_weight > $weight ? $dim_weight : $weight;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
How to get the shipping method rate ID:
To get the related shipping methods rate IDs, something like flat_rate:12, inspect with your browser code inspector each related radio button attribute value like:
The deal is, I have to fix an error in a custom WooCommerce import plugin, which appeared after updating WC from 2.6 to 3.4.
It uses the 'wc_update_product_stock_status' function, and used to pass post (product) id and it's stock status as it is represented in DB ('instock' and 'outofstock', as a string). But nowadays, as I can see in the WooCommerce docs (https://docs.woocommerce.com/wc-apidocs/function-wc_update_product_stock_status.html) it accepts integer instead of string.
So, the question is - what are those integers for in/out of stock values (1/0 did not fit).
If you look to the source code in wc_update_product_stock_status() function:
/**
* Update a product's stock status.
*
* #param int $product_id
* #param int $status
*/
function wc_update_product_stock_status( $product_id, $status ) {
$product = wc_get_product( $product_id );
if ( $product ) {
$product->set_stock_status( $status );
$product->save();
}
}
It uses the WC_Product set_stock_status() Woocommerce 3 CRUD method which uses strings But not integers values:
/**
* Set stock status.
*
* #param string $status New status.
*/
public function set_stock_status( $status = 'instock' ) {
$valid_statuses = wc_get_product_stock_status_options();
if ( isset( $valid_statuses[ $status ] ) ) {
$this->set_prop( 'stock_status', $status );
} else {
$this->set_prop( 'stock_status', 'instock' );
}
}
So it's an error in the comment usage in wc_update_product_stock_status() function.
It still uses: 'instock' and 'outofstock' status strings. the default value is 'instock'…
The main difference is also that stock status is now handled as outofstock term for the custom taxonomy product_visibility
Before Woocommerce 3, stock status was handled as product meta data.
I've coded in a custom select box to a group of my products that changes the price based on the user's selection. It works well, but now I need to change the product title too based on their selection.
Basically if option 1 is chosen, the product name stays the same. But is option 2 is chosen, I need to add "-RZ" to the end of the product title.
I'm not sure if I can do this in the 'woocommerce_before_calculate_totals' hook where I altered the prices, but if anyone knows the hook I should use and the code to access the current product's title via PHP that would be great.
Here is the code that alters the price if it's helpful:
function calculate_core_fee( $cart_object ) {
if( !WC()->session->__isset( "reload_checkout" )) {
/* core price */
//echo $additionalPrice;
//$additionalPrice = 100;
foreach ( $cart_object->cart_contents as $key => $value ) {
$product_id = $value['product_id'];
if( isset( $value["addOn"] ) && $value["addOn"] == $product_id) {
$additionalPrice = $value['core'];
/* Woocommerce 3.0 + */
$orgPrice = floatval( $value['data']->get_price() );
//echo $additionalPrice;
//echo $orgPrice;
$value['data']->set_price( $orgPrice + $additionalPrice );
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'calculate_core_fee', 99 );
I know may have to get the name and store it in a SESSION variable to use later if the hook to do this is on the cart, checkout, or order page rather than the single-product page.
Yes this is possible in the same hook. You can manipulate the product title with class WC_Product get_name() and set_name() methods. But as for the price, you should set and get a custom cart field value to make it (just as $additionalPrice = $value['core'];).
See here a simple related answer: Changing WooCommerce cart item names
So you could have something like (just a fake example):
// Get your custom field cart value for the user selection
$userSelection = $value['user_selection'];
// Get original title
$originalTitle = $value['data']->get_name();
// Conditionally set the new item title
if($userSelection == 'option2')
$value['data']->set_name( $originalTitle . '-RZ' );
I have created a WooCommerce plugin that enables free shipping for subscribers. It seems to have broken following a recent WooCommerce upgrade.
Specifically, the problem seems that the shipping class of the cart items may not be being retrieved correctly.
Here is my calculate_shipping code - can anyone advise what is wrong?
/**
* Add free shipping option for customers in base country with an active subscription,
* but only if the cart doesn't contain an item with the 'heavy-item-shipping-class'.
*
* #access public
* #param mixed $package
* #return void
*/
public function calculate_shipping($package) {
global $woocommerce;
// Check country and subscription status
if (is_user_in_base_country() && does_user_have_active_subscription()) {
// This flag will be set to TRUE if cart contains heavy items
$disable_free_shipping = FALSE;
// Get cart items
$cart_items = $package['contents'];
// Check all cart items
foreach ($cart_items as $cart_item) {
// Get shipping class
$shipping_class = $cart_item['data']->shipping_class; // *** IS THIS THE RIGHT WAY TO GET THE SHIPPING CLASS ??? ***
// If heavy item, set flag so free shipping option is not made available
if ($shipping_class === 'heavy-item-shipping-class') {
// Set flag
$disable_free_shipping = TRUE;
// Enough
break;
}
}
// If appropriate, add the free shipping option
if ($disable_free_shipping === FALSE) {
// Create the new rate
$rate = array(
'id' => $this->id,
'label' => "Free Shipping",
'cost' => '0',
'taxes' => '',
'calc_tax' => 'per_order'
);
// Register the rate
$this->add_rate($rate);
}
else {
// Doesn't qualify for free shipping, so do nothing
}
}
}
UPDATE
I've looked at the %package array and noticed that it now contains the shipping class under [shipping_class:protected]. (Previously, this must have been [shipping_class].) Is it possible to extract this data? If not, what is the correct way of doing it?
I found the solution. Now, it seems the only way to get the shipping class of a product/item is to call get_shipping_class() on it.
So, in my code snippet, above, I changed...
$shipping_class = $cart_item['data']->shipping_class;
...to...
$shipping_class = $cart_item['data']->get_shipping_class();
Hopefully, this will help someone else. :)