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.

Creating a Form for Billing Information

The Billing Information partial contains a form gathering customer billing information:

  • billing first and last names
  • bulling email address
  • billing company and phone
  • billing address

Start with creating a new partial. According to the code example in the Checkout Page partial code, the name of the Billing Information partial should be shop:checkout_billing_info. You could use any other name for partials in your store.

The following code demonstrates an example of a Billing Information partial:

<h3>Billing Information</h3>
<? if ($this->customer): ?>
  <p>Bill to: <strong><?= h($this->customer->name) ?>, <?= $this->customer->email ?></strong>.</p>
<? endif ?>
<? if (!$this->customer): ?>
  <label for="first_name">First Name</label>
  <input name="first_name" value="<?= h($billing_info->first_name) ?>" id="first_name" type="text" /><br/>
  
  <label for="last_name">Last Name</label>
  <input name="last_name" value="<?= h($billing_info->last_name) ?>" id="last_name" type="text" /><br/>
  
  <label for="email">Email</label>
  <input id="email" name="email" value="<?= h($billing_info->email) ?>" type="text" /><br/>
<? endif ?>

<label for="company">Company</label>
<input id="company" type="text" value="<?= h($billing_info->company) ?>" name="company" /><br/> 

<label for="phone">Phone</label>
<input id="phone" type="text" value="<?= h($billing_info->phone) ?>" name="phone"/><br/>

<label for="street_address">Street Address</label>
<input id="street_address" name="street_address" type="text" value="<?= h($billing_info->street_address) ?>"/><br/>

<label for="city">City</label>
<input id="city" type="text" name="city" value="<?= h($billing_info->city) ?>"/><br/>

<label for="zip">Zip/Postal Code</label>
<input id="zip" type="text" name="zip" value="<?= h($billing_info->zip) ?>"/><br/>

<label for="country">Country</label>
<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': '<?= $billing_info->state ?>'},
  update: {'billing_states': 'shop:state_selector'}
})">
  <? foreach ($countries as $country): ?>
    <option <?= option_state($billing_info->country, $country->id) ?> 
      value="<?= h($country->id) ?>"><?= h($country->name) ?></option>
  <? endforeach ?>
</select><br/>

<label for="state">State</label>
<div id="billing_states">
  <?= $this->render_partial('shop:state_selector', array(
    'states'=>$states, 
    'control_id'=>'state', 
    'control_name'=>'state', 
    'current_state'=>$billing_info->state)) ?>
</div>
<input type="hidden" name="checkout_step" value="<?= $checkout_step ?>"/>
<input type="button" value="Next" onclick="return $(this).getForm().sendRequest(
  'on_action',
  {update:{'checkout_page': 'checkout_partial'}})"/>
<h3>Billing Information</h3>
{% if this.customer %}
  <p>Bill to: <strong>{{ field(this.customer, 'name') }}, {{ this.customer.email }}</strong>.</p>
{% endif %}

{% if not this.customer %}
  <label for="first_name">First Name</label>
  <input name="first_name" value="{{ billing_info.first_name }}" id="first_name" type="text" class="text"/><br/>
  
  <label for="last_name">Last Name</label>
  <input name="last_name" value="{{ billing_info.last_name }}" id="last_name" type="text" class="text"/><br/>

  <label for="email">Email</label>
  <div><input id="email" name="email" value="{{ billing_info.email }}" type="text" class="text"/><br/>
{% endif %}

<label for="company">Company</label>
<input id="company" type="text" value="{{ billing_info.company }}" name="company" class="text"/><br/>

<label for="phone">Phone</label>
<input id="phone" type="text" class="text" value="{{ billing_info.phone }}" name="phone"/><br/>

<label for="street_address">Street Address</label>
<input id="street_address" type="text" name="street_address" value="{{ billing_info.street_address }}"/><br/>

<label for="city">City</label>
<input id="city" type="text" class="text" name="city" value="{{ billing_info.city }}"/><br/>

<label for="zip">Zip/Postal Code</label>
<input id="zip" type="text" class="text" name="zip" value="{{ billing_info.zip }}"/><br/>

<label for="country">Country</label>
<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': '{{ billing_info.state }}'},
    update: {'billing_states': 'shop:state_selector'}
  })">
  {% for country in countries %}
    <option {{ option_state(billing_info.country, country.id) }} value="{{ country.id }}">{{ country.name }}</option>
  {% endfor %}
</select><br/>

<label for="state">State</label>
<div id="billing_states">
  {{
    render_partial(
      'shop:state_selector', 
      {
        'states': states, 
        'control_id': 'state', 
        'control_name': 'state', 
        'current_state': billing_info.state
      }
    )
  }}
</div>

<div class="clear"></div>
<input type="hidden" name="checkout_step" value="{{ checkout_step }}"/>
<input type="button" value="Next" onclick="return $(this).getForm().sendRequest(
  'on_action',
  {update:{'checkout_page': 'checkout_partial'}})"/>

The code creates text labels and INPUT elements for entering customer billing information. In the beginning of the code snippet you can see the conditional statement checking whether the logged in customer is present. If it is true, the code outputs the customer name and email address. $customer is a field of the Cms_Controller class which is accessible as $this variable inside any page, partial and template code.

If there is no customer logged in, the code outputs controls for specifying the billing first name, last name and email address. Otherwise these controls are not displayed and corresponding values are loaded from the current customer object by LemonStand automatically.

The code for displaying most of the fields is simple. The $billing_info variable (an instance of Shop_CheckoutAddressInfo class) is always available in the Checkout page code. The values of INPUT element names and Ids should be used as demonstrated in the code example.

The list of available countries is presented in the $countries variable. The SELECT element used for displaying the country list has the onChange event handler which sends an AJAX request to LemonStand for updating the state list. The state list is wrapped into the DIV element with a specific ID (billing_states). The content of this element is updated each time a visitor selects another country in the country list with content of shop:state_selector partial. shop:state_selector is is simple partial used solely for updating the state list with AJAX and contains the following code:

<select id="<?= h($control_id) ?>" name="<?= $control_name ?>">
  <? foreach ($states as $state): ?>
    <option <?= option_state($current_state, $state->id) ?> value="<?= h($state->id) ?>"><?= h($state->name) ?></option>
  <? endforeach ?>
</select>
<select autocomplete="off" id="{{ control_id }}" name="{{ control_name }}">
  {% for state in states %}
    <option {{ option_state(current_state, state.id) }} value="{{ state.id }}">{{ state.name }}</option>
  {% endfor %}
</select>

The values of variables $states, $current_state, $control_name, $control_id are passed to the partial from the outside code.

The hidden field checkout_step is needed for LemonStand for determining a current checkout step and processing the form field values.

The last line in the code snippet contains the Next button with onClick event handler which sends LemonStand an AJAX request forcing the script to validate the form and go to the next checkout step.

See also:

Next: Creating a Form for Shipping Information
Previous: AJAX-driven single-page checkout
Return to AJAX-driven single-page checkout