PayPal Express Checkout Setup

This page outlines how to set up your LemonStand store to accept payments using PayPal Express.

What We'll Cover

Adding PayPal Express Checkout as a Payment Method

Please refer to the following docs before proceeding:

  • Payment Methods, for an overview of the general parameters available to a payment method.
  • Checkout Page, for an overview of how the Checkout page is implemented.
  • CMS Actions, for an overview of what CMS actions are and how they work.

In addition, you'll need the following credentials from PayPal:

  • A PayPal Account API Username
  • A PayPal Account API Password
  • A PayPal Account API Signature.
  • A PayPal Account Merchant ID.

1. Click the plus button on the Business Settings > Payment Methods page to add a new payment method.

2. Select PayPal Express Checkout from the list of payment methods, and click the Continue button.



3. Open the Configuration tab, and enter the credentials listed above into their respective fields.

PayPal-Express-Checkout-2016-03-03-14-22

4. Toggle any of the additional settings to satisfy your use case.

5. You, optionally, also configure a Logo Image URL from the PayPal Payment Page Configuration tab as well as the size of the PayPal Express Checkout button generated from the PayPal Button Configuration tab.

  • Logo Image URL
  • PayPal Button Configuration
Payment-Methods-PayPal-Express-Checkout-

6. Click the Save button. You will now be accepting payments via PayPal Express Checkout!


Theme Configuration for PayPal Express Checkout CMS Action

A new CMS action has been introduced to facilitate the PayPal Express Checkout checkout process, payPalExpress:checkout. It's a slightly modified implementation of the shop:checkout action, with one less step.

Additionally, when the PayPal Express Checkout payment method is enabled, the following variables will be injected into the following pages/partials:

  • payPalExpressCheckoutButton, into the cart page.

To build out the storefront to accommodate the Express Checkout flow, we recommend adding pages and partials specific to the payPalExpress:checkout CMS action, following, generally the same patterns that our themes utilize in their traditional checkout pages (excluding the first billing_info/shipping_info steps), but with swapped values for partial and CMS action references.

Let's use the Zest theme as an example. Adding the following pages and partials would allow you to step through an PayPal Express Checkout flow:

  • page - page-paypalcheckout.htm, representative of a typical checkout page. This page will sit on top of the payPalExpress:checkout action. It should be noted that the integration, on redirecting back from the PayPal Express Checkout page, will redirect to the first page in your store associated with this CMS action.
    ---
    action: 'payPalExpress:checkout'
    template: inner
    protocol: all
    published: true
    name: 'PayPal Express Checkout'
    url: /paypal-checkout
    ---
    <div class="row">
        <div class="content twelve columns">
        {% if not items.count %}
            <a class="secondary button" href="{{ site_url('shop') }}">Your cart is empty! Continue shopping.</a>
                {% else %}
            <div id="checkout-page">{{ partial('shop-paypal-checkout') }}</div>
        {% endif %}
        </div>
    </div>
    partial - shop-paypal-checkout.htm, representative of a typical shop-checkout partial, minus the billing_info step.
    {% if step == 'shipping_method' %}
    {{ partial('shop-paypal-checkout-shippingmethod') }}
    {% elseif step == 'pay' %}
    {{ partial('shop-paypal-checkout-pay') }}
    {% endif %}
    
partial - shop-paypal-checkout-progress.htm, in place of a typical shop-checkout-progress partial.
{{ open_form({'class': 'custom'}) }}
{% if step == 'pay' %}
<div class="left">
    <ul class="mybreadcrumbs">
    <li><a href="#" 
    data-ajax-handler="payPalExpress:checkout" 
    data-ajax-update="#checkout-page=shop-paypal-checkout, #breadcrumbs-area=shop-paypal-checkout-progress, #mini-cart=shop-minicart"
    data-ajax-extra-fields="nextStep=shipping_method"
        >Back to Shipping Method...</a>
    </li>
    </ul>
</div>
<div class="clear"></div>
<h2 class="left">PayPal Express Checkout - Pay</h2>
{% else %}
<h2 class="left">PayPal Express Checkout</h2>
{% endif %}
{{ close_form }}
partial - shop-paypal-checkout-shippingmethod.htm, representative of a typical shop-checkout-shippingmethod partial.
{{ open_form({'class': 'custom'}) }}
<div class="row">
    <h3>Shipping Method</h3>
        <div class="six columns">
        {% if shippingOptions %}
            <input type="hidden" value="" name="shippingMethod">
            <table class="compact full-width" id="shipping-methods">
            {% for index, option in shippingOptions %}
            <tr>
            <td>
            <label for="{{ 'option'~index }}">
            <!-- The shipping method radio button clicks are handled in the app.js -->
            <input name="shippingMethod" 
                {{ option.error_hint ? 'disabled' : null }} 
                value="{{ index }}" 
                {{ radio_state(shippingMethodInfo.id, option.id) }}
                type="radio" id="{{ 'option'~index }}"/>
            <span class="choice-title">
                {{ option.shippingMethodName }}
                {% if option.shippingServiceName %}: {{ option.shippingServiceName }}{% endif %}
            </span>
            {% if option.error_hint %}
            <span class="choice-description error-hint">{{ option.error_hint }}</span>
            {% endif %}
            </label>
            </td>
            <td class="narrow">
                {% if not option.error_hint %}
                {{ not option.is_free ? option.quote|currency : 'free' }}
                {% endif %}
            </td>
            </tr>
            {% endfor %}
            </table> 
            {% else %}
            <p>We are sorry, there are no shipping options available for your location.</p>
            {% endif %}
        </div>
    <div class="three columns data-list align-right" id="checkout-totals">
        {{ partial('shop-checkout-totals') }}
    </div>
</div>
{% if shippingOptions %}
<div class="row"> 
    <div class="twelve columns">
        <div class="right">
            <a class="button" href="#" data-ajax-handler="payPalExpress:checkout" data-ajax-update="#checkout-page=shop-paypal-checkout, #breadcrumbs-area=shop-paypal-checkout-progress, #mini-cart=shop-minicart">Place order & pay</a>
        </div>
    </div>
</div>
{% endif %}
<input type="hidden" name="step" value="shipping_method,review" />
<input type="hidden" name="nextStep" value="pay" />
{{ close_form }}
partial - shop-paypal-checkout-pay.htm, representative of a typical shop-checkout-pay partial.
{% if cart %}
{{ partial('shop-cart-items') }}
<div class="row">
    <div class="six columns">
{% if order.payment_processed %}
<p class="flash info"><strong>Thank you!</strong> The payment is already processed for this order.</p>
{% else %}
    <div class="row">
        <div class="twelve columns">
            <div class="row">
                <div id="payment_form">{{ partial('shop-paymentform') }}</div>
            </div>
        </div>
    </div>
{% endif %}
</div>
<div class="three columns offset-by-two data-list align-right">
{{ partial('shop-checkout-totals') }}
</div>
</div>
{% else %}
<p class="flash error">
Order not found.
</p>
{% endif %}
You should also modify your shop-cart-content.htm partial to expose the payPalExpressCheckoutButton.
partial - shop-cart-content.htm
{{ flash() }}
{% if itemCount %}
<div class="row">
    {{ partial('shop-cart-items', {'edit_cart': true}) }}
</div>
<div class="row">
    <!-- shipping estimate calculator... how to do this? -->
    <div class="six columns" style="display:none">
        <h3>Shipping rates calculator</h3>
            <div class="row">
                <div class="four columns">
                    <label for="country">
                    Country
                    </label>
<!-- 
The state selector updates automatically when the country changes. 
See app.js for the implementation details. 
-->
<select id="country" name="country" data-state-select="state" data-current-state="{{ shipping_info.state }}">
    {% for country in countries %}
<option value="{{ country.id }}" {{ option_state(country.id, shipping_info.country) }}>
{{ country.name }}
</option>
{% endfor %}
</select>
</div>
<div class="four columns">
    <label for="state">State</label>
    <select id="state" name="state"> 
        {# partial('shop-stateoptions', {'states': states, 'current_state': shipping_info.state}) #}
    </select>
</div>
<div class="four columns">
    <label for="zip">Zip/Postal Code</label>
    <input name="zip" type="text" value="{{ shipping_info.zip }}"/>
</div>
</div>
    <a class="button" href="#" data-ajax-handler="shop:onEvalShippingRate" data-ajax-update="#shipping_options=shopestimatedshippingoptions">Calculate</a>
    <div id="shipping_options"></div>
</div>
<div class="three columns offset-by-three data-list align-right">
    {% if totals.discountTotal > 0 %}
    <p><strong>Coupon discount:</strong> <i>{{ totals.discountTotal|currency }}</i></p>
    {% endif %}
    <p><strong>Cart total:</strong> <i>{{ totals.subtotal|currency }}</i></p>
    {% if totals.totalShippingQuote > 0 %}
    <p><strong>Shipping:</strong> <i>{{ totals.totalShippingQuote|currency }}</i></p>
    {% endif %}
    <p class="subtotal"><strong>Estimated total:</strong> <i>{{ totals.total|currency }}</i></p>
</div>
</div>
<div class="row">
    <div class="buttons-block">
        <div class="six columns">
            <a class="secondary button" href="{{ site_url('shop') }}">Continue shopping</a>
        </div>
        <div class="six columns">
            <div class="right">
<input type="text" id="coupon" name="coupon" value="{{ coupon_code }}" placeholder="Coupon code" />
    <a class="secondary button" href="#" data-ajax-handler="shop:cart" data-ajax-update="#cart-content=shop-cart-content, #mini-cart=shop-minicart">Update cart</a>
    {% if customer %}
<a class="button" href="{{ site_url('/checkout') }}">Checkout</a>
{% else %}
<a class="button" href="{{ site_url('/checkout-start') }}">Checkout</a>
{% endif %}
{% if payPalExpressCheckoutButton %}
{{ payPalExpressCheckoutButton }}
{% endif %}
            </div>
        </div>
    </div>
</div>
{% else %}
<div class="row">
    <div class="six columns">
        <a class="secondary button" href="{{ site_url('shop') }}">Your cart is empty! Continue shopping.</a>
    </div>
</div>
{% endif %}