1

I'm finding a guest checkout flow in Commerce 3.4.14 insanely confusing, docs aren't much help. I'm using Craft Solo and Commerce Lite.

TL;DR

I realize the code below is probably too complex, so even an example of a guest checkout process in Commerce would be extremely helpful (how do docs not provide this?!). Requirements:

  1. 3 page checkout process Contact > Shipping > Payment
  2. Contact page has email, billing address, shipping address
  3. Shipping page has shipping method (looked up by region) and notes
  4. Payment page has Stripe payment, ideally paypal as well (but not absolutely required)
  5. No javascript. All php/forms submitted to commerce

Overview (if you're still here)

I don't want to register customers or manage accounts. I want a guest checkout where they can enter shipping address > billing address > pay (Stripe or Paypal). I'm trying to set this up without javascript/JSON responses as suggested here. I want to use forms commerce/cart/update-cart and commerce/payments/pay as much as possible to update the cart addresses and pay.

I keep losing the shipping address because my commerce/cart/update-cart creates a whole new shipping address or the billing address overrides it (research: 1, 2 and 3). I've tried adding <input type="hidden" name="shippingAddress[id]" value="{{cart.shippingAddress.id}}"/> suggested in those links, but I'm still losing my shipping address somewhere along the line no matter how I try it.

I know billingAddress overrides shippingAddress updates when they have the same id but I can't figure out how to control that without registering them as a customer. I couldn't get the code from this issue to work with my template flow.

With the current code I get a new address when I submit store/checkout/shipping that only has the shipping method data.

Current code

store/cart

{% set customer = craft.commerce.customers ? craft.commerce.customers.customer : null %}
{% set addresses = customer ? customer.addresses : null %}

<form method="POST" data-cart>
  {{ csrfInput() }}
  {{ actionInput('commerce/cart/update-cart') }}
  {{ hiddenInput('successMessage', 'Cart has been updated.'|hash) }}

  {% include '_partials/_cart-items' with {items: cart.lineItems} %}

  <div class="actions">
    <a href="/store" class="button actions__action">&larr; Back to Store</a>

    <button class="button actions__action"
      type="submit"
      name="redirect"
      value="{{ '/store/cart' | hash }}">Update Cart</button>
    <button class="button actions__action"
      type="submit"
      name="redirect"
      value="{{ '/store/checkout/contact' | hash }}">Checkout &rarr;</button>
  </div>
</form>

store/checkout/contact

{% set cart = craft.commerce.carts.cart %}
{% set address = cart.shippingAddress %}
{% set hasCountry = address and address.countryId %}
      <form method="post">
        {{ csrfInput() }}
        {{ actionInput('commerce/cart/update-cart') }}
        {{ redirectInput(hasCountry ? '/store/checkout/shipping' : '/store/checkout/contact') }}

        <fieldset>
          <legend>Shipping Address</legend>

          {% if not hasCountry %}
            <p>Please select the country that you want me to ship this order to.</p>
          {% endif %}

          {% include "_partials/_forms/_cartShippingFields" %}

        </fieldset>

        {% if hasCountry %}
          {% if address.id %}
            {# use shipping address id created when country was submitted #}
            {{ hiddenInput('shippingAddress[id]', address.id) }}
          {% endif %}
          <fieldset>
            <legend>Contact Info</legend>

            <label class="field">
              <span class="field__label">email:</span>

              <div class="field__inputs">
                <input
                  class="text-input"
                  name="email"
                  required
                  type="email"
                  value="{{ cart.email }}"
                />
              </div>

              <div class="field__errors">{{ cart.getErrors('email') | join }}</div>
            </label>
          </fieldset>
        {% endif %}

        <div class="actions">
          <a href="/store/cart" class="button actions__action">&larr; Back to Cart</a>

          <button type="submit" class="button actions__action">
            {% if hasCountry %}Shipping Method &rarr;{% else %}Set Country{% endif %}
          </button>
        </div>
      </form>

store/checkout/shipping

{% set cart = craft.commerce.carts.cart %}
{% set address = cart.shippingAddress %}
{% set hasCountry = address and address.countryId %}

      <form method="post">
        <input type="hidden" name="action" value="commerce/cart/update-cart" />
        {{ csrfInput() }}
        {{ redirectInput('/store/checkout/payment') }}
        {% if address.id %}
          {{ hiddenInput('shippingAddress[id]', address.id) }}
        {% endif %}

        <fieldset>
          <legend>Shipping Method</legend>

          {% for handle, method in cart.availableShippingMethodOptions %}
            {% set isCurrentSelection = handle == cart.shippingMethodHandle %}
            {% set formattedPrice = method.priceForOrder(cart)|currency(cart.currency) %}
            <label>
              <input type="radio"
                name="shippingMethodHandle"
                value="{{ handle }}"
                {{ isCurrentSelection ? ' checked' : '' }}
              />
              <strong>{{ method.name }}</strong> {{ formattedPrice }}
            </label>
          {% endfor %}
          
          <label>
            <input name="billingAddressSameAsShipping" type="checkbox" checked="" value="1" />
            My billing address is the same as my shipping address.
          </label>

          <legend>Order Notes</legend>

          <label class="field">
            <span class="field__label">Order Notes:</span>

            <div class="field__inputs">
              <textarea name="shippingAddress[notes]" cols="30" rows="4">{{ address ? address.notes : '' }}</textarea>
            </div>
          </label>
        </fieldset>

        <div class="actions">
          <a href="/store/checkout/contact" class="button actions__action">&larr; Back to Contact</a>

          <button type="submit" class="button actions__action">Payment &rarr;</button>
        </div>
      </form>

store/checkout/payment

{% set cart = craft.commerce.carts.cart %}
{% set address = cart.shippingAddress %}
     {# update the payment method and add billing address if needed #}
     <form method="post">
      {{ csrfInput() }}
      {{ actionInput('commerce/cart/update-cart') }}
      {{ hiddenInput('successMessage', 'Payment method has been updated.'|hash) }}
      {{ redirectInput('store/checkout/payment') }}
      {% if address.id %}
        {{ hiddenInput('shippingAddress[id]', address.id) }}
      {% endif %}
      {% if cart.billingAddress.id %}
        {{ hiddenInput('billingAddress[id]', address.id) }}
      {% endif %}

      <label for="gatewayId">Payment Method</label>
      <select name="gatewayId" id="gatewayId">
        {% for id,name in enabledGateways %}
          <option value="{{ id }}"{% if id == cart.gatewayId %} selected{% endif %}>
            {{- name -}}
          </option>
        {% endfor %}
      </select>

      {# check if they checked billing same as shipping #}
      {% if cart.billingAddress is null %}
        {% include "_partials/_forms/_cartBillingFields" %}
      {% endif %}

      <div class="actions">
        <button type="submit" class="button actions__action">
          Update payment details
        </button>
      </div>
    </form>
    
   {# submit the payment #}
   {% if cart.gatewayId|length and address|length and cart.billingAddress|length %}
    {% set gateway = craft.commerce.gateways.getGatewayById(cart.gatewayId) %}

      <form method="post">
        {{ csrfInput() }}
        {{ actionInput('commerce/payments/pay') }}
        {{ redirectInput('/commerce/customer/order?number={number}') }}
        {{ hiddenInput('cancelUrl', '/commerce/checkout/payment'|hash) }}
        {% if address.id %}
          {{ hiddenInput('shippingAddress[id]', address.id) }}
        {% endif %}
        {% if cart.billingAddress.id %}
          {{ hiddenInput('billingAddress[id]', address.id) }}
        {% endif %}

        {{ gateway.getPaymentFormHtml({})|raw }}

        <div class="actions">
          <a href="/store/checkout/shipping" class="button actions__action">&larr; Back to Shipping</a>

          <button type="submit" class="button actions__action">
            Pay {{ cart.totalPrice|commerceCurrency(cart.paymentCurrency,convert=true) }} &rarr;
          </button>
        </div>
      </form>

  {% endif %}

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.