This is the documentation for LemonStand V1, which has been discontinued. You can learn more and upgrade your store here.

LemonStand Version 1 Has Been Discontinued

This documentation is for LemonStand Version 1. LemonStand is now offered as a cloud-based eCommerce platform.
You can try the new LemonStand and learn about upgrading here.

Implementing the Shipping Cost Estimator Feature

The shipping cost estimator feature allows customers to estimate shipping quotes for different shipping methods before they begin the checkout process. You can implement the shipping cost estimator on any page of your store, but usual place for it is the Cart page.

Implementing the Shipping Cost Estimator form

The shipping rate estimator feature uses the shop:on_evalShippingRate event handler, which requires a country and state identifiers and a ZIP code. The event handler generates the $shipping_options PHP variable, which is an array containing a list of available shipping options and prices. You should build a partial for rendering the shipping option. Below is an example code of a form for specifying the shipping location (country, state and ZIP code). 

<h4>Estimate shipping cost</h4>

<select id="country" name="country" onchange="return $('#country').getForm().sendRequest(
  'shop:on_updateStateList', {      
    extraFields: {'country': $('#country').val(),
    'control_name': 'state',
    'control_id': 'state',
    'current_state': '<?= $shipping_info->state ?>'},
    update: {'shipping_states': 'shop:state_selector'}
  })">
  <? foreach ($countries as $country): ?>
    <option value="<?= $country->id ?>" <?= option_state($country->id, $shipping_info->country) ?>><?= h($country->name) ?></option>
  <? endforeach ?>
</select>

<span id="shipping_states">
  <?= $this->render_partial('shop:state_selector', array(
    'states'=>$states, 
    'control_id'=>'state', 
    'control_name'=>'state', 
    'current_state'=>$shipping_info->state)) ?>
</span>

<label>Zip: <input type="text" class="zip" name="zip" value="<?= h($shipping_info->zip) ?>"/></label>
 
<a href="#" onclick="return $(this).getForm().sendRequest('shop:on_evalShippingRate', {
  update: {'shipping_options': 'estimated_shipping_options'}})">Submit</a>

<div id="shipping_options"></div>
<h4>Estimate shipping cost</h4>

<select id="country" name="country" onchange="return $('#country').getForm().sendRequest(
  'shop:on_updateStateList', {      
    extraFields: {'country': $('#country').val(), 
    'control_name': 'state', 
    'control_id': 'state', 
    'current_state': '{{ shipping_info.state }}'},
    update: {'shipping_states': 'shop:state_selector'}
  })">
  {% for country in countries %}
    <option value="{{ country.id }}" {{ option_state(country.id, shipping_info.country) }}>{{ country.name }}</option>
  {% endfor %}
</select>

<span id="shipping_states">
  {{ render_partial(
      'shop:state_selector', {
        'states': states, 
        'control_id': 'state', 
        'control_name': 'state', 
        'current_state': shipping_info.state
  }) }}
</span>

<label>Zip: <input type="text" class="zip" name="zip" value="{{ shipping_info.zip }}"/></label>
 
<a href="#" onclick="return $(this).getForm().sendRequest('shop:on_evalShippingRate', {
  update: {'shipping_options': 'estimated_shipping_options'}})">Submit</a>
  
<div id="shipping_options"></div>

Please note that the state list on the form updates (using AJAX) each time when a customer selects a country in the country list. This approach is explained on the Creating the Billing Information Partial page.

The $countries, $states and $shipping_info variables used in the example are generated automatically by the shop:cart action.

The Submit link on the form sends the AJAX request to the server, invoking the shop:onEvalShippingRate handler. The request updates the DIV element with the shipping_options identifier, using the estimated_shipping_options partial. You can use other DIV identifier and partial name in your implementation. The estimated_shipping_options partial is described below.

Implementing the shipping options partial

The shipping options partial is a partial which renders when a customer clicks the Submit button on the estimator form. In our examples the partial name is 'estimated_shipping_options'. The shop:on_evalShippingRate handler generates the $shipping_options variable which contains a list of available options. The following code example demonstrates how you can render shipping options and rates. Please note, that some shipping options has sub options. For example, the UPS and USPS gateways return multiple shipping options. The code below displays a common header for such shipping options.

<? if (count($shipping_options)): ?>
  <ul>
    <? foreach ($shipping_options as $option): ?>
      <? if ($option->multi_option): ?>
        <li>
          <h4><?= h($option->name) ?></h4>
          <? if ($option->description): ?>
            <p><?= h($option->description) ?></p>
          <? endif ?>

          <ul>
          <? foreach ($option->sub_options as $sub_option): ?>
            <li>
              <?= h($sub_option->name) ?> - 
              <strong><?= !$sub_option->is_free ? format_currency($sub_option->quote) : 'free' ?></strong>
            </li>
          <? endforeach ?>
          </ul>
        </li>
      <? else: ?>
        <li>
          <?= h($option->name) ?> - 
          <strong><?= !$option->is_free ? format_currency($option->quote) : 'free' ?></strong>
          <? if ($option->description): ?>
            <span><?= h($option->description) ?></span>
          <? endif ?>
        </li>
      <? endif ?>
    <? endforeach ?>
  </ul>
<? else: ?>
  <p>There are no shipping options available for your location.</p>
<? endif ?>
{% if shipping_options|length > 0 %}
  <ul>
    {% for option in shipping_options %}
      {% if option.multi_option %}
        <li>
          <h4>{{ option.name }}</h4>
          {% if option.description|length > 0 %}
            <p>{{ option.description }}</p>
          {% endif %}

          <ul>
            {% for sub_option in option.sub_options %}
              <li>{{ sub_option.name }} - <strong>{{ not sub_option.is_free ? sub_option.quote|currency : 'free' }}</strong></li>
            {% endfor %}
          </ul>
        </li>
      {% else %}
        <li>
          {{ option.name }} - <strong>{{ not option.is_free ? option.quote|currency : 'free' }}</strong>
          {% if option.description|length > 0 %}
            <span>{{ option.description }}</span>
          {% endif %}
        </li>
      {% endif %}
    {% endfor %}
  </ul>
{% else %}
  <p>There are no shipping options available for your location.</p>
{% endif %}

Displaying shipping service error messages

By default LemonStand does not return shipping options with errors. If a visitor entered an invalid ZIP code, all shipping options provided by external services (USPS, UPS, etc.) would be suppressed. You can enable the Display shipping service errors option on the Parameters tab of the System/Settings/Shipping Configuration page. When this option is enabled, LemonStand returns all options. To determine whether a shipping option has an error message assigned, use the error_hint field of the Shop_ShippingOption class. If this field is not empty, you should display its content instead of the option price. Example:

<? if (count($shipping_options)): ?>
  <ul>
    <? foreach ($shipping_options as $option): ?>
      <? if ($option->error_hint): ?>
        <li><?= h($option->name) ?> - <?= h($option->error_hint) ?></li>
      <? else: ?>
        <? if ($option->multi_option): ?>
          <li>
            <h4><?= h($option->name) ?></h4>
            <? if ($option->description): ?>
              <p><?= h($option->description) ?></p>
            <? endif ?>
  
            <ul>
            <? foreach ($option->sub_options as $sub_option): ?>
              <li>
                <?= h($sub_option->name) ?> - 
                <strong><?= !$sub_option->is_free ? format_currency($sub_option->quote) : 'free' ?></strong>
              </li>
            <? endforeach ?>
            </ul>
          </li>
        <? else: ?>
          <li>
            <?= h($option->name) ?> - 
            <strong><?= !$option->is_free ? format_currency($option->quote) : 'free' ?></strong>
            <? if ($option->description): ?>
              <span><?= h($option->description) ?></span>
            <? endif ?>
          </li>
        <? endif ?>
      <? endif ?>
    <? endforeach ?>
  </ul>
<? else: ?>
  <p>There are no shipping options available for your location.</p>
<? endif ?>
{% if shipping_options|length > 0 %}
  <ul>
    {% for option in shipping_options %}
      {% if option.error_hint %}
        <li>{{ option.name }} - {{ option.error_hint }}</li>
      {% else %}
        {% if option.multi_option %}
          <li>
            <h4>{{ option.name }}</h4>
            {% if option.description|length > 0 %}
              <p>{{ option.description }}</p>
            {% endif %}
  
            <ul>
              {% for sub_option in option.sub_options %}
                <li>{{ sub_option.name }} - <strong>{{ not sub_option.is_free ? sub_option.quote|currency : 'free' }}</strong></li>
              {% endfor %}
            </ul>
          </li>
        {% else %}
          <li>
            {{ option.name }} - <strong>{{ not option.is_free ? option.quote|currency : 'free' }}</strong>
            {% if option.description|length > 0 %}
              <span>{{ option.description }}</span>
            {% endif %}
          </li>
        {% endif %}
      {% endif %}
    {% endfor %}
  </ul>
{% else %}
  <p>There are no shipping options available for your location.</p>
{% endif %}


Previous: Creating a Shopping Cart Page
Return to Creating a Shopping Cart Page