Store Default Shipping Plugin
Written by: Justin Long | On: August 30, 2012
If you are following along with my Exp:resso Store series I promise that my next post will be picking backup after my 3 week hiatus. Today however I want to talk about the Default Shipping Plugin that ships with Store. I am going to be making some changes to the default shipping core files but these changes will become standard in the next release of Store. I will be using the modified version of the plugin in my series.
If you don't need live rates for your site it is a great option it also allows you to easily do things like Free Shipping when your order reaches a certain $ amount. If you have ever used the Default Shipping Plugin you might have had some weird issues with certain rules appearing higher then you anticipated or for some reason your Free Shipping rule sinks to the bottom of the list. The problem with is is the Default Shipping Plugin has one very important rule when it comes to usage in your checkout templates and that is when it is evaluating rules it stops at the first rule that meets its criteria. So my Free Shipping rule that became the last rule in the list of rules to be evaluated is going to cause unexpected behaviors. Store by default uses a complex query to rank and sort the rules which ranks more complex rules higher then simpler rules. For example if I had a rule for the United States with any region and gave it a shipping total of $5 a rule with United States and Florida selected with a shipping total of $10 would result in users in Florida automatically being charged $10. That makes sense but it doesn't make sense if I now include a rule with Free Shipping for orders over $25 for everywhere the site ships to. So for example a user in Texas would still be charged $5 because the shipping rule for the United States is more complex. The easiest way I think to illustrate what is happening is to show you the actual query that determines the order.
// line #128
$this->db->order_by('priority DESC, country_code_order ASC,
country_code ASC, region_code_order ASC, region_code ASC,
postcode_order ASC, postcode ASC, min_order_qty ASC,
max_order_qty ASC, min_order_total ASC, max_order_qty ASC,
min_weight ASC, max_weight ASC');
When I originally came across this problem I thought I was going to need write an extension to leverage one of Store's extensions hooks but the query above brought on a new idea. As of version 1.5.3 Store does not currently set or use the priority column of the shipping_rules table. So I just needed to enter a value into the column and that rule would be evaluated first. To do this you will need to edit 3 files inside of Store, I actually edited 4 because I wanted the priority to be available on the shipping rules main page too. The files in question are /store/language/english/store_lang.php, /store/models/store_shipping_model.php, /store/views/settings/shipping_default_edit.php, and /store/views/settings/shipping_default.php.
Lets start with "shipping_default_edit.php" this file controls the page that you see when you are adding/editing a rule. Open it up and look around lines 57-60 for
Once you have found it on a new line you will want to add
We can now save the file and move onto the "store_lang.php" file. We just need to add our newly created language variable to the array inside the file. It can go anywhere in the file but I like to try and keep it as organized as possible so I inserted
form_input('shipping_rule[priority]', set_value('shipping_rule[priority]', $shipping_rule['priority']), 'placeholder="'.lang('none').'"')
around line 138. You can save the file and close it. Before Store will save our newly created field to the DB we need to open up "store_shipping_model.php". You will want do a search in the file for "private function _clean_shipping_rule($data)" after you have found that scroll down to about line 238 where you will see "if (isset($data['enabled']))" you will want to create a new line and add
'shipping_priority_desc' => 'Higher numbers will be evaluated first',
if (isset($data['priority'])) $output['priority'] = (int)$data['priority'];
After you have done that you can save the file and should be able to now add a priority to your rules. The higher the value you place on your rule the higher it will be when Store evaluates the rules during checkout. Remember that rules with the same priority will be evaluated in the same fashion as before and that the priority field must be a whole number. Trying to enter something other then a number in the priority field will result in a priority of "0". You also want to remember to create a catch-all field with a very low priority. If you do not set a priority when you are creating a new rule it will default to "0".
If you want to show the priority on the main Shipping Rule page you will need to open "shipping_default.php" and scroll down to line 21 or so. The first bit of code we add is going to add Priority to the table header so remember the order of the column where you add the following code.
If your newly added code is on line 22 you will want to jump down to 39 and add a new line beneath it with
array('data' => lang('priority'), 'width' => '7%'),
now occupying line 40. You can now save the file and close your editor because we are done adding the priority field to the Default Shipping Plugin.
If you have nay questions or problems post them in the comments below. These changes should be implemented in the next version of Store to be released but until then please remember to document all core changes and make a back up of your files. I am not responsible for your actions so please be careful.