The payment form is the heart of Charge. There are a few required fields, and some optional ones too.
The payment form requires two hidden inputs - action and redirect.
action
redirect
<form id="charge-form" method="post" action="" accept-charset="UTF-8">
<input type="hidden" name="action" value="charge/charge">
<input type="hidden" name="redirect" value="payment/thanks/{hash}">
//etc..
<button type="submit"> Pay </button>
</form>
The basic form contains the following fields :
customerName
*requiredcustomerEmail
*requiredplanAmount
*requiredplanCurrency
planInterval
planIntervalCount
planCoupon
New in 1.3Note: Meta fields are passed over to stripe during processing and attached to the customer. You can use them to add any extra information you might need later to reconcile.
Meta data fields are very useful if you need to capture additional information from a user about a purchase or subscription. These meta fields are free form and can be named whatever you like, simply pass them as an array in the form. They're later available as a returned array on the charge elements.
meta[..]
Usage is simple, like :
<input type="text" name="meta[firstMetaField]" value="{% if charge is defined %}{{ charge.meta.firstMetaField }}{% endif %}"/> <input type="text" name="meta[otherField]" value="{% if charge is defined %}{{ charge.meta.otherField }}{% endif %}"/> <input type="text" name="meta[anythingElse]" value="{% if charge is defined %}{{ charge.meta.anythingElse }}{% endif %}"/>
Note: For these fields, we don't ever want to pass them to the server, so don't name the inputs. Instead, use a data attribute so Stripe.js can pick them up.
These fields need to be formatted slightly differently than normal fields. Like so :
<input type="text" data-stripe="number"/>
So - where you'd normally call the input 'name="cardNumber"', give it an attribute of 'data-stripe="number"' instead. The same for applies for all of the card* inputs
cardNumber
*required passed as data-stripe="number"
cardCvc
*required passed as data-stripe="cvc"
cardExpMonth
*required passed as data-stripe="exp_month"
cardExpYear
*required passed as data-stripe="exp_year"
cardName
passed as data-stripe="name"
cardAddressLine1
passed as data-stripe="address_line1"
cardAddressLine2
passed as data-stripe="address_line1"
cardAddressCity
passed as data-stripe="address_city"
cardAddressState
passed as data-stripe="address_state"
cardAddressZip
passed as data-stripe="address_zip"
cardAddressCountry
passed as data-stripe="address_country"
For fields like cardExpMonth and cardExpYear you'll want to display a select input or years/months. Twig makes this easy :
<select data-stripe="exp_month">
{% for month in craft.i18n.getLocaleData().getMonthNames() %}
<option value="{{ loop.index }}" {% if now.month == loop.index %}selected="selected"{% endif %}>{{ month }}</option>
{% endfor %}
</select>
and for years :
<select data-stripe="exp_year">
{% for year in now.year..now.year+5 %}
<option value="{{ year }}">{{ year }}</option>
{% endfor %}
</select>
On submit validation is performed, and if an error is found, the page is reloaded with the charge object, with any errors attached. You can repopulate the form, and show any errors.
Standard fields can be directly repopulated like this :
<input type="text" name="customerName" value="{% if charge is defined %}{{ charge.customerName }}{% endif %}">
Card fields are handled differently. Charge never sees the direct card details, but instead gets a cardToken, cardLast4 and cardType from Stripe. Re-population is done like this :
{% if charge is defined and charge.cardToken is not null %}
<input type="hidden" name="cardToken" value="{{ charge.cardToken }}" data-stripe="token"/>
<input type="hidden" name="cardLast4" value="{{ charge.cardLast4 }}"/>
<input type="hidden" name="cardType" value="{{ charge.cardType }}"/>
Payment card : {{ charge.formatCard() }}
{% else %}
// Show the standard card fields
{% endif %}
Note: Use {{ charge.formatCard() }} to show the formatted version of the card number, similar to : ··· ···· ···· 4242
If validation fails, the page will return with the charge object with the errors attached.
There are 'general' errors, along with field specific errors. You can define a twig macro to output the errors, like so :
{% macro errorList(errors) %}
{% if errors %}
{% for error in errors %}
{{ error }}
{% endfor %}
{% endif %}
{% endmacro %}
Then display the errors like so :
{% if charge is defined %}
{{ _self.errorList(charge.getErrors('general')) }}
{% endif %}
And also, per field errors like :
{% if charge is defined %}
{{ _self.errorList(charge.getErrors('customerName')) }}
{% endif %}
Where 'customerName' can be any of the fields above.
Note: Be sure to include the general error output in your form. If the payment fails on Stripe's side for any reason, that's where the error will be displayed