{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.
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}
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.
Set an id attribute on the generated HTML form.
Set a name attribute on the generated HTML form.
Set a class attribute on the generated HTML form.
Specify arbitrary attributes on the generated HTML form. For example:
html:parsley-validate="true"
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.
Create a member account for this user when the order is complete.
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.
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?
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]"
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.
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>'
When set to yes
, this disables any automatic javascript output by the tag.
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:
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}
The product SKU.
The product entry title.
The product entry URL title.
The applicable price of the product, (equal to the sale price if the product is on sale, otherwise the regular price).
The regular price of the product, regardless of whether it is currently on sale.
The sale price of the product, regardless of whether it is currently on sale.
True if the product is currently on sale.
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.
True if the product has free shipping selected.
The length of the product.
The width of the product.
The height of the product.
The weight of the product.
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.The dollar discount value if the product is on sale.
The percentage discount value if the product is on sale, rounded to the nearest whole number.
The number of this product the user has in their cart.
The item price multiplied by the item quantity.
The total discounts applied to this item.
The total tax applicable to this item.
The item total, including discounts and tax.
The row number of this item (similar to the channel entries tag’s {count}
variable).
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.
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>
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.
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:
The name of the adjustment (either the shipping method, tax name, or discount name).
The adjustment type. This can be used as a conditional. It will normally be one of
shipping
, handling
, discount
or tax
.
The adjustment rate. This currently only applies to taxes, and will return a decimal
(for example, 0.15
if the tax rate is 15%).
The adjustment percent. This currently only applies to taxes, and will return a percent
equivalent of the {adjustment:rate}
variable.
The adjustment amount. This will be a positive or negative currency value.
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.
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.
A simple count variable, which will return 1 for the first adjustment, 2 for the second adjustment, etc.
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.
The total number of items in the cart.
The total of all items in the cart.
The total shipping charges.
The discount applicable to shipping charges.
The tax applicable to shipping charges.
The shipping total, including discounts and tax.
The total handling charges.
The tax applicable to handling charges.
The handling total, including tax.
The total discount given by any applicable promo codes.
The total amount saved by sale pricing in the order.
The total tax applicable to this order.
The total of all items in the cart.
The total of all adjustments in the cart (excluding adjustments which are marked as “included”, which do not contribute to the order total).
The final order total, including all shipping, discounts and taxes.
The email address for this order (required).
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.
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:
The billing first name.
The billing last 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.
The first line of the billing address.
The second line of the billing address (usually this field is optional).
The third line of the billing address (usually used for the city).
The code of the currently selected state.
The name of the currently selected state.
Generates a list of <option>
elements to put inside your select tag.
For example:
<select name="billing_state">
{billing_state_options}
</select>
The two digit country code.
The full country name.
Generates a list of <option>
elements to put inside your select tag.
For example:
<select name="billing_country">
{billing_country_options}
</select>
All shipping details fields mirror the billing details. You can display and submit them in the same way.
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>
True if the current cart has the “shipping address same as billing address” option applied.
Shorthand for {if shipping_same_as_billing}checked="checked"{/if}
True if the current cart has the “billing address same as shipping address” option applied.
Shorthand for {if billing_same_as_shipping}checked="checked"{/if}
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>
If the shipping plugin returned an error, you can use this variable to display it inline.
The ID of the currently selected shipping method.
The name of the currently selected shipping method.
The class of this shipping method (if calculated by an extension).
A helper variable to display all available shipping methods as HTML <option>
elements.
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.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 -->
Displays the short name of the currently selected payment method. This is useful in conditional statements.
Displays the full name of the currently selected payment method.
If the payment gateway returns an error, you can use this variable to display it inline.
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:
The credit card number.
The credit card holder’s name.
This should be submitted as 2 digis (e.g. “04”).
This should be submitted as 4 digits (e.g. “2011”)
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 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.
The tax name as defined in the Settings.
The tax rate as a decimal (e.g. “0.15”).
The tax rate as a percentage (e.g. “15”).
True if the current tax rate is applied to shipping costs.
The tax applicable to an individual order item. Must be used inside the {items} loop.
The tax applicable to your order items.
The tax applicable to your shipping charges.
The tax discounted by any promo codes.
The total order tax
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" />
The promo code currently associated with this cart.
The id of the active discount
The name of the active discount
The promo code of the active discount
The base discount of the active discount
The start date of the active discount
The end date of the active discount
True if the current discount triggers free shipping for the order.
The total discount value applied to this order.
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>
TRUE if the register member option is enabled for the current cart.
This field can be submitted to set a password for the new member account.
This field can be submitted to confirm the customer typed their password correctly.
The username for the new member account. This will default to the value
of the order_email
field, and must be unique.
The screen name for the new member account. This will default to the
value of the order_email
field.
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.
The following error variables are available when you use the
error_handling="inline"
parameter:
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.
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}
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}
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}
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}
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}
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.