How to get the available tax rates in WooCommerce - wordpress

Based on Using WC_Tax::get_tax_classes() to get all WooCommerce tax-classes answer to my previous question, I am trying to get the available tax rates from the defined tax-classes in WooCommerce.
I tried the following code:
$tax_classes = wc_get_product_tax_class_options();
foreach ( $tax_classes as $tax_class ) {
$taxes = WC_Tax::get_rates( $tax_class );
var_dump($taxes);
}
The var_dump exports are empty, but it looks like it interacts with the available classes.
/home/public_html/...etc
array (size=0)
empty
/home/public_html/...etc
array (size=0)
empty
/home/public_html/...etc
array (size=0)
empty
/home/public_html/...etc
array (size=0)
empty
/home/public_html/...etc
array (size=0)
empty
How do i get a array (in the backend admin-panel) with the available tax details: name, tax_rate etc?

Each tax class rates are defined in backend by location settings… so they depend on customer location. The tax rates can be applied differently to products and shipping.
For each tax class, you need to set tax rates by country or by shipping zone, depending on allowed purchase locations or zones (see the example below).
Use the following to display the available tax rates for the customer (based on its location):
$location = array(
'country' => WC()->customer->get_shipping_country() ? WC()->customer->get_shipping_country() : WC()->customer->get_billing_country(),
'state' => WC()->customer->get_shipping_state() ? WC()->customer->get_shipping_state() : WC()->customer->get_billing_state(),
'city' => WC()->customer->get_shipping_city() ? WC()->customer->get_shipping_city() : WC()->customer->get_billing_city(),
'postcode' => WC()->customer->get_shipping_postcode() ? WC()->customer->get_shipping_postcode() : WC()->customer->get_billing_postcode(),
);
$output = array(); // Initialiizing (for display)
// Loop through tax classes
foreach ( wc_get_product_tax_class_options() as $tax_class => $tax_class_label ) {
// Get the tax data from customer location and product tax class
$tax_rates = WC_Tax::find_rates( array_merge( $location, array( 'tax_class' => $tax_class ) ) );
// Finally we get the tax rate (percentage number) and display it:
if( ! empty($tax_rates) ) {
$rate_id = array_keys($tax_rates);
$rate_data = reset($tax_rates);
$rate_id = reset($rate_id); // Get the tax rate Id
$rate = $rate_data['rate']; // Get the tax rate
$rate_label = $rate_data['label']; // Get the tax label
$is_compound = $rate_data['compound']; // Is tax rate compound
$for_shipping = $rate_data['shipping']; // Is tax rate used for shipping
// set for display
$output[] = '<li class="tax-rate '.$tax_class.'">'.$tax_class_label.': <strong>'.$rate.'</strong> <small>(label: '.$rate_label.' | id: ' . $rate_id . ')</small></li>';
}
}
// Display
if ( ! empty($output) ) {
echo '<div><h4>' . __("Available Tax rates") . '</h4><ul>' . implode('', $output) . '</ul></div>';
}
You will get something like:
Related: Using WC_Tax::get_tax_classes() to get all WooCommerce tax-classes
Usage specifying a location
As it seems that you want to use it in backend as are asking in your comment, you need to specify a location to be able to get tax rates for that specific location.
So for example to get the tax rates set for France country ("FR" country code) you will replace the $location array by:
$location = array( 'country' => 'FR', 'state' => '', 'city' => '', 'postcode' => '' );
If there is no country specified, you will use an array with empty values like:
$location = array( 'country' => '', 'state' => '', 'city' => '', 'postcode' => '' );

Related

Split a WooCommerce order, and create a new one with line items that has specific product tag

I have tried modifying the answer provided in //stackoverflow.com/a/59544491/19984414. I am not getting any errors when testing it, but also nothing really happens to my test order.
How can I test, why nothing happens when I make an order?
add_action( 'woocommerce_checkout_order_processed', 'action_woocommerce_checkout_order_processed', 10, 3 );
function action_woocommerce_checkout_order_processed( $order_id, $posted_data, $order ) {
// Initialize
$check_for_stock = false;
$taxonomy = 'product_tag';
// Loop through order items
foreach ( $order->get_items() as $item_key => $item ) {
// Get product
$product = $item->get_product();
// Product has tag 'stock'
if ( has_term( 'stock', $taxonomy, $product ) ) {
// Will only be executed once if the order contains line items with tag "stock"
if ( $check_for_stock == false ) {
$check_for_stock = true;
// Create new order with stock items
$stock_order = wc_create_order();
}
// Add product to 'backorder' order
$stock_order->add_product( $product, $item['quantity'] );
$stock_order->save();
// Delete item from original order
$order->remove_item( $item->get_id() );
}
}
// If current order contains line items with product tag "stock", retrieve the necessary data from the existing order and apply it in the new order
if ( $check_for_stock ) {
// Recalculate and save original order
$order->calculate_totals();
$order->save();
// Obtain necessary information
// Get address
$address = array(
'first_name' => $order->get_billing_first_name(),
'last_name' => $order->get_billing_last_name(),
'email' => $order->get_billing_email(),
'phone' => $order->get_billing_phone(),
'address_1' => $order->get_billing_address_1(),
'address_2' => $order->get_billing_address_2(),
'city' => $order->get_billing_city(),
'state' => $order->get_billing_state(),
'postcode' => $order->get_billing_postcode(),
'country' => $order->get_billing_country()
);
// Get shipping
$shipping = array(
'first_name' => $order->get_shipping_first_name(),
'last_name' => $order->get_shipping_last_name(),
'address_1' => $order->get_shipping_address_1(),
'address_2' => $order->get_shipping_address_2(),
'city' => $order->get_shipping_city(),
'state' => $order->get_shipping_state(),
'postcode' => $order->get_shipping_postcode(),
'country' => $order->get_shipping_country()
);
// Get order currency
$currency = $order->get_currency();
// Get order payment method
$payment_gateway = $order->get_payment_method();
// Required information has been obtained, assign it to the 'backorder' order
// Set address
$stock_order->set_address( $address, 'billing' );
$stock_order->set_address( $shipping, 'shipping' );
// Set the correct currency and payment gateway
$stock_order->set_currency( $currency );
$stock_order->set_payment_method( $payment_gateway );
// Calculate totals
$stock_order->calculate_totals();
// Set order note with original ID
$stock_order->add_order_note( 'Automated "stock" order. Created from the original order ID: ' . $order_id );
// Optional: give the new 'backorder' order the correct status
$stock_order->update_status( 'on-hold' );
$stock_order->save();
}
}
I am running the snippet from WPCodeBox with the following (default) settings:
How to run the snippet: Always (On Page Load)
Hook/Priority: Root (Default)
Snippet Order: 10
Where to run the snippet: Everywhere

Add total orders and customer status in new order email notification in WooCommerce

I would like to add a note to the new order email notifications that the admin gets. This note should indicate whether the order is from a new customer, or from a returning customer.
This so that the people in the warehouse know what they should add in the shippingbox. We give new customers a ticket and don't want customers who order again to receive the same ticket, they get a diffrent ticket.
This should apply to both logged in users and users who are not logged in. A check via email address perhaps?
This code is using the has_bought for all customer orders - source
function has_bought() {
// Get all customer orders
$customer_orders = get_posts( array(
'numberposts' => 1, // one order is enough
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-completed', // Only orders with "completed" status
'fields' => 'ids', // Return Ids "completed"
) );
// return "true" when customer has already at least one order (false if not)
return count($customer_orders) > 0 ? true : false;
}
But I don't get it on the the new order email that admins receive, I would like to show it as:
Customer: new OR returning
Number of purchases: 4
How would i go about this and is this possible to create?
Some comments/suggestions:
To display text in email notifications, you can use different hooks, depending on where exactly you want to display the text. For example, the woocommerce_email_order_details hook is very suitable for this
To target a specific email notification you can use $email->id
Via wc_get_orders() you can get and count the existing orders for a customer based on the email address. If desired, pass a series of arguments that define the criteria for the search
So you get:
function action_woocommerce_email_order_details( $order, $sent_to_admin, $plain_text, $email ) {
// Target specific email notification
if ( $email->id == 'new_order' ) {
// Get email
$customer_email = $order->get_billing_email();
// NOT empty
if ( ! empty ( $customer_email ) ) {
// Get orders from customer by email and statuses
$orders_by_customer_email = wc_get_orders( array(
'customer' => $customer_email,
'status' => array( 'wc-on-hold','wc-processing','wc-completed' ),
'limit' => -1,
'return' => 'ids'
));
// When new customer
if ( count( $orders_by_customer_email ) == 1 ) {
$customer = __( 'new', 'woocommerce' );
} else {
$customer = __( 'returning', 'woocommerce' );
}
// Output
echo '<p style="color:red;font-size:14px;">' . sprintf( __( 'Customer: %s, number of purchases: %d', 'woocommerce' ), $customer, count( $orders_by_customer_email ) ) . '</p>';
}
}
}
add_action( 'woocommerce_email_order_details', 'action_woocommerce_email_order_details', 10, 4 );

Add attribute value automatically based on user meta key

I have created a registration form (using plugin ultimate-member) for a partner as a salesperson. The key here is:
Label : Registration Number
Meta : 'regno'
Value : X123W
So, each new registrant will get a different value as a salesperson unique ID .
On the other hand, I have created a product which is divided into 3 packages, separated by attribute with values ​​'pa_silver', 'pa_gold', and 'pa_diamond'.
'pa_silver' & 'pa_gold' => self-sold product (no salesperson required)
'pa_diamond' => product entrusted for selling (using salesperson).
Then on products that have taxonomy 'pa_diamond' I've added the attribute:
Label : List
tax : 'pa_list'
value : 'X123W', 'X234W' => this has been created manually.
Targets : What I want is that every time someone registers as a partner, the partner code should be "added" automatically on existing attribute ('pa_list') and on products that have taxonomy 'pa_diamond'.
I'm trying something, like:
$users = get_users( array( 'role' => array( 'partner' ) ) );
foreach($users as $user){
$regno = get_the_author_meta( 'regno', $user->ID);
echo $regno;
}
Note : it output like this => X345WX456W (2 New partner code)
Tried using the code I got from #LoicTheAztec's answer here.
The code is :
$product_id = get_the_ID();
$taxonomy = 'pa_list';
$clean_keywords = array('X345W','X456W');
$term_taxonomy_ids = wp_set_object_terms( $product_id, $clean_keywords, $taxonomy, true );
// Get existing attributes
$product_attributes = get_post_meta( $product_id, '_product_attributes', true);
// get the count of existing attributes to set the "position" in the array
$count = count($product_attributes);
// Insert new attribute in existing array of attributes (if there is any)
$product_attributes[$taxonomy] = array(
'name' => $taxonomy,
'value' => '',
'position' => $count, // added
'is_visible' => '0',
'is_variation' => '0', // added (set the right value)
'is_taxonomy' => '1'
);
// Save the data
update_post_meta( $product_id, '_product_attributes', $product_attributes );
Note : I replaced (manually) $taxonomy -> 'pa_list' and $clean_keywords = array('X345W','X465W');
In attribute field 'pa_list' both partner codes have been added but do not fill or set to product.
I'm having a hard time connecting some logic here.
I hit a dead end to get what I wanted.
Can anyone help me?
Thank You

How to programmatically set the product attribute variation price in woocommerce?

I have a product attribute variation which has options of -
small - $20
medium - $25
large - $30
Since all the products in the store has the same price for this variations.
How to set the price for the attribute values programmatically?
3 attribute variation buttons are show on product page when I add them as variations.
How to change the price of product when "small" option is selected programmatically instead of setting price in variation options in admin panel.
As Per our understanding to want to add products with different sizes and different prices.
There is 2 way:
1. You can add from woocommerece dashboard like this:
https://www.ostraining.com/blog/woocommerce/product-variations/
You can add programmatically like this:
function insert_product ($product_data)
{
$post = array( // Set up the basic post data to insert for our product
'post_author' => 1,
'post_content' => $product_data['description'],
'post_status' => 'publish',
'post_title' => $product_data['name'],
'post_parent' => '',
'post_type' => 'product'
);
$post_id = wp_insert_post($post); // Insert the post returning the new post id
if (!$post_id) // If there is no post id something has gone wrong so don't proceed
{
return false;
}
update_post_meta($post_id, '_sku', $product_data['sku']); // Set its SKU
update_post_meta( $post_id,'_visibility','visible'); // Set the product to visible, if not it won't show on the front end
wp_set_object_terms($post_id, $product_data['categories'], 'product_cat'); // Set up its categories
wp_set_object_terms($post_id, 'variable', 'product_type'); // Set it to a variable product type
insert_product_attributes($post_id, $product_data['available_attributes'], $product_data['variations']); // Add attributes passing the new post id, attributes & variations
insert_product_variations($post_id, $product_data['variations']); // Insert variations passing the new post id & variations
}
function insert_product_attributes ($post_id, $available_attributes, $variations)
{
foreach ($available_attributes as $attribute) // Go through each attribute
{
$values = array(); // Set up an array to store the current attributes values.
foreach ($variations as $variation) // Loop each variation in the file
{
$attribute_keys = array_keys($variation['attributes']); // Get the keys for the current variations attributes
foreach ($attribute_keys as $key) // Loop through each key
{
if ($key === $attribute) // If this attributes key is the top level attribute add the value to the $values array
{
$values[] = $variation['attributes'][$key];
}
}
}
$values = array_unique($values); // Filter out duplicate values
wp_set_object_terms($post_id, $values, 'pa_' . $attribute);
}
$product_attributes_data = array(); // Setup array to hold our product attributes data
foreach ($available_attributes as $attribute) // Loop round each attribute
{
$product_attributes_data['pa_'.$attribute] = array( // Set this attributes array to a key to using the prefix 'pa'
'name' => 'pa_'.$attribute,
'value' => '',
'is_visible' => '1',
'is_variation' => '1',
'is_taxonomy' => '1'
);
}
update_post_meta($post_id, '_product_attributes', $product_attributes_data); // Attach the above array to the new posts meta data key '_product_attributes'
}
function insert_product_variations ($post_id, $variations)
{
foreach ($variations as $index => $variation)
{
$variation_post = array( // Setup the post data for the variation
'post_title' => 'Variation #'.$index.' of '.count($variations).' for product#'. $post_id,
'post_name' => 'product-'.$post_id.'-variation-'.$index,
'post_status' => 'publish',
'post_parent' => $post_id,
'post_type' => 'product_variation',
'guid' => home_url() . '/?product_variation=product-' . $post_id . '-variation-' . $index
);
$variation_post_id = wp_insert_post($variation_post); // Insert the variation
foreach ($variation['attributes'] as $attribute => $value) // Loop through the variations attributes
{
$attribute_term = get_term_by('name', $value, 'pa_'.$attribute); // We need to insert the slug not the name into the variation post meta
update_post_meta($variation_post_id, 'attribute_pa_'.$attribute, $attribute_term->slug);
}
update_post_meta($variation_post_id, '_price', $variation['price']);
update_post_meta($variation_post_id, '_regular_price', $variation['price']);
}
}
function insert_products ($products)
{
if (!empty($products)) // No point proceeding if there are no products
{
array_map('insert_product', $products); // Run 'insert_product' function from above for each product
}
}
$json = file_get_contents('product-data.json'); // Get json from sample file
// $products_data = json_decode($json_file, true); // Decode it into an array
echo json_last_error();
// if(get_magic_quotes_gpc()){
// $d = stripslashes($json);
// }else{
// $d = $json;
// }
$d = json_decode($d,true);
$products_data = json_decode( preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $json), true );
echo "<h1>json</h1>";
echo "<pre>";
print_r($json);
echo "</pre>";
echo "<h1>Product data</h1>";
echo "<pre>";
var_dump($products_data);
echo "</pre>";
insert_products($products_data);
Where $product_data sample:
$product_data = array(
'sku' => '123SKU',
'categories' => array('size', 'color'),
'available_attributes' => array('size', 'color'),
'variations' => array(
'size' => array(
'attributes' => array( 'XL', 'M', 'S' ),
),
'color' => array(
'attributes' => array( 'Blue', 'Red', 'Green' )
)
)
)
insert_products($products_data);
Note: You can create product-data.json and import product or you can create $product_data = (); and set on insert_products() function.
For Aditional Info:
You can also check this URL for more info https://newbedev.com/create-programmatically-a-woocommerce-product-variation-with-new-attribute-values

How To Create Multiple Product Variations Woocommerce

I tried to use the function given on this answer: Create programmatically a WooCommerce product variation with new attribute values
But i can't make it work, i inserted it on a my plugin function file instead of functions.php of my theme.
I call that function in this code after a product creation code:
foreach ($variations as $variation) {
$model_name = $variation['name'];
$model_name = explode(',',$model_name);
$color = $model_name[0];
$model = $model_name[1];
$price = $variation['price'];
$stock = $variation['stock'];
// The variation data
$variation_data = array(
'attributes' => array(
'color' => $color,
'model' => $model,
),
'sku' => '',
'regular_price' => $price,
'sale_price' => '',
'stock_qty' => $stock,
);
// The function to be run
create_product_variation( $new_post_id, $variation_data );
}
All the values of product & variations came from a API call from external link. The data is on array format, i can get all those data i need, my problem now is to create the variations of the product and i used this create_product_variation but i cant make it work.
It gives me an error 500 status on my ajax call.

Resources