Versions 0.7.1 and older: Note that applying javascript shipping modifications using either live or flat rates where you are setting custom values has been found to not work as expected for subscription based products where you need the shipping to apply to each subscription renewal. A fix is in place for versions 0.7.2 and newer.
Using version 2.0? There is a new snippet available for our latest version, available from here.
If you're using handling fees note that you can't overwrite handling fees using javascript on the checkout to provide free shipping. While it will appear that the shipping is $0 on the checkout, the handling fees will be added back in server-side, and the customer will see a shipping fee that matches the handling fee cost you have set in the administration.
The following functionality allows you to add and update any number of custom flat rate shipping options based on any criteria (eg: what categories are products in, total cost of the cart, shipping destination country). This script is limited to flat rate shipping only.
The functionality described on this page require advanced javascript knowledge, and are not officially supported. They are included in our official wiki because certain shipping methods and functionality are not natively supported, and though we are working on radically improving our shipping functionality, in the meantime these methods may be great workarounds. Use with caution, test, and post in our forum if you run into problems.
See the changelog for details on updates to this script.
Update all categories to 'Shipped using a flat rate fee' with a value of 0 in the 'Product Delivery Option' section.
Add the following right after the ^^checkout^^ placeholder in your checkout template:
^^custom_begin^^ <div id="fc_custom_shipping_methods_container"> </div> ^^custom_end^^
Add the following right before the closing </head>
tag in your checkout template (we will add code to the “customShippingLogic” function later):
<script type="text/javascript" charset="utf-8"> //<![CDATA[ FC.checkout.config.customShipping = { onLoad: true, // Set to false if you don't want shipping calculated when the checkout loads onLocationChange: false, // Set to true if your shipping logic relies on updating whenever the shipping location for the order changes onPreSubmit: true // Set to false if you don't want to load shipping if it hasn't already loaded before the user tries to checkout }; function customShippingLogic() { /* BEGIN CUSTOM SHIPPING LOGIC */ // ... add your custom logic here /* END CUSTOM SHIPPING LOGIC */ } //]]> </script> <script type="text/javascript" charset="utf-8"> //<![CDATA[ /* Multiple Flat Rate Shipping Options Logic v2.4 */ jQuery(document).ready(function() { jQuery("#fc_custom_shipping_methods_container").on('click', 'input[name=shipping_service]', function(){ shipping_service_description = jQuery(this).siblings(".fc_shipping_carrier").html(); shipping_service_description += ((shipping_service_description == "") ? '' : ' '); shipping_service_description += jQuery(this).siblings(".fc_shipping_service").html(); $("#shipping_details").val(shipping_service_description); // Launch FoxyCart functionality FC.checkout.updatePrice(-1); }); if (FC.checkout.config.customShipping.onLoad) { runShippingLogic(); } if (FC.checkout.config.customShipping.onLocationChange) { isValidateAndSubmit = false; FC.checkout.overload("updateTaxes", function() { if (!isValidateAndSubmit) { runShippingLogic(); } }, null); FC.checkout.overload("validateAndSubmit", function() { isValidateAndSubmit = true; }, function() { isValidateAndSubmit = false }); } if (FC.checkout.config.customShipping.onPreSubmit) { FC.checkout.overload("validateAndSubmit", function() {if (!jQuery("#shipping_service_id").length) { runShippingLogic(); }}, null); } }); function runShippingLogic() { // Check to see if there are actually shippable products in the current cart before running the custom shipping (0.7.1+ only), or just run it for older carts if ((typeof(FC.checkout.config.hasShippableProducts) === "boolean" && FC.checkout.config.hasShippableProducts) || typeof(FC.checkout.config.hasShippableProducts) === "undefined") { customShippingLogic(); } } // example: addShippingOption(1, 4.99, 'PostBox', 'Express Local'); function addShippingOption(code, cost, carrier, service) { if (jQuery("#fc_shipping_methods_inner").length == 0) { addCustomShippingContainer(); } carrier = (typeof(carrier) == 'undefined' || carrier == null) ? "" : carrier; service = (typeof(service) == 'undefined' || service == null) ? "" : service; var newShippingOption = '<label for="shipping_service_' + code + '" class="fc_radio"><input type="radio" class="fc_radio fc_required" value="' + code + '|' + cost + '" id="shipping_service_' + code + '" name="shipping_service" /><span class="fc_shipping_carrier">' + carrier + '</span><span class="fc_shipping_service">' + service + '</span><span class="fc_shipping_cost">' + FC.formatter.currency(cost, true) + '</span></label>'; jQuery("#fc_shipping_methods_inner").append(newShippingOption); } // example: updateShippingOptionCost(1, 4); function updateShippingOptionCost(code, cost) { jQuery("input#shipping_service_" + code).val(code + '|' + cost).siblings("span.fc_shipping_cost").html(FC.formatter.currency(cost, true)); FC.checkout.updatePrice(-1); } // example: removeShippingOption(1); function removeShippingOption(code) { jQuery("label[for=shipping_service_" + code + "]").remove(); if (jQuery("#fc_shipping_methods_inner").html() == "") { removeCustomShippingContainer(); } FC.checkout.updatePrice(-1); } function addCustomShippingContainer() { jQuery("#fc_custom_shipping_methods_container").html('<h2>Shipping Options</h2><div class="fc_row fc_shipping_methods_container" id="fc_shipping_methods_container"><div class="fc_radio_group_container fc_row fc_shipping_methods" id="fc_shipping_methods"><input type="hidden" value="0" id="shipping_service_id" name="shipping_service_id"><input type="text" style="display:none;" value="" id="shipping_service_description" name="shipping_service_description"><input type="text" value="" id="shipping_details" name="Shipping_Details" style="display:none;" /><div class="fc_shipping_methods_inner" id="fc_shipping_methods_inner"></div><label style="display: none;" class="fc_error" for="fc_shipping_methods">Please select a shipping method.</label></div></div>'); } function removeCustomShippingContainer() { jQuery("#fc_custom_shipping_methods_container").html(""); FC.checkout.updatePrice(-1); } //]]> </script>
Based on the type of shipping options you're providing, you may need to customise when the shipping options are run in your script. At the top of the script, you need to edit the options array to match the type of functionality you're looking for. Note: If all options are set to false, the shipping options will never run.
FC.checkout.config.customShipping = { onLoad: true, onLocationChange: false, onPreSubmit: true };
onLoad
: If set to true, your shipping logic will run once the checkout has completed loading. Recommended value: trueonLocationChange
: If set to true, this will run your shipping logic whenever the checkout tries to recalculate taxes - which is generally after the customer changes a location input like country, state and postcode. If your shipping logic is based off of an address detail, this should be set to true. Note that this means your shipping logic may be run multiple times before the customer checks out, so make sure you account for it by using the removeCustomShippingContainer()
or updateShippingOptionCost()
methods. If not, you may end up in a situation with duplicate copies of the same shipping option.onPreSubmit
: If set to true, your shipping logic will run when the user tries to complete the purchase, and if no shipping options have been presented to the customer yet, it loads them at that point. Recommended value: true
Now the fun part, based on whatever criteria you want, add in the different shipping options you require for your site. Add your custom code between the /* BEGIN CUSTOM SHIPPING LOGIC */
and /* END CUSTOM SHIPPING LOGIC */
lines in the first script block. There are four functions available to you.
addShippingOption()
code, cost, carrier, service
addShippingOption(1, 4.99, 'PostBox', 'Local Delivery');
updateShippingOptionCost()
code, cost
updateShippingOptionCost(1, 5.50);
removeShippingOption()
code
removeShippingOption(1);
removeCustomShippingContainer()
removeCustomShippingContainer();
Note that the code parameter must be a number. Setting it to a string will result in your checkout failing in a situation where the gateway returns your customer to the checkout with an error.
addShippingOption(1, 5, 'Postmaster', 'Standard Delivery'); addShippingOption(2, 9.45, 'Postmaster', 'Priority Delivery'); addShippingOption(3, 10, 'PostPlus', 'Express (Next Day)'); if (fc_json.total_weight > 10) { updateShippingOptionCost(1, 6); updateShippingOptionCost(2, 10); updateShippingOptionCost(3, 11.99); } if (fc_json.product_count > 5) { removeShippingOption(3); }
onLocationChange
being set to trueif (typeof(country_code) === "undefined") {country_code = "";} new_country_code = (jQuery("#use_different_addresses").is(":checked") ? $("#shipping_country").val() : $("#customer_country").val()); if (country_code != new_country_code) { // The shipping country has changed! country_code = new_country_code; removeCustomShippingContainer(); // This call will make sure that when it updates, it starts fresh. if (country_code == "US") { postage = 10 + ((fc_json.product_count - 1) * 0.50); addShippingOption(1, postage, 'USPS', 'Standard'); postage = 12 + ((fc_json.product_count - 1) * 1.50); addShippingOption(2, postage, 'USPS', 'Express'); } else { postage = 15 + ((fc_json.product_count - 1) * 2); addShippingOption(3, postage, 'USPS', 'International'); } }
var hasCategoryA = false; var hasCategoryB = false; for (p in fc_json.products) { switch (fc_json.products[p ].category) { case "CategoryA": hasCategoryA = true; break; case "CategoryB": hasCategoryB = true; break; } } if (hasCategoryB && !hasCategoryA) { addShippingOption(1, 0, '', 'Free Ground Shipping'); } else if (hasCategoryA) { addShippingOption(2, 5.99, 'USPS', 'Express') }