Skip to content

Instantly share code, notes, and snippets.

@bummzack
Created December 31, 2017 20:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bummzack/80deeed074af1caeaebdbedfbfd25ca0 to your computer and use it in GitHub Desktop.
Save bummzack/80deeed074af1caeaebdbedfbfd25ca0 to your computer and use it in GitHub Desktop.
SilverShop: Optional Billing Address in Single-Page-Checkout
// JS File to toggle the billing address. This has to be loaded *after* jQuery.
// This gist assumes, that this file is located at `mysite/javascript/checkout.js`
(function ($) {
$(function () {
// ----------------------------------------------------------------------
// Checkout address toggle
// ----------------------------------------------------------------------
$("input.checkout-form__address-toggle").each(function () {
var $this = $(this);
if (!$this.is(':checked')) {
$this.parents('.field').next().slideUp(0);
}
$this.on("change", function (e) {
if (!$this.is(':checked')) {
$this.parents('.field').next().stop().slideUp(500).find('input[data-required]').removeAttr("required");
} else {
$this.parents('.field').next().stop().slideDown(500).find('input[data-required]').attr("required", "required");
}
})
});
});
})(jQuery);
<?php
/**
* Custom billing address component that makes the billing address optional by default.
* When toggling the `SeparateBillingAddress` checkbox, the address becomes mandatory.
*/
class CustomBillingAddressComponent extends BillingAddressCheckoutComponent
{
/**
* No required fields, since this is optional
* @param Order $order
* @return array
*/
public function getRequiredFields(Order $order)
{
return [];
}
public function getFormFields(Order $order)
{
// Feel free to alther the JS requirements to your need…
// If your website already includes jquery, the following line can be deleted.
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
// checkout.js can be integrated into your other JS code if needed…
Requirements::javascript('mysite/javascript/checkout.js');
$fields = parent::getFormFields($order);
$required = $this->getAddress($order)->getRequiredFields();
foreach ($required as $requiredField) {
if ($field = $fields->dataFieldByName($requiredField)) {
// Add an attribute to the required fields that will be used in JS to toggle the "required" attribute.
$field->setAttribute('data-required', '1');
}
}
$fields->unshift(LiteralField::create('_title', sprintf(
'<h3 class="checkout-form__title">%s</h3>',
_t('Address.BillingAddress')
)));
return FieldList::create(
CheckboxField::create(
'SeparateBillingAddress',
_t('Order.db_SeparateBillingAddress', 'Separate billing address')
)->addExtraClass('checkout-form__address-toggle'),
CompositeField::create($fields)
);
}
/**
* Manually validate address data if a separate billing address is given
* @param Order $order
* @param array $data
* @throws ValidationException
* @return boolean
*/
public function validateData(Order $order, array $data)
{
if (!empty($data['SeparateBillingAddress'])) {
$required = $this->getAddress($order)->getRequiredFields();
$result = ValidationResult::create();
foreach ($required as $requiredField) {
if (empty($data[$requiredField])) {
$result->error(_t(
'Form.FIELDISREQUIRED',
'{name} is required',
array(
'name' => _t('Address.db_' .$requiredField)
)
));
}
}
if (!$result->valid()) {
throw new ValidationException($result);
}
}
return true;
}
public function setData(Order $order, array $data)
{
if (!empty($data['SeparateBillingAddress'])) {
$order->SeparateBillingAddress = true;
parent::setData($order, $data);
}
}
}
<?php
use SilverStripe\Omnipay\GatewayInfo;
class CustomCheckoutComponentConfig extends CheckoutComponentConfig
{
public function __construct(Order $order)
{
parent::__construct($order);
$this->addComponent(CustomerDetailsCheckoutComponent::create());
$this->addComponent(ShippingAddressCheckoutComponent::create());
// This line is basically the only difference to the default `SinglePageCheckoutComponentConfig`
$this->addComponent(CustomBillingAddressComponent::create());
if (Checkout::member_creation_enabled() && !Member::currentUserID()) {
$this->addComponent(MembershipCheckoutComponent::create());
}
if (count(GatewayInfo::getSupportedGateways()) > 1) {
$this->addComponent(PaymentCheckoutComponent::create());
}
$this->addComponent(NotesCheckoutComponent::create());
$this->addComponent(TermsCheckoutComponent::create());
}
}
# Tell the Injector to use the CustomCheckoutComponentConfig.
# Put this somewhere in your config
Injector:
CheckoutComponentConfig:
class: CustomCheckoutComponentConfig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment