Checkout Tag

{exp:store:checkout}
    <!-- checkout form -->
{/exp:store:checkout}

This tag handles the entire checkout process, from updating item quantities, to billing and shipping details, through to submitting and paying for the order. It is extremely flexible, and you can template the process however you like - either as a single, or as a multi step process. You can also choose which step of the process will require users to log in, or simply allow anonymous orders.

Think of the user’s cart as being like a session. With Expresso Store, your visitors add items to their cart. When they get to the checkout, they update their cart with billing and shipping details, and the cart totals are recalculated to reflect their relevant tax and shipping costs.

When the user reaches the final step of your checkout, the cart is converted in to an order. At this point, if any payment details were submitted on the final page of the checkout, these are sent to the relevant payment gateway, and the user will be taken to your payment success (or failure) page.

Checkout Tag Parameters

next=”path”

The next step of a multi step checkout. If the user clicks an input button with name=”next”, and current form validates, the user will be redirected to this location.

{exp:store:checkout next="checkout/confirm"}
    <input type="submit" name="next" value="Confirm Order" />
{/exp:store:checkout}

return=”path”

Where to redirect the user to once the order is submitted. You only need to add this parameter to the last step of your checkout process. The order will only be submitted when the user clicks an input button with name=”submit”, this is to differentiate between other buttons in the form.

Optionally, you may redirect to an order-specific confirmation page (this is the normal setup). The constants ORDER_ID and ORDER_HASH can be used in this parameter to customize your return location.

{exp:store:checkout return="order/ORDER_HASH"}
    <input type="submit" name="submit" value="Place Order" />
{/exp:store:checkout}

Alternatively, since 1.3.0 you may name your submit button “commit”. This allows compatibility when using javascript to interact with your form on certain browsers.

form_id=”value”

Set an id attribute on the generated HTML form.

form_name=”value”

Set a name attribute on the generated HTML form.

form_class=”value”

Set a class attribute on the generated HTML form.

html:attribute=”value”

Specify arbitrary attributes on the generated HTML form. For example:

html:parsley-validate="true"

payment_method=”name”

Set the payment method of the current cart. This can also be specified via a hidden input or select drop-down if you would like to give the user a choice of payment methods.

register_member=”yes”

Create a member account for this user when the order is complete.

secure=”yes”

Ensures the current page is displayed over a secure SSL (HTTPS) connection. If the page was not displayed over HTTPS, the user is redirected to a secure version. The current form action is also submitted over HTTPS. If you accept inline credit card details on the final page of the checkout, this option must be set. If you configure “Require SSL connection for checkout and order tags” in the Store settings, all tags will have this option by default.

require=”fields”

Specify a pipe-separated list of required fields. All order fields can be made required using this tag. In addition, a shorthand syntax is available if both billing and shipping details are required. For example, the following parameter:

{exp:store:checkout require="name|address1|address2|state|country|postcode"}

is equivalent to typing:

{exp:store:checkout require="billing_name|billing_address1|billing_address2|billing_state|billing_country|billing_postcode|
  shipping_name|shipping_address1|shipping_address2|shipping_state|shipping_country|shipping_postcode"}

Much nicer, right?

rules:field_name=”rule”

As well as using the require="field_name" parameter, the longer SafeCracker-style syntax is also available. For each field, any of the CodeIgniter Form Validation Rules may be specified. If this syntax is used in addition to the require="field_name" parameter, both will apply. Note that the order_email field is already run through the valid_email rule, you don’t need to manually specify it.

rules:billing_name="required"
rules:billing_phone="numeric"
rules:billing_postcode="required|min_length[5]|max_length[5]"

error_handling=”inline”

By default, validation errors are displayed using the ugly standard ExpressionEngine error template. To alleviate this issue, add error_handling="inline" to your template. Field-specific error messages will then become available in the form {error:field_name}, which you can add to your template code in appropriate places. If you are having trouble with your form not submitting, the first thing you should try is removing the error_handling="inline" parameter from your template, as often this is caused by validation errors which you have forgotten to display error messages for.

error_delimiters=”pre|post”

You can optionally specify HTML to wrap around your inline error messages. This should be specified as two pipe-separated elements. If do not have error_handling="inline" on your checkout tag, this parameter will have no effect.

error_delimiters='<span class="notice">|</span>'

disable_javascript=”yes”

When set to yes, this disables any automatic javascript output by the tag.

Checkout Tag Variables

Items Loop

Loop through the order items. Inside the items loop, most product variables are available. All prices may be appended with _val to display the unformatted value.

{items}
    <!-- item details -->
{/items}

Inside the {items} loop, you can use the following variables:

entry_id

The entry id of this item. If you need to access other custom fields associated with this item, you can feed the entry id into a channel entries loop:

{items}
  {exp:channel:entries entry_id="{entry_id}"}
    {my_custom_field}
  {/exp:channel:entries}
{/items}

sku

The product SKU.

title

The product entry title.

url_title

The product entry URL title.

price

The applicable price of the product, (equal to the sale price if the product is on sale, otherwise the regular price).

regular_price

The regular price of the product, regardless of whether it is currently on sale.

sale_price

The sale price of the product, regardless of whether it is currently on sale.

if on_sale

True if the product is currently on sale.

handling

The per-item handling surcharge. If the user purchases multiple items, this number will be multiplied by the item quantity, and displcyed in the {order_handling} variable.

if free_shipping

True if the product has free shipping selected.

length

The length of the product.

width

The width of the product.

height

The height of the product.

weight

The weight of the product.

modifiers Variable Pair

Displays the selected item modifiers for the product. Inside the modifiers loop, you can use the following variables:

  • {modifier_name} - The name of the modifier group.
  • {modifier_value} - The selected option (or value of text modifiers).
  • {price_mod} - The amount added to the base product price for this modifier.

you_save

The dollar discount value if the product is on sale.

you_save_percent

The percentage discount value if the product is on sale, rounded to the nearest whole number.

item_qty

The number of this product the user has in their cart.

item_subtotal

The item price multiplied by the item quantity.

item_discount

The total discounts applied to this item.

item_tax

The total tax applicable to this item.

item_total

The item total, including discounts and tax.

item:count

The row number of this item (similar to the channel entries tag’s {count} variable).

item:total_results

The total number of rows in the cart (similar to the channel entries tag’s {total_results} variable). This can be used in conjunction with the count variable, for example {if item:count == item:total_results} will evaluate to TRUE for the last checkout item.

Updating Quantities

To update quantities of existing line items in the cart, you must template inputs on your checkout form, inside the {items} loop. Normally you would display this in a table layout.

The special {key} variable is available inside the {items} loop to use as an index for your input name. This is required, as it tells Store which line item you want to update the quantity of.

<table>
    {items}
        <tr>
            <td>{title}</td>
            <td>{price}</td>
            <td>
                <input name="items[{key}][item_qty]" value="{item_qty}" />
            </td>
            <td>{item_subtotal}</td>
        </tr>
    {/items}
</table>

Removing Items

To remove items from your cart, there are two options. You can either submit the item_qty field above as 0, or alternatively, you can use the remove_items input field. The remove_items input is useful if you want to display a checkbox:

<table>
    {items}
        <tr>
            <td>{title}</td>
            <td>
                <input type="checkbox" name="remove_items[{key}]" value="1" /> Remove {title}
            </td>
        </tr>
    {/items}
</table>

Always set the checkbox value to 1. If the customer doesn’t check the field, the value won’t be submitted, so it won’t cause any unexpected side effects on your checkout form.

You could also template the remove_items input as a form submit button, using the same name.

Adjustments Loop

Loop through the order adjustments. Adjustments are extra line items on the order which are not products (e.g. discounts, shipping charges, and taxes).

{adjustments}
    <tr>
        <td>{adjustment:name}</td>
        <td>{adjustment:amount}</td>
    </tr>
{/adjustments}

Inside the {adjustments} loop, you can use the following variables:

adjustment:name

The name of the adjustment (either the shipping method, tax name, or discount name).

adjustment:type

The adjustment type. This can be used as a conditional. It will normally be one of shipping, handling, discount or tax.

adjustment:rate

The adjustment rate. This currently only applies to taxes, and will return a decimal (for example, 0.15 if the tax rate is 15%).

adjustment:percent

The adjustment percent. This currently only applies to taxes, and will return a percent equivalent of the {adjustment:rate} variable.

adjustment:amount

The adjustment amount. This will be a positive or negative currency value.

adjustment:taxable

Returns TRUE if the adjustment is taxable. Generally only shipping and handling adjustments are taxable, but taxes are not applied to discounts or other taxes.

adjustment:included

Returns TRUE if the adjustment is included in the order total. This will be true for taxes which have been configured as “included in price”.

If an adjustment is included, it will not contribute to the order total, and is only displayed for informational purposes. For example, if a tax is included in the existing order item totals, then it must be displayed during checkout, but is not added on top of the existing item totals.

adjustment:count

A simple count variable, which will return 1 for the first adjustment, 2 for the second adjustment, etc.

adjustment:total_results

Returns the total number of adjustments in the order. May be used in conjunction with the count variable, for example {if adjustment:count == adjustment:total_results} will evaluate to TRUE for the last order adjustment.

Order Details

order_qty

The total number of items in the cart.

order_subtotal

The total of all items in the cart.

order_shipping

The total shipping charges.

order_shipping_discount

The discount applicable to shipping charges.

order_shipping_tax

The tax applicable to shipping charges.

order_shipping_total

The shipping total, including discounts and tax.

order_handling

The total handling charges.

order_handling_tax

The tax applicable to handling charges.

order_handling_total

The handling total, including tax.

order_discount

The total discount given by any applicable promo codes.

order_you_save

The total amount saved by sale pricing in the order.

order_tax

The total tax applicable to this order.

order_items_total

The total of all items in the cart.

order_adjustments_total

The total of all adjustments in the cart (excluding adjustments which are marked as “included”, which do not contribute to the order total).

order_total

The final order total, including all shipping, discounts and taxes.

order_email

The email address for this order (required).

accept_terms

If you require your customers to accept terms & conditions before placing an order, you can use this checkbox. Simply include it on any page of the checkout, like so:

<input type="hidden" name="accept_terms" value="0">
<input type="checkbox" name="accept_terms" value="1" {accept_terms_checked} >

Or more simply:

{field:accept_terms} <label for="accept_terms">I accept the terms & conditions</label>

The hidden field is required and must be placed before the checkbox, because per the html specifications, if a checkbox is unticked then nothing is submitted (and Store wouldn’t be able to tell whether the checkbox existed on your page in the first place).

If you don’t want the checkbox to be automatically checked when customers click the back button, simply template it yourself, without using the {accept_terms_checked} helper.

Billing Details

All billing details are stored in the cart, and you can submit them using standard html inputs.

To display a simple text/drop-down input where appropriate, use the following code:

{field:billing_name}
{field:billing_country}

To customize your inputs, you can simply template them as regular html inputs:

<input type="text" name="billing_name" value="{billing_name}" />

The following fields are available:

billing_first_name

The billing first name.

billing_last_name

The billing last name.

billing_name

A combination of the billing first and last names. {billing_name} is equivalent to typing {billing_first_name} {billing_last_name}. If a field named billing_name is submitted, it will be automatically split into separate first and last names after the first space.

billing_address1

The first line of the billing address.

billing_address2

The second line of the billing address (usually this field is optional).

billing_city

The third line of the billing address (usually used for the city).

billing_state

The code of the currently selected state.

billing_state_name

The name of the currently selected state.

billing_state_options

Generates a list of <option> elements to put inside your select tag. For example:

<select name="billing_state">
    {billing_state_options}
</select>

billing_country

The two digit country code.

billing_country_name

The full country name.

billing_country_options

Generates a list of <option> elements to put inside your select tag. For example:

<select name="billing_country">
    {billing_country_options}
</select>

billing_postcode

billing_phone

billing_company

Shipping Details

All shipping details fields mirror the billing details. You can display and submit them in the same way.

shipping_first_name

shipping_last_name

shipping_name

shipping_address1

shipping_address2

shipping_city

shipping_state

shipping_state_name

shipping_state_options

shipping_country

shipping_country_name

shipping_country_options

shipping_postcode

shipping_phone

shipping_company

Shipping Same As Billing

Most order processes will have a “Shipping same as Billing” checkbox. Using these fields, you can copy the billing details to the shipping details, or vice versa.

To display a simple “Shipping same as Billing” checkbox, use the following code:

<label for="shipping_same_as_billing">
  {field:shipping_same_as_billing} Same as Billing Details
</label>

If you want to customize the checkbox, you can template it yourself:

<label for="shipping_same_as_billing">
  <input type="hidden" name="shipping_same_as_billing" value="0" />
  <input type="checkbox" id="shipping_same_as_billing" name="shipping_same_as_billing" value="1" {shipping_same_as_billing_checked} />
  Same as Billing Details
</label>

The hidden field must be placed before the checkbox, so that if it is unchecked, “0” will be submitted.

Usually you would combine this checkbox with some simple javascript to hide the shipping details when checked:

<h3>Shipping Details</h3>

<label for="shipping_same_as_billing">
  {field:shipping_same_as_billing} Same as Billing Details
</label>

<div id="shipping_details_drawer">
    <!-- shipping details here -->
</div>

<script type="text/javascript">
$(function() {
    // handle the checkbox change event
    $('#shipping_same_as_billing').change(function() {
        if (this.checked) {
            $('#shipping_details_drawer').slideUp();
        } else {
            $('#shipping_details_drawer').slideDown();
        }
    });
    // hide on page load if already checked
    if ($('#shipping_same_as_billing').is(':checked')) {
        $('#shipping_details_drawer').hide();
    }
});
</script>

if shipping_same_as_billing

True if the current cart has the “shipping address same as billing address” option applied.

shipping_same_as_billing_checked

Shorthand for {if shipping_same_as_billing}checked="checked"{/if}

if billing_same_as_shipping

True if the current cart has the “billing address same as shipping address” option applied.

billing_same_as_shipping_checked

Shorthand for {if billing_same_as_shipping}checked="checked"{/if}

Shipping Methods

Shipping methods are specified by ID (found in the Store Settings page). You can template the shipping method as a drop-down or hidden fields in your template.

To display a simple shipping method drop-down, use the following code:

{field:shipping_method}

To display a custom shipping method drop-down, simply submit the shipping_method field along with your form:

<select name="shipping_method">
    <option value="">Select shipping method...</option>
    {shipping_method_options}
</select>

error:shipping_method

If the shipping plugin returned an error, you can use this variable to display it inline.

shipping_method_id

The ID of the currently selected shipping method.

shipping_method_name

The name of the currently selected shipping method.

shipping_method_class

The class of this shipping method (if calculated by an extension).

shipping_method_options

A helper variable to display all available shipping methods as HTML <option> elements.

shipping_methods Variable Pair

Loop through the available shipping methods (useful if you want to display something other than a select menu). Inside the loop, the following variables are available:

  • {method_id} - The shipping method ID.
  • {method_title} - The shipping method title.
  • {method_price} - The price for this shipping method, assuming the current user location. This variable is only available for the Default Shipping Plugin (other shipping plugins which would require a server-side query to display the price).
  • {if method_selected} - True if the current shipping method is selected.

Payment Methods

To give the user a choice between payment methods, you can either use the payment_method="" parameter, or submit a payment_method field on the last page of your checkout.

All payment methods must be configured in the settings. Orders must have a valid payment method before they can be submitted. If payment fails, the customer will be returned to the current page so that they may try again.

For more information about supported payment gateways, and which fields they require, see Payment Gateways.

To display a simple payment method drop-down, use the following code:

{field:payment_method}

To customize your payment method options, simply submit a payment_method parameter with your form:

How would you like to pay for your order?
<label><input type="radio" name="payment_method" value="manual"> Cheque / Bank Deposit</label>
<label><input type="radio" name="payment_method" value="paypal"> Paypal</label>
<label><input type="radio" name="payment_method" value="authorize_net"> Credit Card</label>

<!-- optionally you could use javascript to display a credit card form here when necessary -->

payment_method

Displays the short name of the currently selected payment method. This is useful in conditional statements.

payment_method_name

Displays the full name of the currently selected payment method.

error:payment_method

If the payment gateway returns an error, you can use this variable to display it inline.

Credit Card Details

Some payment gateways require you to submit the credit card details directly, rather than redirecting the user to a secure payment page. For these gateways, you will need to template additional inputs. You will also need to ensure that your web server is correctly set up with an SSL certificate, as credit card details must always be submitted over a secure connection.

All inputs names should be in the format payment[field_name]. For example:

<input type="text" name="payment[card_no]" value="" />

The exact fields required depends on the particular gateway. All gateways require the following fields:

card_no

The credit card number.

card_name

The credit card holder’s name.

exp_month

This should be submitted as 2 digis (e.g. “04”).

exp_year

This should be submitted as 4 digits (e.g. “2011”)

csc

The card security code (also known as the CVC or CVV)

The exp_month and exp_year fields are usually templated as select menus. To help with this, the {exp_month_options} and {exp_year_options} variables are available to you:

<select name="payment[exp_month]">
    <option value=""></option>
    {exp_month_options}
</select>
<select name="payment[exp_year]">
    <option value=""></option>
    {exp_year_options}
</select>

This will automatically generate a list of HTML option elements, based on the current date.

Tax Rates

Tax Rates are configured under Settings » Tax Rates. The tax rate is decided based on the shipping state and country.

In general, you can display the tax applicable to any price by appending _tax to the variable.

tax_name

The tax name as defined in the Settings.

tax_rate

The tax rate as a decimal (e.g. “0.15”).

tax_percent

The tax rate as a percentage (e.g. “15”).

if tax_shipping

True if the current tax rate is applied to shipping costs.

item_tax

The tax applicable to an individual order item. Must be used inside the {items} loop.

order_subtotal_tax

The tax applicable to your order items.

order_shipping_tax

The tax applicable to your shipping charges.

order_discount_tax

The tax discounted by any promo codes.

order_tax

The total order tax

Discounts / Promo Codes

To display a simple input for customers to enter a promo code, use the following code:

{field:promo_code}

If you want to customize the input, simply submit a promo_code field with your checkout form:

<input type="text" name="promo_code" value="{promo_code}" />

Only one promo code may be entered per order. To remove promo codes from the cart, you can either submit a blank promo_code field, or use a checkbox or button to submit a remove_promo_code field:

<label>
    <input type="checkbox" name="remove_promo_code" value="1" /> Remove Promo Code
</label>

<input type="submit" name="remove_promo_code" value="Remove Promo Code" />

promo_code

The promo code currently associated with this cart.

discount:id

The id of the active discount

discount:name

The name of the active discount

discount:code

The promo code of the active discount

discount:base_discount

The base discount of the active discount

discount:start_date

The start date of the active discount

discount:end_date

The end date of the active discount

discount:free_shipping

True if the current discount triggers free shipping for the order.

order_discount

The total discount value applied to this order.

Registering Members

Most stores will allow anonymous orders. However, Store provides a simple way for members to create an account during checkout. To enable member registration, you can either use the register_member="" parameter, or submit a the register_member field. To display a register member checkbox field, use the following code:

{field:register_member}

Member accounts will be created based on the order_email, and the email address must not already be used for a member account. After creating the member account, any existing orders tied to that email address will be assigned to the new member.

Member accounts will only be created if a password fields is submitted. In addition, the username and screen_name fields are optional. For example:

{field:register_member} <label for="register_member">Register Member Account?</label>

<!-- These fields are optional -->
<div class="toggle">
  <div>
    <label for="password">Password</label>
    {field:password}
  </div>

  <div>
    <label for="password_confirm">Confirm Password</label>
    {field:password_confirm}
  </div>

  <div>
    <label for="username">Username</label>
    {field:username}
  </div>

  <div>
    <label for="screen_name">Screen Name</label>
    {field:screen_name}
  </div>
</div>

register_member

TRUE if the register member option is enabled for the current cart.

password

This field can be submitted to set a password for the new member account.

password_confirm

This field can be submitted to confirm the customer typed their password correctly.

username

The username for the new member account. This will default to the value of the order_email field, and must be unique.

screen_name

The screen name for the new member account. This will default to the value of the order_email field.

Custom Order Fields

Orders can have up to 9 custom fields associated with them. As with other order fields, you can submit them using the field helper:

{field:order_custom1}

You may also template them as regular form inputs. You can give these fields a custom name under Settings » Order Fields, which will appear on the Order Details page in the control panel.

order_custom1

order_custom2

order_custom3

order_custom4

order_custom5

order_custom6

order_custom7

order_custom8

order_custom9

Inline Error Handling

The following error variables are available when you use the error_handling="inline" parameter:

error:billing_first_name

error:billing_last_name

error:billing_name

error:billing_address1

error:billing_address2

error:billing_city

error:billing_state

error:billing_country

error:billing_postcode

error:billing_phone

error:billing_company

error:shipping_first_name

error:shipping_last_name

error:shipping_name

error:shipping_address1

error:shipping_address2

error:shipping_city

error:shipping_state

error:shipping_country

error:shipping_postcode

error:shipping_phone

error:shipping_company

error:order_email

error:accept_terms

error:payment_method

error:shipping_method

error:promo_code

error:order_custom1

error:order_custom2

error:order_custom3

error:order_custom4

error:order_custom5

Submitting Orders

Different actions can be taken when your checkout form is submitted, depending on which button the customer clicks. You can have multiple buttons in your checkout form, which each perform different actions.

Update Cart

To update your cart totals, your submit button should be named update_cart. In addition, if your submit button name doesn’t match any of the other options below, it will be treated as an update cart button.

{exp:store:checkout}
    <input type="submit" name="update_cart" value="Update Cart" />
{exp:store:checkout}

Next Step

To move to the next step in your checkout, your submit button should be named “next”. For example, the following code will take the user to “checkout/confirm”:

{exp:store:checkout next="checkout/confirm"}
    <input type="submit" name="next" value="Confirm Order" />
{exp:store:checkout}

Previous Step

To move to the previous step of your checkout, you should not use a button, as you do not want to submit and validate the current form. Just use a regular A element instead (which you can style like a button using CSS if you like):

{exp:store:checkout}
    <a href="{path='checkout/cart'}">Back</a>
{exp:store:checkout}

Continue Shopping

On the first page of your checkout, you may wish to have a “Continue Shopping” button, which takes the customer back to the most recent product they were viewing. For this, we provide the {previous_url} variable, which contains a URL linking to the most recent page the user viewed on your site:

{exp:store:checkout}
    <a href="{previous_url}">Continue Shopping</a>
{exp:store:checkout}

Empty Cart

To provide an empty cart function, simply submit your checkout using a button named empty_cart:

{exp:store:checkout}
    <input type="submit" name="empty_cart" value="Empty Cart" />
{exp:store:checkout}

Submit Cart

On the final page of your checkout, you want to submit the order. You can do this by naming your button either “submit” or “commit”:

{exp:store:checkout return="order/ORDER_HASH"}
    <input type="submit" name="submit" value="Place Order" />
{exp:store:checkout}

When the cart is submitted on the final page of your checkout, a valid payment method must be specified. If the payment is successful, the customer will be redirected to the URL specified in the return="" parameter. If payment is unsuccessful, the customer will be returned to the final page of your checkout, and the error can be displayed using the {error:payment_method} variable.