components/checkout/.
1) Address input
Before the customer reaches this page, they must be logged in. In addition, the button that links to this page must contain a URL parameter so that the code for the first step is loaded.Template basket.htm
{{ if $wsBasket.items }}
...
{{ if $wsAccount.isLoggedIn or $wsCheckout.guestMail }}
<a href="{{= $wsViews.viewUrl('checkout.htm', {step: 1}) }}">Checkout</a>
{{ else }}
<a href="{{= $wsViews.viewUrl('account/login.htm', {checkout: true}) }}">Checkout</a>
{{ /if }}
...
{{ /if }}
Template login.htm
...
{{ include "components/account/login.htm" with $cTemplate = "login" }}
{{# redirect if login was successfull #}}
{{ if $wsAccount.isLoggedIn == true }}
{{ if $cCheckout == "true" }}
<meta http-equiv="refresh" content="0;url={{= $wsViews.viewUrl('checkout.htm', {step: 1}) }}">
{{ else }}
<meta http-equiv="refresh" content="0;url={{= $wsViews.viewUrl('account/overview.htm') }}">
{{ /if }}
{{ /if }}
...
www.example-shop.com/?wsvc=View&view=checkout.htm&step=1
Template checkout.htm
This template is already present in the shop and must be extended. We check for the URL parameter and use it to load the corresponding template.{{ block content_main }}
{{# get step parameter from URL #}}
{{ var $cStep = "" }}
{{ foreach $cParam in $wsViews.current.paramList }}
{{ if $cParam.name == "step" }}
{{ $cStep = $cParam.value }}
{{ /if }}
{{ /foreach }}
{{ if $cStep == "1" }}
{{ if $wsAccount.isLoggedIn or $wsCheckout.guestMail }}
Your address
{{ /if }}
{{ include "components/checkout/address.htm" }}
{{ elseif $cStep == "2" }}
Payment & shipping
{{ include "components/checkout/paymentDelivery.htm" }}
{{ elseif $cStep == "3"}}
Order overview
{{ include "components/checkout/orderOverview.htm" }}
{{ elseif $cStep == "4"}}
{{ include "components/checkout/confirm.htm" with $cStep = $cStep }}
{{ else }}
An error has occurred here. This is not a valid URL.
{{ /if }}
{{# Basket overview #}}
{{ include "components/checkout/basketOverview.htm" with $cStep = $cStep }}
{{ /block }}
...
{{ block scripts }}
<script defer>
$(document).on("change", "input[name='accountType']", function(){
$("#wsFormLoginMethod").submit();
});
$(document).on("change", "#wsShippingAddressCheck", function() {
if ($(this).prop("checked")) {
$("#wsFormUseSameShippingAddress").submit();
} else {
$("#wsFormUseDifferentShippingAddress").submit();
}
});
</script>
{{ /block }}

Template address.htm
A new template is created for this. not yet tested...
{{ var $cCheckoutStep2 = false }}
{{# content for new user #}}
{{ if $wsCheckout.accountType == "new" and not $wsAccount.isLoggedIn }}
New customer login
Please enter an email and any password to create a customer account.
{{ include "components/account/register.htm" with $cTemplate = "checkout" }}
{{# content for known user #}}
{{ elseif $wsCheckout.accountType == "registered" and not $wsAccount.isLoggedIn }}
Existing customer login
Please enter your email and password to log in.
{{ include "components/account/login.htm" with $cTemplate = "checkout" }}
{{# content for guest user #}}
{{ elseif $wsCheckout.accountType == "guest" and not $wsAccount.isLoggedIn }}
{{ var $cActionCheckoutSetGuestEmail = $wsActions.create("CheckoutSetGuestEmail") }}
Guest order
<form id="wsFormCheckoutSetGuestMail" action="{{= $wsViews.current.url() }}" method="post" ws-ajax-form>
<input type="hidden" name="wsReplaceIds" value="wsCheckoutContent">
<input type="hidden" name="wsact" value="{{= $cActionCheckoutSetGuestEmail.id }}">
<input type="hidden" name="wscsrf" value="{{= $cActionCheckoutSetGuestEmail.csrf }}">
<input type="hidden" name="wstarget" value="{{= $wsViews.current.url() }}">
<div class="form-floating mb-3">
<input type="text" id="guestEmailInput" name="guestEmail" value="{{ if $wsCheckout.guestMail }}{{= $wsCheckout.guestMail }}{{ else }}{{= $cActionCheckoutSetGuestEmail.params.guestEmail | ifNull('') }}{{ /if }}" class="form-control{{ if $cActionCheckoutSetGuestEmail.errorsByField.guestEmail }} is-invalid{{ /if }}" autocomplete="email" placeholder="Email *">
<label>Email *</label>
{{ include "components/errorFeedback.htm" with $cAction = $cActionCheckoutSetGuestEmail, $cField = "guestEmail" }}
</div>
<button type="submit">Apply change</button>
</form>
{{ /if }}
{{ if $wsCheckout.guestMail }}
{{ $cCheckoutStep2 = false }}
{{# guest order gets address automatically from backend #}}
{{ var $cAddress = $wsAccount.loadAddress($wsCheckout.selectedBillAddress) }}
{{ var $cActionAddressUpdate = $wsActions.create("AddressUpdate", {address: $cAddress}, tag = "billAddress") }}
<form id="wsFormAddressUpdate" action="{{= $wsViews.current.url() }}" method="post" ws-ajax-form>
<input type="hidden" name="wsReplaceIds" value="wsCheckoutContent">
<input type="hidden" name="wsact" value="{{= $cActionAddressUpdate.id }}">
<input type="hidden" name="wscsrf" value="{{= $cActionAddressUpdate.csrf }}">
<input type="hidden" name="wstarget" value="{{= $wsViews.current.url() }}">
{{# addressId is necessary for guest order #}}
<input type="hidden" name="addressId" value="{{= $cAddress.id }}">
{{ include "components/errorAlert.htm" with $cAction = $cActionAddressUpdate }}
Fields marked with a * are mandatory and must be filled in.
{{ include "components/account/addressInputs.htm" with $cAction = $cActionAddressUpdate }}
<button type="submit">Save address</button>
</form>
{{= $wsCheckout | json }}
{{ if $wsCheckout.isValidBillAddress($wsCheckout.selectedBillAddress) }}
Valid address stored
{{ else }}
No valid address stored
{{ /if }}
{{ /if }}
{{ if $wsAccount.isLoggedIn }}
{{# show select options for bill address #}}
{{ if $wsAccount.addresses | len > 0 }}
{{ var $cAddress = $wsAccount.loadAddress($wsCheckout.selectedBillAddress) }}
{{ var $cCheckoutBillAddressSelect = $wsActions.create("CheckoutBillAddressSelect") }}
<form id="wsFormCheckoutBillAddressSelect" action="{{= $wsViews.current.url() }}" method="post" ws-ajax-form data-auto-submit-change>
<input type="hidden" name="wsReplaceIds" value="wsCheckoutContent">
<input type="hidden" name="wsact" value="{{= $cCheckoutBillAddressSelect.id }}">
<input type="hidden" name="wscsrf" value="{{= $cCheckoutBillAddressSelect.csrf }}">
<input type="hidden" name="wstarget" value="{{= $wsViews.current.url() }}">
<select name="addressId" class="form-select">
<option>Please select</option>
{{ foreach $cAddress in $wsAccount.addresses }}
<option value="{{= $cAddress.id }}"{{ if $cAddress.id == $wsCheckout.selectedBillAddress }} selected{{ /if }}>{{= $cSalutations[$cAddress.salutationCode] | ifNull("")}} {{= $cAddress.firstName}} {{= $cAddress.lastName}}, {{= $cAddress.street}}, {{= $cAddress.zip}} {{= $cAddress.city }}</option>
{{ /foreach }}
</select>
<a href="{{= $wsViews.viewUrl('account/newAddress.htm')}}">Add address</a>
</form>
{{ /if }}
{{ if $wsCheckout.isValidBillAddress($wsCheckout.selectedBillAddress) }}
{{ $cCheckoutStep2 = true }}
{{ var $cAddress = $wsAccount.loadAddress($wsCheckout.selectedBillAddress) }}
Valid address stored
Billing address
<a href="{{= $wsViews.viewUrl('account/changeAddress.htm', {addressId: $address.id}) }}">Edit address</a>
{{ include "components/account/addressSelected.htm" with $cAddress = $cAddress }}
<input id="wsShippingAddressCheck" type="checkbox"{{ if not $wsCheckout.useAlternativeShippingAddress }} checked{{ /if }}>
<label for="wsShippingAddressCheck">Deliver to this address</label>
{{ else }}
No valid address stored
{{ /if }}
{{ /if }}
{{ if $cCheckoutStep2 == true }}
<a href="{{= $wsViews.viewUrl('checkout.htm', {step: 2}) }}">Continue to payment and shipping</a>
<a href="{{= $wsViews.viewUrl('basket.htm') }}">Back to the basket</a>
{{ /if }}
Template basketOverview.htm
Create a new template checkout/basketOverview.htm. This template is used to display the basket during the checkout process.{{ input $cStep }}
Your order
{{ include "components/product/productTable.htm" with $cTemplate = "checkoutConfirm" }}
<table>
<tbody>
<tr>
<td>Shipping costs</td>
<td>{{= $wsCheckout.sum.shippingCost | currency }}</td>
</tr>
<tr>
<td>VAT included</td>
<td>{{= $wsCheckout.sum.totalTax | currency }}</td>
</tr>
<tr>
<th>Total</th>
<th>{{= $wsBasket.total | currency }}</th>
</tr>
</tbody>
</table>
{{ if $cStep == "3" }}
{{ if $wsAccount.isLoggedIn or $wsCheckout.guestMail }}
{{ var $cActionCheckoutConfirm2 = $wsActions.create("CheckoutConfirm") }}
{{ var $cActionSetFreeFields2 = $wsActions.create("CheckoutSetFreeFields") }}
<form id="wsFormFreeFields2" method="post" action="{{= $wsViews.current.url() }}" ws-ajax-form data-auto-submit-change>
<input type="hidden" name="wsReplaceIds" value="wsCheckoutContent">
<input type="hidden" name="wsact" value="{{= $cActionSetFreeFields2.id }}">
<input type="hidden" name="wscsrf" value="{{= $cActionSetFreeFields2.csrf }}">
<input type="hidden" name="wstarget" value="{{= $wsViews.current.url() }}">
{{ include "components/errorAlert.htm" with $cAction = $cActionSetFreeFields2 }}
{{# show checkbox for GTC #}}
{{ foreach $cField in $wsCheckout.freeFields }}
{{ if $cField.id == "agb" }}
<input id="wsAcceptTermsAndConditionsInput-2" name="freeFields.{{= $cField.id }}.value" type="{{= $cField.type }}" {{ if $cField.checked }} checked{{ /if }}>
<label for="wsAcceptTermsAndConditionsInput-2">Yes, I accept your terms and conditions and have taken note of my right of withdrawal.</label>
{{ /if }}
{{ /foreach }}
</form>
<form method="post" action="{{= $wsViews.current.url() }}">
<input type="hidden" name="wsact" value="{{= $cActionCheckoutConfirm2.id }}">
<input type="hidden" name="wscsrf" value="{{= $cActionCheckoutConfirm2.csrf }}">
<input type="hidden" name="wstarget" value="{{= $wsViews.viewUrl('checkout.htm', {step: 4}) }}">
{{ include "components/errorAlert.htm" with $cAction = $cActionCheckoutConfirm2 }}
<button type="submit">Submit order</button>
</form>
{{ /if }}
{{ /if }}
2) Choose payment method & shipping method
In this step, the customer can choose the payment/shipping options.Template paymentDelivery.htm
Choose payment method...
{{ var $cActionCheckoutPaymentUpdate = $wsActions.create("CheckoutPaymentUpdate") }}
<form id="wsFormCheckoutPaymentUpdate" method="post" action="{{= $wsViews.current.url() }}" ws-ajax-form data-auto-submit-change>
<input type="hidden" name="wsReplaceIds" value="wsCheckoutContent">
<input type="hidden" name="wsact" value="{{= $cActionCheckoutPaymentUpdate.id }}">
<input type="hidden" name="wscsrf" value="{{= $cActionCheckoutPaymentUpdate.csrf }}">
<input type="hidden" name="wstarget" value="{{= $wsViews.current.url() }}">
<input style="display: none;" type="radio" class="resetter" name="paymentId" value="">
{{ include "components/errorAlert.htm" with $cAction = $cActionCheckoutPaymentUpdate }}
{{ if $wsCheckout.problems.payment or $cActionCheckoutPaymentUpdate.error }}
An error has occurred. Please try again. Please choose a different payment method to continue with the order.
{{ /if }}
{{ foreach $cPayment in $wsConfig.payments }}
<input class="form-check-input" type="radio" name="paymentId" id="{{= $cPayment.id }}" value="{{= $cPayment.id }}"{{ if $wsCheckout.selectedPayment == $cPayment.id }} checked{{ /if }}{{ if not $wsCheckout.isValidPayment($cPayment.id) }} disabled{{ /if }}>
<label for="{{= $cPayment.id }}">{{= $cPayment.name }}</label>
{{ /foreach }}
</form>
...
...
{{ var $cActionCheckoutShippingMethodUpdate = $wsActions.create("CheckoutShippingMethodUpdate") }}
<form id="wsFormCheckoutShippingMethodUpdate" method="post" action="{{= $wsViews.current.url() }}" ws-ajax-form data-auto-submit-change>
<input type="hidden" name="wsReplaceIds" value="wsCheckoutContent">
<input type="hidden" name="wsact" value="{{= $cActionCheckoutShippingMethodUpdate.id }}">
<input type="hidden" name="wscsrf" value="{{= $cActionCheckoutShippingMethodUpdate.csrf }}">
<input type="hidden" name="wstarget" value="{{= $wsViews.current.url() }}">
{{ include "components/errorAlert.htm" with $cAction = $cActionCheckoutPaymentUpdate }}
{{ if $wsCheckout.problems.shippingMethod or $cActionCheckoutShippingMethodUpdate.error }}
An error has occurred. Please try again. Please choose a different shipping method to continue with the order.
{{ /if }}
{{ foreach $cShipping in $wsConfig.shippingMethods }}
<input class="form-check-input" type="radio" name="shippingMethodId" id="{{= $cShipping.id }}" value="{{= $cShipping.id }}"{{ if $wsCheckout.selectedShippingMethod == $cShipping.id }} checked{{ /if }}{{ if not $wsCheckout.isValidShippingMethod($cShipping.id) }} disabled{{ /if }}>
<label for="{{= $cShipping.id }}">
{{= $cShipping.name }}{{ if $cShipping.cost }}({{= $cShipping.cost | currency }}){{ /if }}
</label>
{{ /foreach }}
</form>
...
...
<form id="wsFormCheckoutPaymentUpdate" method="post" action="{{= $wsViews.current.url() }}" ws-ajax-form data-auto-submit-change>
...
</form>
<form id="wsFormCheckoutShippingMethodUpdate" method="post" action="{{= $wsViews.current.url() }}" ws-ajax-form data-auto-submit-change>
...
</form>
{{ if $wsCheckout.selectedPayment and $wsCheckout.selectedShippingMethod }}
{{ $cCheckoutStep3 = true }}
{{ /if }}
{{ if $cCheckoutStep3 == true }}
<a href="{{= $wsViews.viewUrl('checkout.htm', {step: 3}) }}">Continue to order overview</a>
{{ /if }}
<a href="{{= $wsViews.viewUrl('checkout.htm', {step: 1}) }}">Back to address</a>
...
3) Order overview
On this page, the customer can check their information and basket and then submit the order.Template orderOverview.htm
{{ input $cStep }}
{{ var $cAddress = $wsAccount.loadAddress($wsCheckout.selectedBillAddress) }}
{{ var $cActionCheckoutConfirm = $wsActions.create("CheckoutConfirm") }}
{{ var $cActionSetFreeFields = $wsActions.create("CheckoutSetFreeFields") }}
Billing address
{{ if $cStep != "4" }}
<a href="{{= $wsViews.viewUrl('checkout.htm', {step: 1}) }}">Change billing address</a>
{{ /if }}
{{ include "components/account/addressSelected.htm" with $cAddress = $cAddress }}
Shipping address
{{ if $cStep != "4" }}
<a href="{{= $wsViews.viewUrl('checkout.htm', {step: 1}) }}">Change shipping address</a>
{{ /if }}
{{ if $wsCheckout.useAlternativeShippingAddress }}
{{ var $cShippingAddress = $wsAccount.loadAddress($wsCheckout.selectedShippingAddress) }}
{{ include "components/account/addressSelected.htm" with $cAddress = $cShippingAddress }}
{{ else }}
Same as billing address
{{ /if }}
Payment and shipping
{{ if $cStep != "4" }}
<a href="{{= $wsViews.viewUrl('checkout.htm', {step: 2}) }}">Change payment and shipping</a>
{{ /if }}
{{ foreach $cPayment in $wsConfig.payments }}
{{ if $wsCheckout.selectedPayment == $cPayment.id }}
Selected payment method: {{= $cPayment.name }}
{{ /if }}
{{ /foreach }}
{{ foreach $cShipping in $wsConfig.shippingMethods }}
{{ if $wsCheckout.selectedShippingMethod == $cShipping.id }}
Selected shipping method: {{= $cShipping.name }}
{{ /if }}
{{ /foreach }}
{{ if $cStep != "4" }}
<form id="wsFormFreeFields1" method="post" action="{{= $wsViews.current.url() }}" ws-ajax-form data-auto-submit-change>
<input type="hidden" name="wsReplaceIds" value="wsCheckoutContent">
<input type="hidden" name="wsact" value="{{= $cActionSetFreeFields.id }}">
<input type="hidden" name="wscsrf" value="{{= $cActionSetFreeFields.csrf }}">
<input type="hidden" name="wstarget" value="{{= $wsViews.current.url() }}">
{{ include "components/errorAlert.htm" with $cAction = $cActionSetFreeFields }}
{{# show comment textarea #}}
{{ foreach $cField in $wsCheckout.freeFields }}
{{ if $cField.id == "comment" }}
Wishes, comments, suggestions
<textarea name="freeFields.{{= $cField.id }}.value" rows="3" value="{{= $cField.text | ifNull($cField.default) }}"></textarea>
{{ /if }}
{{ /foreach }}
{{# show checkbox for GTC #}}
{{ foreach $cField in $wsCheckout.freeFields }}
{{ if $cField.id == "agb" }}
<input id="wsAcceptTermsAndConditionsInput-1" name="freeFields.{{= $cField.id }}.value" type="{{= $cField.type }}">
<label for="wsAcceptTermsAndConditionsInput-1">Yes, I accept your terms and conditions and have taken note of my right of withdrawal.</label>
{{ /if }}
{{ /foreach }}
</form>
<form method="post" action="{{= $wsViews.current.url() }}">
<input type="hidden" name="wsact" value="{{= $cActionCheckoutConfirm.id }}">
<input type="hidden" name="wscsrf" value="{{= $cActionCheckoutConfirm.csrf }}">
<input type="hidden" name="wstarget" value="{{= $wsViews.viewUrl('checkout.htm', {step: 4}) }}">
{{ include "components/errorAlert.htm" with $cAction = $cActionCheckoutConfirm }}
<button type="submit">Submit order</button>
</form>
{{ /if }}
{{ if $cStep == "4" }}
{{ foreach $cFreeField in $wsCheckout.freeFields }}
{{ if $cFreeField.id == "comment" and $cFreeField.text }}
Comment: {{= $cFreeField.text | ifNull("") }}
{{ /if }}
{{ /foreach }}
{{ /if }}
4) Order confirmation
Template confirm.htm
{{ input $cStep }}
{{ var $cCurrentAction = $wsActions.current.name }}
{{ if not $cCurrentAction == null }}
Thank you for your order
A confirmation email for your order will be sent to you in a few minutes.
We wish you a lot of fun with your order and would be delighted to welcome you back to our shop soon.
Please also check your spam folder if necessary, or contact our customer service.
Order number: {{= $wsCheckout.orderId }}
{{ var $cOrder = $wsOrderHistory.load($wsCheckout.orderId) }}
Order date: {{= $cOrder.general.dateTime | dateFmt("%d.%m.%Y") }} at {{= $cOrder.general.dateTime | dateFmt("%H:%M") }}
{{ if not $wsAccount.isLoggedIn }}
Would you like to register after all?
{{ var $cGuestRegister = $wsActions.create("GuestRegister") }}
{{ if $cGuestRegister.success }}
Account successfully created.
{{ /if }}
{{ foreach $cError in $cGuestRegister.errors }}
{{ if $cError.text }}
{{= $cError.text }}
{{ else }}
{{= $cError.code }}
{{ /if }}
{{ if $cError.code == "passwordCheckFailed" }}
{{ if $cError.subCode == "minlen" }}
Minimum length: {{= $cError.details.len }} characters
{{ /if }}
{{ if $cError.subCode == "maxlen" }}
Maximum length: {{= $cError.details.len }} characters
{{ /if }}
{{ /if }}
{{ /foreach }}
{{ if not $cGuestRegister.success }}
<form action="{{= $wsViews.current.url() }}" method="post">
<input type="hidden" name="wscsrf" value="{{= $cGuestRegister.csrf }}">
<input type="hidden" name="wsact" value="{{= $cGuestRegister.id }}">
<input type="hidden" name="wstarget" value="{{= $wsViews.current.url() }}">
<input type="email" name="guestMail" value="{{= $wsCheckout.guestMail }}" placeholder="Your used email address" readonly>
<label>Your used email address</label>
<input type="password" name="password" placeholder="Password">
<label>Password</label>
<input type="password" name="passwordRepeat" placeholder="Repeat password">
<label>Repeat password</label>
<button type="submit">Register</button>
</form>
{{ /if }}
{{ /if }}
{{ include "components/checkout/orderOverview.htm" with $cStep = $cStep }}
{{ else }}
Oops... an error has occurred.
{{ /if }}
