mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 13:44:42 +08:00
Merge pull request #1858 from woocommerce/PCP-2273-block-buttons
Render block buttons separately and add block style settings
This commit is contained in:
commit
9f5d62e2f2
18 changed files with 506 additions and 137 deletions
|
@ -32,7 +32,7 @@
|
|||
.wp-block-woocommerce-checkout {
|
||||
#applepay-container, .ppcp-button-applepay {
|
||||
--apple-pay-button-margin: 0;
|
||||
--apple-pay-button-height: 40px;
|
||||
--apple-pay-button-height: 48px;
|
||||
&.ppcp-button-pill {
|
||||
--apple-pay-button-border-radius: 50px;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@
|
|||
.wp-block-woocommerce-cart {
|
||||
#applepay-container, .ppcp-button-applepay {
|
||||
--apple-pay-button-margin: 0;
|
||||
--apple-pay-button-height: 40px;
|
||||
--apple-pay-button-height: 48px;
|
||||
}
|
||||
/* Workaround for blocks grid */
|
||||
.wc-block-components-express-payment__event-buttons {
|
||||
|
|
|
@ -107,7 +107,7 @@ class ApplepayButton {
|
|||
let config = {
|
||||
wrapper: this.buttonConfig.button.wrapper,
|
||||
ppcpStyle: this.ppcpConfig.button.style,
|
||||
//buttonStyle: this.buttonConfig.button.style,
|
||||
buttonStyle: this.buttonConfig.button.style,
|
||||
ppcpButtonWrapper: this.ppcpConfig.button.wrapper
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ class ApplepayButton {
|
|||
}
|
||||
|
||||
if (['cart-block', 'checkout-block'].indexOf(this.context) !== -1) {
|
||||
config.ppcpButtonWrapper = '#express-payment-method-ppcp-gateway';
|
||||
config.ppcpButtonWrapper = '#express-payment-method-ppcp-gateway-paypal';
|
||||
}
|
||||
|
||||
return config;
|
||||
|
@ -167,14 +167,8 @@ class ApplepayButton {
|
|||
addButton() {
|
||||
this.log('addButton', this.context);
|
||||
|
||||
const wrapper =
|
||||
(this.context === 'mini-cart')
|
||||
? this.buttonConfig.button.mini_cart_wrapper
|
||||
: this.buttonConfig.button.wrapper;
|
||||
const shape =
|
||||
(this.context === 'mini-cart')
|
||||
? this.ppcpConfig.button.mini_cart_style.shape
|
||||
: this.ppcpConfig.button.style.shape;
|
||||
const { wrapper, ppcpStyle } = this.contextConfig();
|
||||
|
||||
const appleContainer = document.getElementById(wrapper);
|
||||
const type = this.buttonConfig.button.type;
|
||||
const language = this.buttonConfig.button.lang;
|
||||
|
@ -185,7 +179,12 @@ class ApplepayButton {
|
|||
appleContainer.innerHTML = `<apple-pay-button id="${id}" buttonstyle="${color}" type="${type}" locale="${language}">`;
|
||||
}
|
||||
|
||||
jQuery('#' + wrapper).addClass('ppcp-button-' + shape);
|
||||
jQuery('#' + wrapper).addClass('ppcp-button-' + ppcpStyle.shape);
|
||||
|
||||
if (ppcpStyle.height) {
|
||||
jQuery('#' + wrapper).css('--apple-pay-button-height', `${ppcpStyle.height}px`)
|
||||
}
|
||||
|
||||
jQuery(wrapper).append(appleContainer);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,9 +55,8 @@ const ApplePayComponent = () => {
|
|||
}
|
||||
|
||||
const features = ['products'];
|
||||
let registerMethod = registerExpressPaymentMethod;
|
||||
|
||||
registerMethod({
|
||||
registerExpressPaymentMethod({
|
||||
name: buttonData.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: buttonData.title}}/>,
|
||||
content: <ApplePayComponent isEditing={false}/>,
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
import {useEffect, useState} from '@wordpress/element';
|
||||
import {registerExpressPaymentMethod, registerPaymentMethod} from '@woocommerce/blocks-registry';
|
||||
import {mergeWcAddress, paypalAddressToWc, paypalOrderToWcAddresses} from "./Helper/Address";
|
||||
import {loadPaypalScript} from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading'
|
||||
import {
|
||||
loadPaypalScriptPromise
|
||||
} from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading'
|
||||
import {
|
||||
normalizeStyleForFundingSource
|
||||
} from '../../../ppcp-button/resources/js/modules/Helper/Style'
|
||||
import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher";
|
||||
|
||||
const config = wc.wcSettings.getSetting('ppcp-gateway_data');
|
||||
|
||||
window.ppcpFundingSource = config.fundingSource;
|
||||
|
||||
let registeredContext = false;
|
||||
|
||||
const PayPalComponent = ({
|
||||
onClick,
|
||||
onClose,
|
||||
|
@ -18,12 +25,15 @@ const PayPalComponent = ({
|
|||
activePaymentMethod,
|
||||
shippingData,
|
||||
isEditing,
|
||||
fundingSource,
|
||||
}) => {
|
||||
const {onPaymentSetup, onCheckoutFail, onCheckoutValidation} = eventRegistration;
|
||||
const {responseTypes} = emitResponse;
|
||||
|
||||
const [paypalOrder, setPaypalOrder] = useState(null);
|
||||
|
||||
const methodId = fundingSource ? `${config.id}-${fundingSource}` : config.id;
|
||||
|
||||
useEffect(() => {
|
||||
// fill the form if in continuation (for product or mini-cart buttons)
|
||||
if (!config.scriptData.continuation || !config.scriptData.continuation.order || window.ppcpContinuationFilled) {
|
||||
|
@ -40,24 +50,6 @@ const PayPalComponent = ({
|
|||
window.ppcpContinuationFilled = true;
|
||||
}, [])
|
||||
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
useEffect(() => {
|
||||
if (!loaded && !config.scriptData.continuation) {
|
||||
loadPaypalScript(config.scriptData, () => {
|
||||
setLoaded(true);
|
||||
|
||||
buttonModuleWatcher.registerContextBootstrap(config.scriptData.context, {
|
||||
createOrder: () => {
|
||||
return createOrder();
|
||||
},
|
||||
onApprove: (data, actions) => {
|
||||
return handleApprove(data, actions);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [loaded]);
|
||||
|
||||
const createOrder = async () => {
|
||||
try {
|
||||
const res = await fetch(config.scriptData.ajax.create_order.endpoint, {
|
||||
|
@ -233,7 +225,7 @@ const PayPalComponent = ({
|
|||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (activePaymentMethod !== config.id) {
|
||||
if (activePaymentMethod !== methodId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -269,7 +261,7 @@ const PayPalComponent = ({
|
|||
}, [onPaymentSetup, paypalOrder, activePaymentMethod]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activePaymentMethod !== config.id) {
|
||||
if (activePaymentMethod !== methodId) {
|
||||
return;
|
||||
}
|
||||
const unsubscribe = onCheckoutFail(({ processingResponse }) => {
|
||||
|
@ -296,15 +288,26 @@ const PayPalComponent = ({
|
|||
)
|
||||
}
|
||||
|
||||
if (!loaded) {
|
||||
return null;
|
||||
if (!registeredContext) {
|
||||
buttonModuleWatcher.registerContextBootstrap(config.scriptData.context, {
|
||||
createOrder: () => {
|
||||
return createOrder();
|
||||
},
|
||||
onApprove: (data, actions) => {
|
||||
return handleApprove(data, actions);
|
||||
},
|
||||
});
|
||||
registeredContext = true;
|
||||
}
|
||||
|
||||
const style = normalizeStyleForFundingSource(config.scriptData.button.style, fundingSource);
|
||||
|
||||
const PayPalButton = window.paypal.Buttons.driver("react", { React, ReactDOM });
|
||||
|
||||
return (
|
||||
<PayPalButton
|
||||
style={config.scriptData.button.style}
|
||||
fundingSource={fundingSource}
|
||||
style={style}
|
||||
onClick={handleClick}
|
||||
onCancel={onClose}
|
||||
onError={onClose}
|
||||
|
@ -317,7 +320,7 @@ const PayPalComponent = ({
|
|||
|
||||
const features = ['products'];
|
||||
|
||||
if (config.usePlaceOrder && !config.scriptData.continuation) {
|
||||
if ((config.addPlaceOrderMethod || config.usePlaceOrder) && !config.scriptData.continuation) {
|
||||
registerPaymentMethod({
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: config.title}}/>,
|
||||
|
@ -330,22 +333,39 @@ if (config.usePlaceOrder && !config.scriptData.continuation) {
|
|||
features: features,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
let registerMethod = registerExpressPaymentMethod;
|
||||
if (config.scriptData.continuation) {
|
||||
features.push('ppcp_continuation');
|
||||
registerMethod = registerPaymentMethod;
|
||||
}
|
||||
}
|
||||
|
||||
registerMethod({
|
||||
if (config.scriptData.continuation) {
|
||||
registerPaymentMethod({
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: config.title}}/>,
|
||||
content: <PayPalComponent isEditing={false}/>,
|
||||
edit: <PayPalComponent isEditing={true}/>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => config.enabled,
|
||||
canMakePayment: () => true,
|
||||
supports: {
|
||||
features: [...features, 'ppcp_continuation'],
|
||||
},
|
||||
});
|
||||
} else if (!config.usePlaceOrder) {
|
||||
const paypalScriptPromise = loadPaypalScriptPromise(config.scriptData);
|
||||
|
||||
for (const fundingSource of ['paypal', ...config.enabledFundingSources]) {
|
||||
registerExpressPaymentMethod({
|
||||
name: `${config.id}-${fundingSource}`,
|
||||
paymentMethodId: config.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: config.title}}/>,
|
||||
content: <PayPalComponent isEditing={false} fundingSource={fundingSource}/>,
|
||||
edit: <PayPalComponent isEditing={true} fundingSource={fundingSource}/>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: async () => {
|
||||
await paypalScriptPromise;
|
||||
|
||||
return paypal.Buttons({fundingSource}).isEligible();
|
||||
},
|
||||
supports: {
|
||||
features: features,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,8 +35,10 @@ return array(
|
|||
$container->get( 'blocks.settings.final_review_enabled' ),
|
||||
$container->get( 'session.cancellation.view' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'blocks.add-place-order-method' ),
|
||||
$container->get( 'wcgateway.use-place-order-button' ),
|
||||
$container->get( 'wcgateway.place-order-button-text' )
|
||||
$container->get( 'wcgateway.place-order-button-text' ),
|
||||
$container->get( 'wcgateway.all-funding-sources' )
|
||||
);
|
||||
},
|
||||
'blocks.settings.final_review_enabled' => static function ( ContainerInterface $container ): bool {
|
||||
|
@ -56,4 +58,14 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
|
||||
'blocks.add-place-order-method' => function ( ContainerInterface $container ) : bool {
|
||||
/**
|
||||
* Whether to create a non-express method with the standard "Place order" button redirecting to PayPal.
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_payments_blocks_add_place_order_method',
|
||||
true
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -88,7 +88,14 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
private $session_handler;
|
||||
|
||||
/**
|
||||
* Whether to use the standard "Place order" button.
|
||||
* Whether to create a non-express method with the standard "Place order" button.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $add_place_order_method;
|
||||
|
||||
/**
|
||||
* Whether to use the standard "Place order" button instead of PayPal buttons.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
|
@ -101,6 +108,13 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
*/
|
||||
protected $place_order_button_text;
|
||||
|
||||
/**
|
||||
* All existing funding sources for PayPal buttons.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $all_funding_sources;
|
||||
|
||||
/**
|
||||
* Assets constructor.
|
||||
*
|
||||
|
@ -113,8 +127,10 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
* @param bool $final_review_enabled Whether the final review is enabled.
|
||||
* @param CancelView $cancellation_view The cancellation view.
|
||||
* @param SessionHandler $session_handler The Session handler.
|
||||
* @param bool $use_place_order Whether to use the standard "Place order" button.
|
||||
* @param bool $add_place_order_method Whether to create a non-express method with the standard "Place order" button.
|
||||
* @param bool $use_place_order Whether to use the standard "Place order" button instead of PayPal buttons.
|
||||
* @param string $place_order_button_text The text for the standard "Place order" button.
|
||||
* @param array $all_funding_sources All existing funding sources for PayPal buttons.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
|
@ -126,8 +142,10 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
bool $final_review_enabled,
|
||||
CancelView $cancellation_view,
|
||||
SessionHandler $session_handler,
|
||||
bool $add_place_order_method,
|
||||
bool $use_place_order,
|
||||
string $place_order_button_text
|
||||
string $place_order_button_text,
|
||||
array $all_funding_sources
|
||||
) {
|
||||
$this->name = PayPalGateway::ID;
|
||||
$this->module_url = $module_url;
|
||||
|
@ -139,8 +157,10 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
$this->final_review_enabled = $final_review_enabled;
|
||||
$this->cancellation_view = $cancellation_view;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->add_place_order_method = $add_place_order_method;
|
||||
$this->use_place_order = $use_place_order;
|
||||
$this->place_order_button_text = $place_order_button_text;
|
||||
$this->all_funding_sources = $all_funding_sources;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -194,6 +214,14 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
}
|
||||
}
|
||||
|
||||
$disabled_funding_sources = explode( ',', $script_data['url_params']['disable-funding'] ) ?: array();
|
||||
$funding_sources = array_values(
|
||||
array_diff(
|
||||
array_keys( $this->all_funding_sources ),
|
||||
$disabled_funding_sources
|
||||
)
|
||||
);
|
||||
|
||||
return array(
|
||||
'id' => $this->gateway->id,
|
||||
'title' => $this->gateway->title,
|
||||
|
@ -201,8 +229,10 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
'enabled' => $this->settings_status->is_smart_button_enabled_for_location( $script_data['context'] ),
|
||||
'fundingSource' => $this->session_handler->funding_source(),
|
||||
'finalReviewEnabled' => $this->final_review_enabled,
|
||||
'addPlaceOrderMethod' => $this->add_place_order_method,
|
||||
'usePlaceOrder' => $this->use_place_order,
|
||||
'placeOrderButtonText' => $this->place_order_button_text,
|
||||
'enabledFundingSources' => $funding_sources,
|
||||
'ajax' => array(
|
||||
'update_shipping' => array(
|
||||
'endpoint' => WC_AJAX::get_endpoint( UpdateShippingEndpoint::ENDPOINT ),
|
||||
|
|
|
@ -279,11 +279,12 @@ document.addEventListener(
|
|||
});
|
||||
|
||||
let bootstrapped = false;
|
||||
let failed = false;
|
||||
|
||||
hideOrderButtonIfPpcpGateway();
|
||||
|
||||
jQuery(document.body).on('updated_checkout payment_method_selected', () => {
|
||||
if (bootstrapped) {
|
||||
if (bootstrapped || failed) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -294,6 +295,12 @@ document.addEventListener(
|
|||
bootstrapped = true;
|
||||
|
||||
bootstrap();
|
||||
}, () => {
|
||||
failed = true;
|
||||
|
||||
setVisibleByClass(ORDER_BUTTON_SELECTOR, true, 'ppcp-hidden');
|
||||
buttonsSpinner.unblock();
|
||||
cardsSpinner.unblock();
|
||||
});
|
||||
},
|
||||
);
|
||||
|
|
|
@ -26,7 +26,7 @@ const storeToken = (token) => {
|
|||
sessionStorage.setItem(storageKey, JSON.stringify(token));
|
||||
}
|
||||
|
||||
const dataClientIdAttributeHandler = (scriptOptions, config, callback) => {
|
||||
const dataClientIdAttributeHandler = (scriptOptions, config, callback, errorCallback = null) => {
|
||||
fetch(config.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
@ -51,6 +51,10 @@ const dataClientIdAttributeHandler = (scriptOptions, config, callback) => {
|
|||
if (typeof callback === 'function') {
|
||||
callback(paypal);
|
||||
}
|
||||
}).catch(err => {
|
||||
if (typeof errorCallback === 'function') {
|
||||
errorCallback(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@ import {keysToCamelCase} from "./Utils";
|
|||
// This component may be used by multiple modules. This assures that options are shared between all instances.
|
||||
let options = window.ppcpWidgetBuilder = window.ppcpWidgetBuilder || {
|
||||
isLoading: false,
|
||||
onLoadedCallbacks: []
|
||||
onLoadedCallbacks: [],
|
||||
onErrorCallbacks: [],
|
||||
};
|
||||
|
||||
export const loadPaypalScript = (config, onLoaded) => {
|
||||
export const loadPaypalScript = (config, onLoaded, onError = null) => {
|
||||
// If PayPal is already loaded call the onLoaded callback and return.
|
||||
if (typeof paypal !== 'undefined') {
|
||||
onLoaded();
|
||||
|
@ -19,6 +20,9 @@ export const loadPaypalScript = (config, onLoaded) => {
|
|||
|
||||
// Add the onLoaded callback to the onLoadedCallbacks stack.
|
||||
options.onLoadedCallbacks.push(onLoaded);
|
||||
if (onError) {
|
||||
options.onErrorCallbacks.push(onError);
|
||||
}
|
||||
|
||||
// Return if it's still loading.
|
||||
if (options.isLoading) {
|
||||
|
@ -26,6 +30,12 @@ export const loadPaypalScript = (config, onLoaded) => {
|
|||
}
|
||||
options.isLoading = true;
|
||||
|
||||
const resetState = () => {
|
||||
options.isLoading = false;
|
||||
options.onLoadedCallbacks = [];
|
||||
options.onErrorCallbacks = [];
|
||||
}
|
||||
|
||||
// Callback to be called once the PayPal script is loaded.
|
||||
const callback = (paypal) => {
|
||||
widgetBuilder.setPaypal(paypal);
|
||||
|
@ -34,8 +44,14 @@ export const loadPaypalScript = (config, onLoaded) => {
|
|||
onLoadedCallback();
|
||||
}
|
||||
|
||||
options.isLoading = false;
|
||||
options.onLoadedCallbacks = [];
|
||||
resetState();
|
||||
}
|
||||
const errorCallback = (err) => {
|
||||
for (const onErrorCallback of options.onErrorCallbacks) {
|
||||
onErrorCallback(err);
|
||||
}
|
||||
|
||||
resetState();
|
||||
}
|
||||
|
||||
// Build the PayPal script options.
|
||||
|
@ -44,12 +60,20 @@ export const loadPaypalScript = (config, onLoaded) => {
|
|||
|
||||
// Load PayPal script for special case with data-client-token
|
||||
if (config.data_client_id.set_attribute) {
|
||||
dataClientIdAttributeHandler(scriptOptions, config.data_client_id, callback);
|
||||
dataClientIdAttributeHandler(scriptOptions, config.data_client_id, callback, errorCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
// Load PayPal script
|
||||
loadScript(scriptOptions).then(callback);
|
||||
loadScript(scriptOptions)
|
||||
.then(callback)
|
||||
.catch(errorCallback);
|
||||
}
|
||||
|
||||
export const loadPaypalScriptPromise = (config) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
loadPaypalScript(config, resolve, reject)
|
||||
});
|
||||
}
|
||||
|
||||
export const loadPaypalJsScript = (options, buttons, container) => {
|
||||
|
|
20
modules/ppcp-button/resources/js/modules/Helper/Style.js
Normal file
20
modules/ppcp-button/resources/js/modules/Helper/Style.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
export const normalizeStyleForFundingSource = (style, fundingSource) => {
|
||||
const commonProps = {};
|
||||
['shape', 'height'].forEach(prop => {
|
||||
if (style[prop]) {
|
||||
commonProps[prop] = style[prop];
|
||||
}
|
||||
});
|
||||
|
||||
switch (fundingSource) {
|
||||
case 'paypal':
|
||||
return style;
|
||||
case 'paylater':
|
||||
return {
|
||||
color: style.color,
|
||||
...commonProps
|
||||
};
|
||||
default:
|
||||
return commonProps;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import merge from "deepmerge";
|
|||
import {loadScript} from "@paypal/paypal-js";
|
||||
import {keysToCamelCase} from "../Helper/Utils";
|
||||
import widgetBuilder from "./WidgetBuilder";
|
||||
import {normalizeStyleForFundingSource} from "../Helper/Style";
|
||||
|
||||
class Renderer {
|
||||
constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit) {
|
||||
|
@ -36,16 +37,7 @@ class Renderer {
|
|||
} else {
|
||||
// render each button separately
|
||||
for (const fundingSource of paypal.getFundingSources().filter(s => !(s in enabledSeparateGateways))) {
|
||||
let style = settings.button.style;
|
||||
if (fundingSource !== 'paypal') {
|
||||
style = {
|
||||
shape: style.shape,
|
||||
color: style.color,
|
||||
};
|
||||
if (fundingSource !== 'paylater') {
|
||||
delete style.color;
|
||||
}
|
||||
}
|
||||
const style = normalizeStyleForFundingSource(settings.button.style, fundingSource);
|
||||
|
||||
this.renderButtons(
|
||||
settings.button.wrapper,
|
||||
|
|
|
@ -1049,30 +1049,39 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
'mini_cart_wrapper' => '#ppc-button-minicart',
|
||||
'is_mini_cart_disabled' => $this->is_button_disabled( 'mini-cart' ),
|
||||
'cancel_wrapper' => '#ppcp-cancel',
|
||||
'mini_cart_style' => array(
|
||||
'mini_cart_style' => $this->normalize_style(
|
||||
array(
|
||||
'layout' => $this->style_for_context( 'layout', 'mini-cart' ),
|
||||
'color' => $this->style_for_context( 'color', 'mini-cart' ),
|
||||
'shape' => $this->style_for_context( 'shape', 'mini-cart' ),
|
||||
'label' => $this->style_for_context( 'label', 'mini-cart' ),
|
||||
'tagline' => $this->style_for_context( 'tagline', 'mini-cart' ),
|
||||
'height' => $this->settings->has( 'button_mini-cart_height' ) && $this->settings->get( 'button_mini-cart_height' ) ? $this->normalize_height( (int) $this->settings->get( 'button_mini-cart_height' ) ) : 35,
|
||||
'height' => $this->normalize_height( $this->style_for_context( 'height', 'mini-cart', 35 ), 25, 55 ),
|
||||
)
|
||||
),
|
||||
'style' => array(
|
||||
'style' => $this->normalize_style(
|
||||
array(
|
||||
'layout' => $this->style_for_context( 'layout', $this->context() ),
|
||||
'color' => $this->style_for_context( 'color', $this->context() ),
|
||||
'shape' => $this->style_for_context( 'shape', $this->context() ),
|
||||
'label' => $this->style_for_context( 'label', $this->context() ),
|
||||
'tagline' => $this->style_for_context( 'tagline', $this->context() ),
|
||||
'height' => in_array( $this->context(), array( 'cart-block', 'checkout-block' ), true )
|
||||
? $this->normalize_height( $this->style_for_context( 'height', $this->context(), 48 ), 40, 55 )
|
||||
: null,
|
||||
)
|
||||
),
|
||||
),
|
||||
'separate_buttons' => array(
|
||||
'card' => array(
|
||||
'id' => CardButtonGateway::ID,
|
||||
'wrapper' => '#ppc-button-' . CardButtonGateway::ID,
|
||||
'style' => array(
|
||||
'style' => $this->normalize_style(
|
||||
array(
|
||||
'shape' => $this->style_for_apm( 'shape', 'card' ),
|
||||
'color' => $this->style_for_apm( 'color', 'card', 'black' ),
|
||||
'layout' => $this->style_for_apm( 'poweredby_tagline', 'card', false ) === $this->normalize_style_value( true ) ? 'vertical' : 'horizontal',
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -1143,13 +1152,6 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
$localize['pay_now'] = $this->pay_now_script_data();
|
||||
}
|
||||
|
||||
if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) {
|
||||
$localize['button']['mini_cart_style']['tagline'] = false;
|
||||
}
|
||||
if ( $this->style_for_context( 'layout', $this->context() ) !== 'horizontal' ) {
|
||||
$localize['button']['style']['tagline'] = false;
|
||||
}
|
||||
|
||||
if ( $this->is_paypal_continuation() ) {
|
||||
$order = $this->session_handler->order();
|
||||
assert( $order !== null );
|
||||
|
@ -1410,12 +1412,14 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
*
|
||||
* @param string $style The name of the style property.
|
||||
* @param string $context The context.
|
||||
* @param ?mixed $default The default value.
|
||||
*
|
||||
* @return string
|
||||
* @return string|int
|
||||
*/
|
||||
private function style_for_context( string $style, string $context ): string {
|
||||
// Use the cart/checkout styles for blocks.
|
||||
$context = str_replace( '-block', '', $context );
|
||||
private function style_for_context( string $style, string $context, $default = null ) {
|
||||
if ( $context === 'checkout-block' ) {
|
||||
$context = 'checkout-block-express';
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
'layout' => 'vertical',
|
||||
|
@ -1433,6 +1437,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
|
||||
return $this->get_style_value( "button_{$context}_${style}" )
|
||||
?? $this->get_style_value( "button_${style}" )
|
||||
?? ( $default ? $this->normalize_style_value( $default ) : null )
|
||||
?? $this->normalize_style_value( $defaults[ $style ] ?? '' );
|
||||
}
|
||||
|
||||
|
@ -1443,9 +1448,9 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
* @param string $apm The APM name, such as 'card'.
|
||||
* @param ?mixed $default The default value.
|
||||
*
|
||||
* @return string
|
||||
* @return string|int
|
||||
*/
|
||||
private function style_for_apm( string $style, string $apm, $default = null ): string {
|
||||
private function style_for_apm( string $style, string $apm, $default = null ) {
|
||||
return $this->get_style_value( "${apm}_button_${style}" )
|
||||
?? ( $default ? $this->normalize_style_value( $default ) : null )
|
||||
?? $this->style_for_context( $style, 'checkout' );
|
||||
|
@ -1455,9 +1460,9 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
* Returns the style property value or null.
|
||||
*
|
||||
* @param string $key The style property key in the settings.
|
||||
* @return string|null
|
||||
* @return string|int|null
|
||||
*/
|
||||
private function get_style_value( string $key ): ?string {
|
||||
private function get_style_value( string $key ) {
|
||||
if ( ! $this->settings->has( $key ) ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1468,27 +1473,49 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
* Converts the style property value to string.
|
||||
*
|
||||
* @param mixed $value The style property value.
|
||||
* @return string
|
||||
* @return string|int
|
||||
*/
|
||||
private function normalize_style_value( $value ): string {
|
||||
private function normalize_style_value( $value ) {
|
||||
if ( is_bool( $value ) ) {
|
||||
$value = $value ? 'true' : 'false';
|
||||
}
|
||||
if ( is_int( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value between 25 and 55.
|
||||
* Fixes the style.
|
||||
*
|
||||
* @param int $height The input value.
|
||||
* @param array $style The style properties.
|
||||
* @return array
|
||||
*/
|
||||
private function normalize_style( array $style ): array {
|
||||
if ( array_key_exists( 'tagline', $style ) && ( ! array_key_exists( 'layout', $style ) || $style['layout'] !== 'horizontal' ) ) {
|
||||
$style['tagline'] = false;
|
||||
}
|
||||
if ( array_key_exists( 'height', $style ) && ! $style['height'] ) {
|
||||
unset( $style['height'] );
|
||||
}
|
||||
return $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a number between min and max.
|
||||
*
|
||||
* @param mixed $height The input value.
|
||||
* @param int $min The minimum value.
|
||||
* @param int $max The maximum value.
|
||||
* @return int The normalized output value.
|
||||
*/
|
||||
private function normalize_height( int $height ): int {
|
||||
if ( $height < 25 ) {
|
||||
return 25;
|
||||
private function normalize_height( $height, int $min, int $max ): int {
|
||||
$height = (int) $height;
|
||||
if ( $height < $min ) {
|
||||
return $min;
|
||||
}
|
||||
if ( $height > 55 ) {
|
||||
return 55;
|
||||
if ( $height > $max ) {
|
||||
return $max;
|
||||
}
|
||||
|
||||
return $height;
|
||||
|
|
|
@ -25,14 +25,14 @@
|
|||
.wp-block-woocommerce-checkout {
|
||||
.ppcp-button-googlepay {
|
||||
margin: 0;
|
||||
height: 40px;
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.wp-block-woocommerce-cart {
|
||||
.ppcp-button-googlepay {
|
||||
margin: 0;
|
||||
height: 40px;
|
||||
height: 48px;
|
||||
}
|
||||
/* Workaround for blocks grid */
|
||||
.wc-block-components-express-payment__event-buttons {
|
||||
|
|
|
@ -111,7 +111,7 @@ class GooglepayButton {
|
|||
}
|
||||
|
||||
if (['cart-block', 'checkout-block'].indexOf(this.context) !== -1) {
|
||||
config.ppcpButtonWrapper = '#express-payment-method-ppcp-gateway';
|
||||
config.ppcpButtonWrapper = '#express-payment-method-ppcp-gateway-paypal';
|
||||
}
|
||||
|
||||
return config;
|
||||
|
@ -168,6 +168,10 @@ class GooglepayButton {
|
|||
this.waitForWrapper(wrapper, () => {
|
||||
jQuery(wrapper).addClass('ppcp-button-' + ppcpStyle.shape);
|
||||
|
||||
if (ppcpStyle.height) {
|
||||
jQuery(wrapper).css('height', `${ppcpStyle.height}px`)
|
||||
}
|
||||
|
||||
const button =
|
||||
this.paymentsClient.createButton({
|
||||
onClick: this.onButtonClick.bind(this),
|
||||
|
|
|
@ -56,9 +56,8 @@ const GooglePayComponent = () => {
|
|||
}
|
||||
|
||||
const features = ['products'];
|
||||
let registerMethod = registerExpressPaymentMethod;
|
||||
|
||||
registerMethod({
|
||||
registerExpressPaymentMethod({
|
||||
name: buttonData.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: buttonData.title}}/>,
|
||||
content: <GooglePayComponent isEditing={false}/>,
|
||||
|
|
|
@ -9,7 +9,7 @@ document.addEventListener(
|
|||
|
||||
const smartButtonLocationsSelector = '#field-smart_button_locations';
|
||||
const smartButtonLocationsSelect = smartButtonLocationsSelector + ' select';
|
||||
const smartButtonSelectableLocations = ['product', 'cart', 'checkout', 'mini-cart'];
|
||||
const smartButtonSelectableLocations = ['product', 'cart', 'checkout', 'mini-cart', 'cart-block', 'checkout-block-express'];
|
||||
|
||||
const groupToggle = (selector, group) => {
|
||||
const toggleElement = document.querySelector(selector);
|
||||
|
@ -317,6 +317,7 @@ document.addEventListener(
|
|||
'#field-button' + locationPrefix + '_label',
|
||||
'#field-button' + locationPrefix + '_color',
|
||||
'#field-button' + locationPrefix + '_shape',
|
||||
'#field-button' + locationPrefix + '_height',
|
||||
'#field-button' + locationPrefix + '_preview',
|
||||
]
|
||||
|
||||
|
@ -324,11 +325,7 @@ document.addEventListener(
|
|||
inputSelectors.push('#field-button_' + location + '_heading');
|
||||
}
|
||||
|
||||
if (location === 'mini-cart') {
|
||||
inputSelectors.push('#field-button' + locationPrefix + '_height');
|
||||
}
|
||||
|
||||
return inputSelectors
|
||||
return inputSelectors.filter(selector => document.querySelector(selector));
|
||||
}
|
||||
|
||||
const allPayLaterMessaginginputSelectors = () => {
|
||||
|
|
|
@ -310,11 +310,11 @@ document.addEventListener(
|
|||
|
||||
loadPaypalScript(oldScriptSettings, () => {
|
||||
const payLaterMessagingLocations = ['product', 'cart', 'checkout', 'shop', 'home', 'general'];
|
||||
const paypalButtonLocations = ['product', 'cart', 'checkout', 'mini-cart', 'general'];
|
||||
const paypalButtonLocations = ['product', 'cart', 'checkout', 'mini-cart', 'cart-block', 'checkout-block-express', 'general'];
|
||||
|
||||
paypalButtonLocations.forEach((location) => {
|
||||
const inputNamePrefix = location === 'checkout' ? '#ppcp-button' : '#ppcp-button_' + location;
|
||||
let wrapperName = location.charAt(0).toUpperCase() + location.slice(1);
|
||||
const wrapperName = location.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');
|
||||
const fields = {
|
||||
'color': inputNamePrefix + '_color',
|
||||
'shape': inputNamePrefix + '_shape',
|
||||
|
@ -323,9 +323,8 @@ document.addEventListener(
|
|||
'layout': inputNamePrefix + '_layout',
|
||||
}
|
||||
|
||||
if (location === 'mini-cart') {
|
||||
if (document.querySelector(inputNamePrefix + '_height')) {
|
||||
fields['height'] = inputNamePrefix + '_height';
|
||||
wrapperName = 'MiniCart';
|
||||
}
|
||||
|
||||
createButtonPreview(() => getButtonSettings('#ppcp' + wrapperName + 'ButtonPreview', fields));
|
||||
|
|
|
@ -802,6 +802,242 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
|
||||
// Block express checkout settings.
|
||||
'button_checkout-block-express_heading' => array(
|
||||
'heading' => __( 'Block Express Checkout Buttons', 'woocommerce-paypal-payments' ),
|
||||
'description' => sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__(
|
||||
'Customize the appearance of the PayPal smart buttons on the %1$sBlock Express Checkout%2$s.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#button-on-block-express-checkout" target="_blank">',
|
||||
'</a>'
|
||||
),
|
||||
'type' => 'ppcp-heading',
|
||||
'screens' => array( State::STATE_START, State::STATE_ONBOARDED ),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'button_checkout-block-express_label' => array(
|
||||
'title' => __( 'Button Label', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
/**
|
||||
* Returns default label ID of the PayPal button in block express checkout.
|
||||
*/
|
||||
'default' => apply_filters( 'woocommerce_paypal_payments_button_checkout_block_express_label_default', 'paypal' ),
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'This controls the label on the primary button.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'options' => array(
|
||||
'paypal' => __( 'PayPal', 'woocommerce-paypal-payments' ),
|
||||
'checkout' => __( 'Checkout', 'woocommerce-paypal-payments' ),
|
||||
'buynow' => __( 'PayPal Buy Now', 'woocommerce-paypal-payments' ),
|
||||
'pay' => __( 'Pay with PayPal', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'button_checkout-block-express_color' => array(
|
||||
'title' => __( 'Color', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'gold',
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'Controls the background color of the primary button. Use "Gold" to leverage PayPal\'s recognition and preference, or change it to match your site design or aesthetic.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'options' => array(
|
||||
'gold' => __( 'Gold (Recommended)', 'woocommerce-paypal-payments' ),
|
||||
'blue' => __( 'Blue', 'woocommerce-paypal-payments' ),
|
||||
'silver' => __( 'Silver', 'woocommerce-paypal-payments' ),
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'button_checkout-block-express_shape' => array(
|
||||
'title' => __( 'Shape', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'rect',
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'The pill-shaped button\'s unique and powerful shape signifies PayPal in people\'s minds. Use the rectangular button as an alternative when pill-shaped buttons might pose design challenges.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'options' => array(
|
||||
'pill' => __( 'Pill', 'woocommerce-paypal-payments' ),
|
||||
'rect' => __( 'Rectangle', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'button_checkout-block-express_height' => array(
|
||||
'title' => __( 'Button Height', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'number',
|
||||
'default' => '48',
|
||||
'custom_attributes' => array(
|
||||
'min' => 40,
|
||||
'max' => 55,
|
||||
),
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Set a value from 40 to 55.', 'woocommerce-paypal-payments' ),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'button_checkout-block-express_preview' => array(
|
||||
'type' => 'ppcp-text',
|
||||
'text' => $render_preview_element( 'ppcpCheckoutBlockExpressButtonPreview' ),
|
||||
'screens' => array(
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
|
||||
// Block cart settings.
|
||||
'button_cart-block_heading' => array(
|
||||
'heading' => __( 'Block Cart Buttons', 'woocommerce-paypal-payments' ),
|
||||
'description' => sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__(
|
||||
'Customize the appearance of the PayPal smart buttons on the %1$sBlock Cart%2$s.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#button-on-cart-block" target="_blank">',
|
||||
'</a>'
|
||||
),
|
||||
'type' => 'ppcp-heading',
|
||||
'screens' => array( State::STATE_START, State::STATE_ONBOARDED ),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'button_cart-block_label' => array(
|
||||
'title' => __( 'Button Label', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
/**
|
||||
* Returns default label ID of the PayPal button in block cart.
|
||||
*/
|
||||
'default' => apply_filters( 'woocommerce_paypal_payments_button_cart_block_label_default', 'paypal' ),
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'This controls the label on the primary button.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'options' => array(
|
||||
'paypal' => __( 'PayPal', 'woocommerce-paypal-payments' ),
|
||||
'checkout' => __( 'Checkout', 'woocommerce-paypal-payments' ),
|
||||
'buynow' => __( 'PayPal Buy Now', 'woocommerce-paypal-payments' ),
|
||||
'pay' => __( 'Pay with PayPal', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'button_cart-block_color' => array(
|
||||
'title' => __( 'Color', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'gold',
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'Controls the background color of the primary button. Use "Gold" to leverage PayPal\'s recognition and preference, or change it to match your site design or aesthetic.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'options' => array(
|
||||
'gold' => __( 'Gold (Recommended)', 'woocommerce-paypal-payments' ),
|
||||
'blue' => __( 'Blue', 'woocommerce-paypal-payments' ),
|
||||
'silver' => __( 'Silver', 'woocommerce-paypal-payments' ),
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'button_cart-block_shape' => array(
|
||||
'title' => __( 'Shape', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'rect',
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'The pill-shaped button\'s unique and powerful shape signifies PayPal in people\'s minds. Use the rectangular button as an alternative when pill-shaped buttons might pose design challenges.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'options' => array(
|
||||
'pill' => __( 'Pill', 'woocommerce-paypal-payments' ),
|
||||
'rect' => __( 'Rectangle', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'button_cart-block_height' => array(
|
||||
'title' => __( 'Button Height', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'number',
|
||||
'default' => '48',
|
||||
'custom_attributes' => array(
|
||||
'min' => 40,
|
||||
'max' => 55,
|
||||
),
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Set a value from 40 to 55.', 'woocommerce-paypal-payments' ),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'button_cart-block_preview' => array(
|
||||
'type' => 'ppcp-text',
|
||||
'text' => $render_preview_element( 'ppcpCartBlockButtonPreview' ),
|
||||
'screens' => array(
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
);
|
||||
|
||||
return array_merge( $fields, $smart_button_fields );
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue