Ajax shipping estimator for X-Cart shopping cart
It's pretty easy to add a shipping calculator to X-Cart. Ajax estimator will allow your customers to receive shipping rates without page reloading.
First, you have to download the jquery lib and include it to your page. It can be done in the skin1/customer/meta.tpl (skin1/meta.tpl in older versions) using the following code:
<script type="text/javascript" src="{$SkinDir}/jquery.min.js"></script>
Of course you should download and place the jquey.min.js yourself and place it to your skin dir (skin1 usually). Please note that the jquery is already included into X-Cart since 4.2 branch, just check it in the skin1/customer/meta.tpl in this case.
Then we are able to modify the product page to insert the estimator code, let's place all of the code in separate files, so just include the following file in the skin1/customer/main/product.tpl
{include file='customer/shipping_calculator/shipping_calc.tpl'}
As you can see, you should create skin1/customer/shipping_calculator directory. You can use the following code for the shipping_calc.tpl. It's pretty basic one and you can adjust it to your design.
<script type="text/javascript"> var shc_productid='{$product.productid}'; {literal} function shippingEstimation() { $.ajax({ type: "GET", url: "shipping_calc.php?productid="+shc_productid+"&zipcode="+$('#shc_zipcode').val()+"&is_low=1", dataType: "html", success: function(msg){ $('#shc_results').css('display', ''); $('#shc_results').html(msg); $('#shc_estimation').css('display', 'none'); } }); } function backToEstimation() { $('#shc_results').css('display', 'none'); $('#shc_estimation').css('display', ''); } function viewAllShippingOptions() { window.open('shipping_calc.php?productid='+shc_productid, '','width=700,height=400,toolbar=no,status=no,scrollbars=yes,resizable=no,menubar=no,location=no,direction=no'); } {/literal} </script> <br/> <div id="shc_estimation"> <b>{$lng.lbl_shc_shipping_estimator}</b><br/> <input type="text" name="shc_zipcode" id="shc_zipcode" value="{$shipping_calc_zipcode|default:$lng.lbl_shc_enter_zipcode}" size="15" onfocus="this.value='';" /> {include file="customer/buttons/button.tpl" button_title=$lng.lbl_go href="javascript: return shippingEstimation();" style="link"} </div> <div id="shc_results"></div>
Here you will find a label Shipping estimator and place to enter a zip code. The zip code is enough for USA and Canada estimator, if you like to make the same for other countries - you have to add the appropriate select boxes and modify the javascript code to submit this data.
The main part of the estimator is a special shipping_calc.php script, which should be placed to the root of your X-Cart store. It is pretty short and easy.
<?php define('ALL_CARRIERS', 1); include "./auth.php"; include $xcart_dir."/shipping/shipping.php"; $product_info = func_select_product($productid, @$user_account['membershipid'], true, false, false, false); if ($zipcode) $shipping_calc_zipcode = $zipcode; else $zipcode = $shipping_calc_zipcode; $userinfo = array(); $userinfo['s_country'] = preg_match("/^([a-ceghj-npr-tv-z]){1}[0-9]{1}[a-ceghj-npr-tv-z]{1}[0-9]{1}[a-ceghj-npr-tv-z]{1}[0-9]{1}$/i",$zipcode)?'CA':'US'; $userinfo['s_zipcode'] = $zipcode; $shippings = array(); $product_info = func_select_product($productid, @$user_account['membershipid'], true, false, false, false); $product_info['amount'] = 1; $config['General']['apply_default_country'] = 'Y'; $config['Shipping']['enable_all_shippings'] = 'N'; $smarty->assign('zipcode', $zipcode); $smarty->assign('country', $userinfo['s_country']); $smarty->assign('product', $product_info); $cart_tmp = array(); $cart_tmp['products'] = array($product_info); $tmp_shipping = func_get_shipping_methods_list($cart_tmp, array($product_info), $userinfo, true); if ($is_low) { if (is_array($tmp_shipping)) { $min_price = $tmp_shipping[0]['rate']; $min_ship = $tmp_shipping[0]; foreach($tmp_shipping as $sh) if ($sh['rate'] < $min_price) $min_ship = $sh; } $smarty->assign('shipping', $min_ship); func_display('customer/shipping_calculator/min_rate.tpl', $smarty); exit(0); } $smarty->assign('shippings', $tmp_shipping); $smarty->assign("template_name", 'customer/shipping_calculator/popup.tpl'); func_display("customer/help/popup_info.tpl", $smarty); ?>
In this script we receive a zip code and recognize the type of zip code (US or CA). Then we prepare the fake cart and user data for the shipping calculation by the default X-Cart functions.
Also there are 2 possible inputs. For the product page we use $is_low flag and only the lowest shipping price is displayed. Here is a customer/shipping_calculator/min_rate.tpl template, which is used in this case:
{$lng.lbl_shc_standard_shipping|substitute:'zipcode':$zipcode} {include file='currency.tpl' value=$shipping.rate}<br/> <a href="javascript: backToEstimation();">{$lng.lbl_shc_change_zipcode}</a><br/> <a href="javascript: viewAllShippingOptions();">{$lng.lbl_shc_view_all_shippings}</a>
In this template the “View all shipping options” link is used. It refers to a pop-up page where a whole list of shipping methods is displayed. The customer/shipping_calculator/popup.tpl is used and you can use the following content for it:
<h1>{$lng.lbl_shc_quote_for_product|substitute:'product':$product.product}</h1> {$lng.lbl_available_shipping_methods}<br/> {foreach from=$shippings item=shipping} {$shipping.shipping|trademark:$insert_trademark} ({$shipping.shipping_time}) {include file='currency.tpl' value=$shipping.rate}<br/> {/foreach} <p>{$lng.lbl_shc_popup_note|substitute:'product':$product.product}</p>
Generally it is enough to create the shipping estimator. The zip code text box will be shown on the product page. Your customers can enter their zip code here and receive the lowest rate by ajax. Then they will be able to open the pop-up with all of the rates if required.
One more thing. There are some new language variables here. You can use the following queries in X-Cart admin area to insert them or create your own ones in the languages section:
INSERT INTO xcart_languages SET code='US', name='lbl_shc_shipping_estimator', value='Shipping estimator', topic='Labels'; INSERT INTO xcart_languages SET code='US', name='lbl_shc_enter_zipcode', value='Enter ZIP code', topic='Labels'; INSERT INTO xcart_languages SET code='US', name='lbl_shc_standard_shipping', value='Standard Shipping to {{zipcode}}', topic='Labels'; INSERT INTO xcart_languages SET code='US', name='lbl_shc_change_zipcode', value='Change Your zip code', topic='Labels'; INSERT INTO xcart_languages SET code='US', name='lbl_shc_view_all_shippings', value='View all shipping options', topic='Labels'; INSERT INTO xcart_languages SET code='US', name='lbl_shc_quote_for_product', value='Shipping quote for {{product}}', topic='Labels'; INSERT INTO xcart_languages SET code='US', name='lbl_shc_using_destination_zipcode', value='Using destination <b>{{country}} zipcode {{zipcode}}</b>', topic='Labels'; INSERT INTO xcart_languages SET code='US', name='lbl_shc_popup_note', value='Please note: this shipping quote is for one {{product}}. If you would like to have a quote for more than one of this product or for different products in the same order, please add all of the products that you want to your shopping cart.You will then have an option to get a shipping quote for your whole order', topic='Labels';
X-Cart real-time shipping
There are few possible problems with the real-time shipping calculation. And all of them are related to UPS integration.
First, UPS system supports 2 types of rates: published and negotiated. For the negotiated rated the state field is required in the request to the UPS, here is the part of the official UPS doc:
The receiver's state code. Note: A State/Province Code is required when requesting to receive the negotiated rates. The State/Province code is optional when requesting to receive the published rates.
Since the implementation above does not require to know a state, the negotiated rates have to be disabled. You can make it on the UPS settings page in the X-Cart admin.
Secondly the UPS rates are moved to the separate carrier in X-cart and in some cases are not returned (or just UPS rates are returned and the USPS, FeDEX or any other carrier are missed). It was the reason to use define(ALL_CARRIERS, 1) in the shipping calculation, but in some of the cases it would not help. In this case you should look at the shipping/myshipper.php and check which $ship_mods is used after the following code:
if (defined('ALL_CARRIERS')) { $ship_mods = func_array_merge($ship_mods, $alt_ship_mods); $ship_mods = array_unique($ship_mods); $alt_ship_mods = array(); }
If the required carrier is missed here - it's better to add it to the “if” section above. For example by the following way:
# add it before the last { in the code above $ship_mods[] = "UPS";
PS: BTW, have you got a wordpress blog already? Read how to integrate it with X-Cart.