WooCommerce: How to set a default table-rate shipping method? - php

I have 2 shipping methods defined:
Table Rates - Priority 1
Local Pickup - Priority 2
Within Table Rates, I have 3 options:
Registered Australian Post (2 to 8 Business Days): $6.50
Tracking and Freight Insurance: $7.25
Nation-Wide Delivery (5 to 12 Business Days): $1.40
All orders that fall within the Local Table Rate area are presented with these 3 options and by default, Option 3 is selected ( I assume because it is the cheapest)
It defaults the priority to table rates but you can't define priority within the actual table rates. I want the default option to be Option 1: Registered Australian Post (2 to 8 Business Days)
I have discovered that the default shipping method is set here:
WC()->session->[chosen_shipping_methods] => a:1:{i:0;s:17:"table_rate-5 : 70";}
and apparently can be accessed and modified using the following two methods:
WC()->session->get('chosen_shipping_methods');
WC()->session->set('chosen_shipping_methods', $chosen_method);
BUT, I can get the current chosen_shipping_methods I just can't set a new one.
I'm trying to set it using the action woocommerce_shipping_method_chosen but it's not working
Can anyone guide me to what I should be looking at?

by only looking on your website and not looking at the code, I'm guessing this might be what you want...
add_action( 'template_redirect', 'reigel_chosen_shipping_methods' );
function reigel_chosen_shipping_methods(){
remove_action(current_filter(), __FUNCTION__);
WC()->session->set( 'chosen_shipping_methods', array('table_rate-7 : 72') );
}

You can reorder shipping methods via the admin dashboard. Goto Woocommerce > Shipping > Shipping Methods and change the order using drag and drop.

This is what I ended up using which worked as required:
/*=Use the shipping method filter to set the "selected" shipping method to
* the first (default) method in the list
**************************************************************************/
function oley_reset_default_shipping_method( $method, $available_methods ) {
$method = key($available_methods);
return $method;
}
add_filter('woocommerce_shipping_chosen_method', 'oley_reset_default_shipping_method', 10, 2);
(NOTE: This worked because the shipping rate I wanted was actually the first in the list but just wasn't being selected by default)

Related

WooCommerce: Only show Free Shipping Method when user selects COD

I am trying to create a functionality when a user tries to select COD as a payment option then set shipping to Free Shipping (Make this shipping option available).
Right now I have added this code.
add_action( 'woocommerce_checkout_update_order_review', __NAMESPACE__.'\\refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods($post_data)
{
if (isset($post_data['payment_method']) && $post_data['payment_method'] === 'cod') {
// I am not sure how to add Free Shipping Method here.
}
}
I am unable to figure out how can I add free shipping method here when it isn't available in the available_shipping_method.
How can I add it programmatically ?

How to properly create a WooCommerce Variation using the helper class WC_Product_Variation

Before anything, I'd like to say that I have thoroughly searched all over internet to find as much help as I could into solving this particular issue.
I have tried many different ways of creating a variation, in particular this one which also didn't seem to bind the label to the field next to the variation ID on my product page. The outcome was the same as the method I've written with the helper class. I still have it commented somewhere so if you happen to know a solution for this specific way of creating a variation, hit me up!
Some context: I have a csv file with a lot of information on my products. I wrote a script to import them into WooCommerce programmatically using the WC_Product_Simple helper class and a stripped down version of the original csv (with only two items), and everything worked perfectly for the two products. Item #2 is flour, so I figured I'd try creating variations for it instead of creating multiple simple products (for instance Flour (100Gr), Flour (500Gr) and Flour (1Kg)).
I was able to create an attribute for my WC_Product_Variable, set its variation field to true, create three variations (100Gr, 500Gr and 1Kg) and save them. When I look at my Products page in WooCommerce, I can see the three variations under my variable product.
The issue I'm having is that I can't bind a particuliar field to one variation, no matter how hard I try. I have no idea how this field is called, tho I've noticed that setting it reads/writes the post_excerpt column in my {$wpdb->prefix}posts table.
Here is what is displayed:
And here is what I want to achieve programmatically:
Here's the code:
/**
* At this point, the product is correctly created and available through $wc_product.
* Its id is stored in $product_id.
* I also have an array with information from my product called $product.
* This is where the information is stored to create said product.
* You don't have to worry about the creation of the product itself.
*/
// I have stored as a boolean whether my product had variations or not.
if ($variable) {
// Weight => Label
$weights = array(
'100' => '100Gr',
'500' => '500Gr',
'1000' => '1Kg'
);
$attribute = new WC_Product_Attribute();
$attribute->set_id(0);
$attribute->set_name('Weight');
$attribute->set_options(
$weights
);
$attribute->set_position(0);
$attribute->set_visible(true);
$attribute->set_variation(true);
$wc_product->set_attributes(array($attribute));
$wc_product->save();
// At this point my attribute is created. There is no save method for WC_Product_Attribute.
// I'm 100% sure that everything up to this point works as expected, I've left it here
// for clarity and for better understanding what the code does.
foreach ($weights as $weight=>$label) {
// Each variation will be named after the product sku followed by its label.
// For instance: sku5436-100Gr where sku5436 is the variable product.
$variation_sku = "{$product["sku"]}-{$label}";
// Will uncomment once this works!
// These two lines make sure that each variation is unique through their sku.
// $var_id = wc_get_product_id_by_sku($variation_sku);
// $variation = $var_id?new WC_Product_Variation($var_id):new WC_Product_Variation();
/**
* I create my variation,
* I set its parent id,
* I set its sku,
* I calculate its price with a simple weight/price formula,
* I set its price
*
* And here's the part I'm not too sure about
* I thought "set_attributes" would select between 100Gr, 500Gr and 1Kg
* but it looks like it doesn't do anything. I could just remove that line
* and nothing would change.
*/
$variation = new WC_Product_Variation();
$variation->set_parent_id($product_id);
$variation->set_sku($variation_sku);
$variation_price = ($weight / 1000) * $product["kg_price"];
$variation->set_regular_price($variation_price);
// This is the line I thought would bind the label to the field, but it doesn't
$variation->set_attributes(array("Weight" => $label));
$id_var = $variation->save();
// I tried manually setting the post excerpt. The update works, but since
// it wasn't set through the helper class, I'm assuming some cache
// thing isn't correctly binding the label to the field which I still don't know the name
// global $wpdb;
// $wpdb->update($wpdb->prefix . "posts", array("post_excerpt" => $label), array("ID" => $id_var));
}
}
In short: I'd like to bind the fields next to the post ID (see screenshots) to the correct variation. My code does almost everything except that.
I would also really appreciate if someone could tell me the name of this field. The closest thing I've found is that it is bound to the post_excerpt.

Get fields from checkout form into calculate_shipping

I'm creating a custom shipping calculator for my WooCommerce store. I need to collect some extra form data from the user to calculate the shipping properly.
I have the form fields added to woocommerce_checkout_after_customer_details. I can probably get this into the cart page without much trouble once I figure out the checkout page functionality, so let's focus on this.
I have a class extending WC_Shipping_Method with a calculate_shipping method a la this tutorial.
In that method, I want to use the extra form data (plus the destination) to calculate the shipping for that customer. Right now I just have this adding a dummy rate, which shows up.
I also created a custom cart-shipping.php file to not show any inputs for the available method in the order review cart, just the label and cost. Since the picking happens in my custom form, having options here is unnecessary.
Am I doing this right, or is this approach super hacky?
If this is the correct approach, how do I access the extra form fields inside the calculate_shipping method?
Have tried
Named the final options in my custom form shipping_method_* which triggers the wc-ajax=update_order_review call... which inits my custom shipping method class, but does not appear to ever call the calculate_shipping method anyhow. The only time this method seems to be called is when I'm actually adding a product to the order.
Also tried
Defined all of my possible delivery options and added them in calculate_shipping like $this->add_rate( $rate );. I think then I can somehow select one (force the user into one) when the cart updates via update_order_review ajax call? Again, the set option should be determined by these fields the user interacts with on the checkout form. But I haven't figured out how to set the shipping on that action yet.
calculate_shipping() is not always called
First off, you should know that the calculate_shipping() method of your shipping method class will only be called when the shipping rates are calculated for the first time (in the current WooCommerce session), each time after a product is added to the cart, and whenever the shipping address is changed — from the cart or checkout page.
But of course, a plugin or custom code can programmatically call the method (or re-calculate the rates) at any times. However, the default behavior is as follows:
Rates are stored in the session based on the package hash to avoid
re-calculation every page load.
And the calculate_shipping() method is executed by the WC_Shipping class through its calculate_shipping_for_package() method. In fact, the above quote was taken from the description of WC_Shipping::calculate_shipping_for_package() which calls WC_Shipping_Method::get_rates_for_package() and eventually the calculate_shipping() method in your own class.
How to get the submitted value of a form field in the checkout form from the calculate_shipping() method
So if you have this in the checkout form:
<input type="text" name="my_field"...>
Then you can get the submitted (POSTed) value using either the $_POST superglobal or the WC_Checkout::get_value() method:
$_POST['my_field']
WC()->checkout->get_value( 'my_field' )
It's as simple as that. :)
To ensure calculate_shipping is called
Run something similar to the following to clear out the session information, which will indicate that calculation still needs to be done. Be aware that if you do this on every page, it will mean that the shipping is constantly being recalculated when it doesn't need to be.
$packages = WC()->cart->get_shipping_packages();
foreach( $packages as $package_key => $package ) {
$session_key = 'shipping_for_package_'.$package_key;
$stored_rates = WC()->session->__unset( $session_key );
}
I'm not sure if this is the best way to accomplish this, but currently I am making this work by setting a session value on woocommerce_checkout_update_order_review and then accessing that value in my calculate_shipping method.
Looking at the WooCommerce documentation, it seems their desired way for you to access things such as user location from the calculate_shipping function is to use their Settings API. https://docs.woocommerce.com/document/settings-api/. Read the docs to see exactly how, but here is a simplification:
Read the location using
$this->init_settings();
$this->location = $this->settings['location'];
Write/Set the user's location with this table:
<?php function admin_options() {
?>
<h2><?php _e('You plugin name','woocommerce'); ?></h2>
<table class="form-table">
<?php $this->generate_settings_html(); ?>
</table><?php
}
The table would be made with
function init_form_fields() {
$this->form_fields = array(
'location' => array(
'title' => __( 'Location', 'woocommerce' ),
'type' => 'text',
'description' => __( 'This is the users address.', 'woocommerce' ),
'default' => __( 'none', 'woocommerce' )
)
);
}

Magento: Remove other shipping result when free shipping shown

I have setup the free shipping for specific product categories in magento by refering this blog post http://www.regularjen.com/archives/2010/06/11/free-shipping-on-a-single-item-in-magento/ . And its working fine. Now the issue is , Magento showing both free shipping & other shipping charges in shiiping reuslt.
How can i remove the those result ?
One solution might be to override the getShippingRates() method which you can find in the Mage_Checkout_Block_Onepage_Shipping_Method_Available class.
public function getShippingRates()
{
parent::getShippingRates();
if (isset($this->_rates['freeshipping'])) {
$this->_rates = array('freeshipping' => $this->_rates['freeshipping']);
}
return $this->_rates;
}

How to get all shipping costs for all countries for a product in Magento backend?

I'm currently working on a Magento backend plugin to create widgets for products. I'm trying to get a list of Shipping costs for a product for every country.
What I've got:
I've got a backend controller that loads a product model and I get all the data I need from this model.
The problem is getting a list of shipping costs for each country that is defined. How can I do that?
I've tried to use the example (http://www.magentocommerce.com/magento-connect/EcomDev/extension/3860/ecomdev_productpageshipping) posted by ʍǝɥʇɐɯ in the comments. But this is not working, I always get an empty array.
$addToCartInfo = array("estimate"=> array("country_id"=> "US"), "product"=> "1", "related_product" => "", "qty" => "1" );
$product->setAddToCartInfo($addToCartInfo);
$quote = Mage::getModel('sales/quote');
$shippingAddress = $quote->getShippingAddress();
$shippingAddress->setCountryId('US');
$shippingAddress->setCollectShippingRates(true);
$request = new Varien_Object($addToCartInfo);
$request->setQty(1);
$quote->addProduct($product, $request);
$quote->collectTotals();
$rateResult = $shippingAddress->getGroupedAllShippingRates();
Is there any difference between frontend and backend in this example that makes this code unusuable? How can I do that in the backend?
There is a module somewhere on Magento extensions that does that - maybe have a look for it first and re-use their code.

Categories