changes to mimic google implementation

This commit is contained in:
carmenmaymo 2023-08-31 12:48:01 +02:00
parent 4797d53ad5
commit 63ab1e383d
No known key found for this signature in database
GPG key ID: 6023F686B0F3102E
20 changed files with 724 additions and 216 deletions

View file

@ -27,7 +27,7 @@ return array(
'requirements' => array(),
'gateway' => 'paypal',
);
$fields['applepay_button_enabled_product'] = array(
$fields['applepay_button_enabled'] = array(
'title' => __( 'Apple Pay Button on Product Page', 'woocommerce-paypal-payments' ),
'type' => 'checkbox',
'label' => __( 'Enable Apple Pay button on product page', 'woocommerce-paypal-payments' ),
@ -36,15 +36,6 @@ return array(
'gateway' => 'paypal',
'requirements' => array(),
);
$fields['applepay_button_enabled_cart'] = array(
'title' => __( 'Apple Pay Button on Cart Page', 'woocommerce-paypal-payments' ),
'type' => 'checkbox',
'label' => __( 'Enable Apple Pay button on cart page', 'woocommerce-paypal-payments' ),
'default' => 'yes',
'screens' => array( State::STATE_ONBOARDED ),
'gateway' => 'paypal',
'requirements' => array(),
);
$fields['applepay_live_validation_file'] = array(
'title' => __( 'Apple Pay Live Validation File', 'woocommerce-paypal-payments' ),
'type' => 'textarea',
@ -64,8 +55,6 @@ return array(
'requirements' => array(),
);
return $fields;
},
);

View file

@ -10,6 +10,7 @@
"Edge >= 14"
],
"dependencies": {
"@paypal/paypal-js": "^6.0.0",
"core-js": "^3.25.0"
},
"devDependencies": {

View file

@ -1,6 +1,28 @@
#applepay-container {
margin-top: 0.5rem;
margin-top: 5px;
overflow: hidden;
border-radius: 50px;
height: 45px;
&.ppcp-button-pill {
border-radius: 50px;
}
&.ppcp-button-minicart {
display: block;
height: 40px;
}
}
.woocommerce-checkout {
#applepay-container {
margin-top: 0;
border-radius: 18px;
height: 38px;
}
}
.wp-block-woocommerce-cart, .wp-block-woocommerce-checkout {
#applepay-container {
margin-top: 0;
}
}

View file

@ -0,0 +1,197 @@
import ContextHandlerFactory from "./Context/ContextHandlerFactory";
class ApplepayButton {
constructor(context, externalHandler, buttonConfig, ppcpConfig) {
this.isInitialized = false;
this.context = context;
this.externalHandler = externalHandler;
this.buttonConfig = buttonConfig;
this.ppcpConfig = ppcpConfig;
this.paymentsClient = null;
this.contextHandler = ContextHandlerFactory.create(
this.context,
this.buttonConfig,
this.ppcpConfig
);
}
init(config) {
console.log('[ApplePayButton] init', config);
if (this.isInitialized) {
return;
}
this.isInitialized = true;
this.applePayConfig = config;
this.allowedPaymentMethods = config.allowedPaymentMethods;
this.baseCardPaymentMethod = this.allowedPaymentMethods[0];
this.initClient();
this.paymentsClient.isReadyToPay(
this.buildReadyToPayRequest(this.allowedPaymentMethods, config)
)
.then((response) => {
if (response.result) {
this.addButton(this.baseCardPaymentMethod);
}
})
.catch(function(err) {
console.error(err);
});
}
buildReadyToPayRequest(allowedPaymentMethods, baseRequest) {
return Object.assign({}, baseRequest, {
allowedPaymentMethods: allowedPaymentMethods,
});
}
initClient() {
this.paymentsClient = new apple.payments.api.PaymentsClient({
environment: 'TEST', // TODO: Use 'PRODUCTION' for real transactions
// add merchant info maybe
paymentDataCallbacks: {
//onPaymentDataChanged: onPaymentDataChanged,
onPaymentAuthorized: this.onPaymentAuthorized.bind(this),
}
});
}
/**
* Add a Apple Pay purchase button
*/
addButton(baseCardPaymentMethod) {
console.log('[ApplePayButton] 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;
jQuery(wrapper).addClass('ppcp-button-' + shape);
const button =
this.paymentsClient.createButton({
onClick: this.onButtonClick.bind(this),
allowedPaymentMethods: [baseCardPaymentMethod],
buttonType: 'pay',
buttonSizeMode: 'fill',
});
jQuery(wrapper).append(button);
}
//------------------------
// Button click
//------------------------
/**
* Show Apple Pay payment sheet when Apple Pay payment button is clicked
*/
async onButtonClick() {
console.log('[ApplePayButton] onButtonClick', this.context);
const paymentDataRequest = await this.paymentDataRequest();
console.log('[ApplePayButton] onButtonClick: paymentDataRequest', paymentDataRequest, this.context);
this.paymentsClient.loadPaymentData(paymentDataRequest);
}
async paymentDataRequest() {
let baseRequest = {
apiVersion: 2,
apiVersionMinor: 0
}
const applePayConfig = this.applePayConfig;
const paymentDataRequest = Object.assign({}, baseRequest);
paymentDataRequest.allowedPaymentMethods = applePayConfig.allowedPaymentMethods;
paymentDataRequest.transactionInfo = await this.contextHandler.transactionInfo();
paymentDataRequest.merchantInfo = applePayConfig.merchantInfo;
paymentDataRequest.callbackIntents = ['PAYMENT_AUTHORIZATION'];
return paymentDataRequest;
}
//------------------------
// Payment process
//------------------------
onPaymentAuthorized(paymentData) {
console.log('[ApplePayButton] onPaymentAuthorized', this.context);
return this.processPayment(paymentData);
}
async processPayment(paymentData) {
console.log('[ApplePayButton] processPayment', this.context);
return new Promise(async (resolve, reject) => {
try {
let id = await this.contextHandler.createOrder();
console.log('[ApplePayButton] processPayment: createOrder', id, this.context);
const confirmOrderResponse = await paypal.Applepay().confirmOrder({
orderId: id,
paymentMethodData: paymentData.paymentMethodData
});
console.log('[ApplePayButton] processPayment: confirmOrder', confirmOrderResponse, this.context);
/** Capture the Order on the Server */
if (confirmOrderResponse.status === "APPROVED") {
let approveFailed = false;
await this.contextHandler.approveOrderForContinue({
orderID: id
}, {
restart: () => new Promise((resolve, reject) => {
approveFailed = true;
resolve();
})
});
if (!approveFailed) {
resolve(this.processPaymentResponse('SUCCESS'));
} else {
resolve(this.processPaymentResponse('ERROR', 'PAYMENT_AUTHORIZATION', 'FAILED TO APPROVE'));
}
} else {
resolve(this.processPaymentResponse('ERROR', 'PAYMENT_AUTHORIZATION', 'TRANSACTION FAILED'));
}
} catch(err) {
resolve(this.processPaymentResponse('ERROR', 'PAYMENT_AUTHORIZATION', err.message));
}
});
}
processPaymentResponse(state, intent = null, message = null) {
let response = {
transactionState: state,
}
if (intent || message) {
response.error = {
intent: intent,
message: message,
}
}
console.log('[ApplePayButton] processPaymentResponse', response, this.context);
return response;
}
}
export default ApplepayButton;

View file

@ -0,0 +1,54 @@
import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher";
import ApplepayButton from "./ApplepayButton";
class ApplepayManager {
constructor(buttonConfig, ppcpConfig) {
this.buttonConfig = buttonConfig;
this.ppcpConfig = ppcpConfig;
this.ApplePayConfig = null;
this.buttons = [];
buttonModuleWatcher.watchContextBootstrap((bootstrap) => {
console.log('ApplepayManager.js: buttonModuleWatcher.watchContextBootstrap', bootstrap)
const button = new ApplepayButton(
bootstrap.context,
bootstrap.handler,
buttonConfig,
ppcpConfig,
);
this.buttons.push(button);
if (this.ApplePayConfig) {
button.init(this.ApplePayConfig);
}
});
}
init() {
(async () => {
await this.config();
console.log('ApplepayManager.js: init', this.buttons)
for (const button of this.buttons) {
console.log('ApplepayManager.js: init', button)
button.init(this.ApplePayConfig);
}
})();
}
/**
* Gets ApplePay configuration of the PayPal merchant.
* @returns {Promise<null>}
*/
async config() {
this.ApplePayConfig = await paypal.Applepay().config();
console.log('ApplepayManager.js: config', this.ApplePayConfig)
return this.ApplePayConfig;
}
}
export default ApplepayManager;

View file

@ -0,0 +1,13 @@
import {buttonID} from "./utils";
export const maybeShowButton = () => {
const {ApplePaySession} = window
const applePayMethodElement = document.querySelector(
'#' + buttonID,
)
const canShowButton = applePayMethodElement && (ApplePaySession && ApplePaySession.canMakePayments())
if (!canShowButton) {
console.error('This device does not support Apple Pay');
return false
}
return true
}

View file

@ -0,0 +1,8 @@
export const buttonID = 'applepay-container';
export const endpoints = {
validation: '_apple_pay_validation',
createOrderCart: '_apple_pay_create_order_cart',
createOrderProduct: '_apple_pay_create_order_product',
updateShippingMethod: '_apple_pay_update_shipping_contact',
updateShippingContact: '_apple_pay_update_billing_contact',
}

View file

@ -290,6 +290,12 @@ import {loadPaypalScript} from '../../../ppcp-button/resources/js/modules/Helper
}
})
}
)(window)
)(
{
buttonConfig: window.wc_ppcp_applepay,
ppcpConfig: window.PayPalCommerceGateway,
jQuery: window.jQuery
}
)

View file

@ -0,0 +1,71 @@
import {useEffect, useState} from '@wordpress/element';
import {registerExpressPaymentMethod, registerPaymentMethod} from '@woocommerce/blocks-registry';
import {loadPaypalScript} from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading'
import ApplepayManager from "./ApplepayManager";
import {loadCustomScript} from "@paypal/paypal-js";
const ppcpData = wc.wcSettings.getSetting('ppcp-gateway_data');
const ppcpConfig = ppcpData.scriptData;
const buttonData = wc.wcSettings.getSetting('ppcp-applepay_data');
const buttonConfig = buttonData.scriptData;
if (typeof window.PayPalCommerceGateway === 'undefined') {
window.PayPalCommerceGateway = ppcpConfig;
}
console.log('ppcpData', ppcpData);
console.log('ppcpConfig', ppcpConfig);
console.log('buttonData', buttonData);
console.log('buttonConfig', buttonConfig);
const ApplePayComponent = () => {
console.log('ApplePayComponent render');
const [bootstrapped, setBootstrapped] = useState(false);
const [paypalLoaded, setPaypalLoaded] = useState(false);
const [applePayLoaded, setApplePayLoaded] = useState(false);
const bootstrap = function () {
const manager = new ApplepayManager(buttonConfig, ppcpConfig);
manager.init();
};
useEffect(() => {
// Load ApplePay SDK
loadCustomScript({ url: buttonConfig.sdk_url }).then(() => {
setApplePayLoaded(true);
});
// Load PayPal
loadPaypalScript(ppcpConfig, () => {
setPaypalLoaded(true);
});
}, []);
useEffect(() => {
if (!bootstrapped && paypalLoaded && applePayLoaded) {
setBootstrapped(true);
bootstrap();
}
}, [paypalLoaded, applePayLoaded]);
return (
<div id={buttonConfig.button.wrapper.replace('#', '')}></div>
);
}
const features = ['products'];
let registerMethod = registerExpressPaymentMethod;
registerMethod({
name: buttonData.id,
label: <div dangerouslySetInnerHTML={{__html: buttonData.title}}/>,
content: <ApplePayComponent isEditing={false}/>,
edit: <ApplePayComponent isEditing={true}/>,
ariaLabel: buttonData.title,
canMakePayment: () => buttonData.enabled,
supports: {
features: features,
},
});

View file

@ -0,0 +1,63 @@
import {loadCustomScript} from "@paypal/paypal-js";
import {loadPaypalScript} from "../../../ppcp-button/resources/js/modules/Helper/ScriptLoading";
import ApplepayManager from "./ApplepayManager";
(function ({
buttonConfig,
ppcpConfig,
jQuery
}) {
const bootstrap = function () {
const manager = new ApplepayManager(buttonConfig, ppcpConfig);
manager.init();
};
document.addEventListener(
'DOMContentLoaded',
() => {
if (
(typeof (buttonConfig) === 'undefined') ||
(typeof (ppcpConfig) === 'undefined')
) {
console.error('PayPal button could not be configured.');
return;
}
console.log(buttonConfig.button.wrapper)
// If button wrapper is not present then there is no need to load the scripts.
if (!jQuery(buttonConfig.button.wrapper).length) {
return;
}
let bootstrapped = false;
let paypalLoaded = false;
let applePayLoaded = false;
/* const tryToBoot = () => {
if (!bootstrapped && paypalLoaded && applePayLoaded) {
console.log('Trying to bootstrap')
bootstrapped = true;
bootstrap();
}
}*/
// Load ApplePay SDK
/*loadCustomScript({ url: buttonConfig.sdk_url }).then(() => {
console.log('ApplePay SDK loaded', buttonConfig.sdk_url)
applePayLoaded = true;
//tryToBoot();
});*/
// Load PayPal
loadPaypalScript(ppcpConfig, () => {
paypalLoaded = true;
//tryToBoot();
});
},
);
})({
buttonConfig: window.wc_ppcp_applepay,
ppcpConfig: window.PayPalCommerceGateway,
jQuery: window.jQuery
});

View file

@ -17,20 +17,22 @@ use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
return array(
'apple.status-cache' => static function( ContainerInterface $container ): Cache {
'applepay.status-cache' => static function( ContainerInterface $container ): Cache {
return new Cache( 'ppcp-paypal-apple-status-cache' );
},
'applepay.apple-product-status' => static function( ContainerInterface $container ): AppleProductStatus {
return new AppleProductStatus(
$container->get( 'wcgateway.settings' ),
$container->get( 'api.endpoint.partners' ),
$container->get( 'apple.status-cache' ),
$container->get( 'applepay.status-cache' ),
$container->get( 'onboarding.state' )
);
},
'applepay.enabled' => static function ( ContainerInterface $container ): bool {
$status = $container->get( 'applepay.apple-product-status' );
return $status->apple_is_active();
/*$status = $container->get( 'applepay.apple-product-status' );
assert( $status instanceof AppleProductStatus);
return $status->apple_is_active();*/
return true;
},
'applepay.server_supported' => static function ( ContainerInterface $container ): bool {
return ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off';
@ -59,17 +61,18 @@ return array(
return 'https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js';
},
'applepay.data_to_scripts' => static function ( ContainerInterface $container ): DataToAppleButtonScripts {
$sdk_url = $container->get( 'applepay.sdk_script_url' );
return new DataToAppleButtonScripts($sdk_url);
return new DataToAppleButtonScripts($container->get( 'applepay.sdk_script_url' ));
},
'applepay.button' => static function ( ContainerInterface $container ): ApplePayButton {
$settings = $container->get( 'wcgateway.settings' );
$logger = $container->get( 'woocommerce.logger.woocommerce' );
$order_processor = $container->get( 'wcgateway.order-processor' );
$version = $container->get('ppcp.asset-version');
$module_url = $container->get( 'applepay.url' );
$data = $container->get('applepay.data_to_scripts');
return new ApplePayButton( $settings, $logger, $order_processor, $module_url, $version, $data, $settings );
return new ApplePayButton(
$container->get( 'wcgateway.settings' ),
$container->get( 'woocommerce.logger.woocommerce' ),
$container->get( 'wcgateway.order-processor' ),
$container->get( 'applepay.url' ),
$container->get('ppcp.asset-version'),
$container->get('applepay.data_to_scripts'),
$container->get( 'wcgateway.settings.status' ),
);
},
);

View file

@ -10,7 +10,8 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Applepay;
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
use WooCommerce\PayPalCommerce\ApplePay\Assets\ButtonInterface;
use WooCommerce\PayPalCommerce\Applepay\Assets\AppleProductStatus;
use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface;
use WooCommerce\PayPalCommerce\Onboarding\Environment;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
@ -35,7 +36,7 @@ class ApplepayModule implements ModuleInterface {
* {@inheritDoc}
*/
public function run( ContainerInterface $c ): void {
$apple_payment_method = $c->get( 'applepay.payment_method' );
$apple_payment_method = $c->get( 'applepay.button' );
// add onboarding and referrals hooks.
$apple_payment_method->initialize();
if ( ! $c->get( 'applepay.enabled' ) ) {
@ -80,48 +81,18 @@ class ApplepayModule implements ModuleInterface {
);
}
$this->load_assets( $c );
$env = $c->get( 'onboarding.environment' );
assert( $env instanceof Environment );
$is_sandobx = $env->current_environment_is( Environment::SANDBOX );
$this->load_domain_association_file( $is_sandobx );
$this->handle_validation_file($c);
$this->render_buttons( $c );
$apple_payment_method->bootstrap_ajax_request();
add_filter(
'woocommerce_paypal_payments_sdk_components_hook',
function( $components ) {
$components[] = 'applepay';
return $components;
/*add_action(
'woocommerce_blocks_payment_method_type_registration',
function( PaymentMethodRegistry $payment_method_registry ) use ( $c ): void {
$payment_method_registry->register( $c->get( 'googlepay.blocks-payment-method' ) );
}
);
add_action(
'woocommerce_paypal_payments_gateway_migrate_on_update',
static function() use ( $c ) {
$apple_status_cache = $c->get( 'apple.status-cache' );
assert( $apple_status_cache instanceof Cache );
);*/
$apple_status_cache->delete( AppleProductStatus::APPLE_STATUS_CACHE_KEY );
$settings = $c->get( 'wcgateway.settings' );
$settings->set( 'products_apple_enabled', false );
$settings->persist();
// Update caches.
$apple_status = $c->get( 'applepay.apple-product-status' );
assert( $apple_status instanceof AppleProductStatus );
$apple_status->apple_is_active();
}
);
add_action(
'woocommerce_paypal_payments_on_listening_request',
static function() use ( $c ) {
$apple_status = $c->get( 'applepay.apple-product-status' );
if ( $apple_status->has( AppleProductStatus::APPLE_STATUS_CACHE_KEY ) ) {
$apple_status->delete( AppleProductStatus::APPLE_STATUS_CACHE_KEY );
}
}
);
$this->remove_status_cache($c);
}
/**
@ -196,4 +167,52 @@ class ApplepayModule implements ModuleInterface {
}
);
}
/**
* @param ContainerInterface $c
* @return void
*/
public function remove_status_cache(ContainerInterface $c): void
{
add_action(
'woocommerce_paypal_payments_gateway_migrate_on_update',
static function () use ($c) {
$apple_status_cache = $c->get('applepay.status-cache');
assert($apple_status_cache instanceof Cache);
$apple_status_cache->delete(AppleProductStatus::APPLE_STATUS_CACHE_KEY);
$settings = $c->get('wcgateway.settings');
$settings->set('products_apple_enabled', false);
$settings->persist();
// Update caches.
$apple_status = $c->get('applepay.apple-product-status');
assert($apple_status instanceof AppleProductStatus);
$apple_status->apple_is_active();
}
);
add_action(
'woocommerce_paypal_payments_on_listening_request',
static function () use ($c) {
$apple_status = $c->get('applepay.status-cache');
if ($apple_status->has(AppleProductStatus::APPLE_STATUS_CACHE_KEY)) {
$apple_status->delete(AppleProductStatus::APPLE_STATUS_CACHE_KEY);
}
}
);
}
/**
* @param ContainerInterface $c
* @return void
*/
public function handle_validation_file(ContainerInterface $c): void
{
$env = $c->get('onboarding.environment');
assert($env instanceof Environment);
$is_sandobx = $env->current_environment_is(Environment::SANDBOX);
$this->load_domain_association_file($is_sandobx);
}
}

View file

@ -9,6 +9,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Applepay\Assets;
use Exception;
use Psr\Log\LoggerInterface;
use WC_Cart;
use WC_Checkout;
@ -16,10 +17,12 @@ use WC_Order;
use WC_Session_Handler;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface;
use WooCommerce\PayPalCommerce\Session\MemoryWcSession;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\Webhooks\Handler\RequestHandlerTrait;
@ -79,9 +82,15 @@ class ApplePayButton implements ButtonInterface {
*/
private $module_url;
/**
* @var string
* @var DataToAppleButtonScripts
*/
private $script_data;
/**
* The Settings status helper.
*
* @var SettingsStatus
*/
private $settings_status;
/**
* PayPalPaymentMethod constructor.
@ -96,7 +105,8 @@ class ApplePayButton implements ButtonInterface {
OrderProcessor $order_processor,
string $module_url,
string $version,
DataToAppleButtonScripts $data
DataToAppleButtonScripts $data,
SettingsStatus $settings_status
) {
$this->settings = $settings;
$this->response_templates = new ResponsesToApple();
@ -107,6 +117,7 @@ class ApplePayButton implements ButtonInterface {
$this->module_url = $module_url;
$this->version = $version;
$this->script_data = $data;
$this->settings_status = $settings_status;
}
/**
@ -808,35 +819,87 @@ class ApplePayButton implements ButtonInterface {
public function render_buttons(): bool
{
$button_enabled_product = $this->settings->has( 'applepay_button_enabled_product' ) ? $this->settings->get( 'applepay_button_enabled_product' ) : false;
$button_enabled_cart = $this->settings->has( 'applepay_button_enabled_cart' ) ? $this->settings->get( 'applepay_button_enabled_cart' ) : false;
$is_applepay_button_enabled = $this->settings->has( 'applepay_button_enabled' ) ? $this->settings->get( 'applepay_button_enabled' ) : false;
$button_enabled_product = $is_applepay_button_enabled && $this->settings_status->is_smart_button_enabled_for_location( 'product' );
$button_enabled_cart = $is_applepay_button_enabled && $this->settings_status->is_smart_button_enabled_for_location( 'cart' );
$button_enabled_checkout = $is_applepay_button_enabled;
$button_enabled_payorder = $is_applepay_button_enabled;
$button_enabled_minicart = $is_applepay_button_enabled && $this->settings_status->is_smart_button_enabled_for_location( 'mini-cart' );
add_filter(
'woocommerce_paypal_payments_sdk_components_hook',
function( $components ) {
$components[] = 'applepay';
return $components;
}
);
if ( $button_enabled_product ) {
$render_placeholder = apply_filters( 'woocommerce_paypal_payments_applepay_render_hook_product', 'woocommerce_after_add_to_cart_form' );
$render_placeholder = is_string( $render_placeholder ) ? $render_placeholder : 'woocommerce_after_add_to_cart_form';
$default_hookname = 'woocommerce_paypal_payments_single_product_button_render';
$render_placeholder = apply_filters( 'woocommerce_paypal_payments_applepay_render_hook_product', $default_hookname );
$render_placeholder = is_string( $render_placeholder ) ? $render_placeholder : $default_hookname;
add_action(
$render_placeholder,
function () {
$this->apple_pay_direct_button();
$this->applepay_button();
}
);
}
if ( $button_enabled_cart ) {
$render_placeholder = apply_filters( 'woocommerce_paypal_payments_applepay_render_hook_cart', 'woocommerce_cart_totals_after_order_total' );
$render_placeholder = is_string( $render_placeholder ) ? $render_placeholder : 'woocommerce_cart_totals_after_order_total';
$default_hook_name = 'woocommerce_paypal_payments_cart_button_render';
$render_placeholder = apply_filters( 'woocommerce_paypal_payments_googlepay_cart_button_render_hook', $default_hook_name );
$render_placeholder = is_string( $render_placeholder ) ? $render_placeholder : $default_hook_name;
add_action(
$render_placeholder,
function () {
$this->apple_pay_direct_button();
$this->applepay_button();
}
);
}
if ( $button_enabled_checkout ) {
$default_hook_name = 'woocommerce_paypal_payments_checkout_button_render';
$render_placeholder = apply_filters( 'woocommerce_paypal_payments_googlepay_checkout_button_render_hook', $default_hook_name );
$render_placeholder = is_string( $render_placeholder ) ? $render_placeholder : $default_hook_name;
add_action(
$render_placeholder,
function () {
$this->applepay_button();
},
21
);
}
if ( $button_enabled_payorder ) {
$default_hook_name = 'woocommerce_paypal_payments_payorder_button_render';
$render_placeholder = apply_filters( 'woocommerce_paypal_payments_googlepay_payorder_button_render_hook', $default_hook_name );
$render_placeholder = is_string( $render_placeholder ) ? $render_placeholder : $default_hook_name;
add_action(
$render_placeholder,
function () {
$this->applepay_button();
},
21
);
}
if ( $button_enabled_minicart ) {
$default_hook_name = 'woocommerce_paypal_payments_minicart_button_render';
$render_placeholder = apply_filters( 'woocommerce_paypal_payments_googlepay_minicart_button_render_hook', $default_hook_name );
$render_placeholder = is_string( $render_placeholder ) ? $render_placeholder : $default_hook_name;
add_action(
$render_placeholder,
function () {
echo '<span id="applepay-container-minicart" class="ppcp-button-applepay ppcp-button-minicart"></span>';
},
21
);
}
return true;
}
/**
* ApplePay button markup
*/
protected function apple_pay_direct_button(): void {
protected function applepay_button(): void {
?>
<div class="ppc-button-wrapper">
<div id="applepay-container">
@ -855,7 +918,7 @@ class ApplePayButton implements ButtonInterface {
{
wp_register_script(
'wc-ppcp-applepay',
untrailingslashit( $this->module_url ) . '/assets/js/applePayDirect.js',
untrailingslashit( $this->module_url ) . '/assets/js/boot.js',
array(),
$this->version,
true

View file

@ -0,0 +1,114 @@
<?php
/**
* The applepay blocks module.
*
* @package WooCommerce\PayPalCommerce\Applepay
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Applepay\Assets;
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodTypeInterface;
use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface;
/**
* Class BlocksPaymentMethod
*/
class BlocksPaymentMethod extends AbstractPaymentMethodType {
/**
* The URL of this module.
*
* @var string
*/
private $module_url;
/**
* The assets version.
*
* @var string
*/
private $version;
/**
* The button.
*
* @var ButtonInterface
*/
private $button;
/**
* The paypal payment method.
*
* @var PaymentMethodTypeInterface
*/
private $paypal_payment_method;
/**
* Assets constructor.
*
* @param string $name The name of this module.
* @param string $module_url The url of this module.
* @param string $version The assets version.
* @param ButtonInterface $button The button.
* @param PaymentMethodTypeInterface $paypal_payment_method The paypal payment method.
*/
public function __construct(
string $name,
string $module_url,
string $version,
ButtonInterface $button,
PaymentMethodTypeInterface $paypal_payment_method
) {
$this->name = $name;
$this->module_url = $module_url;
$this->version = $version;
$this->button = $button;
$this->paypal_payment_method = $paypal_payment_method;
}
/**
* {@inheritDoc}
*/
public function initialize() { }
/**
* {@inheritDoc}
*/
public function is_active() {
return $this->paypal_payment_method->is_active();
}
/**
* {@inheritDoc}
*/
public function get_payment_method_script_handles() {
$handle = $this->name . '-block';
wp_register_script(
$handle,
trailingslashit( $this->module_url ) . 'assets/js/boot-block.js',
array(),
$this->version,
true
);
return array( $handle );
}
/**
* {@inheritDoc}
*/
public function get_payment_method_data() {
$paypal_data = $this->paypal_payment_method->get_payment_method_data();
return array(
'id' => $this->name,
'title' => $paypal_data['title'], // TODO : see if we should use another.
'description' => $paypal_data['description'], // TODO : see if we should use another.
'enabled' => $paypal_data['enabled'], // This button is enabled when PayPal buttons are.
'scriptData' => $this->button->script_data(),
);
}
}

View file

@ -1,40 +0,0 @@
<?php
/**
* The interface for the smart button asset renderer.
*
* @package WooCommerce\PayPalCommerce\Button\Assets
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApplePay\Assets;
/**
* Interface SmartButtonInterface
*/
interface ButtonInterface {
/**
* Renders the necessary HTML.
*
* @return bool
*/
public function render_buttons(): bool;
/**
* Whether any of the scripts should be loaded.
*/
public function should_load_script(): bool;
/**
* Enqueues scripts/styles.
*/
public function enqueue(): void;
/**
* The configuration for the smart buttons.
*
* @return array
*/
public function script_data(): array;
}

View file

@ -106,6 +106,10 @@ class DataToAppleButtonScripts {
return array(
'sdk_url' => $this->sdk_url,
'button' => array(
'wrapper' => '#applepay-container',
'mini_cart_wrapper' => '#applepay-container-minicart',
),
'product' => array(
'needShipping' => $product_need_shipping,
'id' => $product_id,

View file

@ -9,7 +9,8 @@ module.exports = {
target: 'web',
plugins: [ new DependencyExtractionWebpackPlugin() ],
entry: {
'applepayDirect': path.resolve('./resources/js/applepayDirect.js'),
'boot': path.resolve('./resources/js/boot.js'),
'boot-block': path.resolve('./resources/js/boot-block.js'),
"styles": path.resolve('./resources/css/styles.scss')
},
output: {

View file

@ -963,7 +963,7 @@
resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
"@babel/runtime@^7.13.10", "@babel/runtime@^7.16.0", "@babel/runtime@^7.8.4":
"@babel/runtime@^7.8.4":
version "7.22.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438"
integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==
@ -1059,6 +1059,13 @@
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz#ea6d23ade78a325f7a52750aab1526b02b628c29"
integrity sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==
"@paypal/paypal-js@^6.0.0":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@paypal/paypal-js/-/paypal-js-6.0.1.tgz#5d68d5863a5176383fee9424bc944231668fcffd"
integrity sha512-bvYetmkg2GEC6onsUJQx1E9hdAJWff2bS3IPeiZ9Sh9U7h26/fIgMKm240cq/908sbSoDjHys75XXd8at9OpQA==
dependencies:
promise-polyfill "^8.3.0"
"@types/eslint-scope@^3.7.3":
version "3.7.4"
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16"
@ -1090,32 +1097,6 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.3.tgz#329842940042d2b280897150e023e604d11657d6"
integrity sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==
"@types/prop-types@*":
version "15.7.5"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
"@types/react-dom@^16.9.0":
version "16.9.19"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.19.tgz#6a139c26b02dec533a7fa131f084561babb10a8f"
integrity sha512-xC8D280Bf6p0zguJ8g62jcEOKZiUbx9sIe6O3tT/lKfR87A7A6g65q13z6D5QUMIa/6yFPkNhqjF5z/VVZEYqQ==
dependencies:
"@types/react" "^16"
"@types/react@^16", "@types/react@^16.9.0":
version "16.14.43"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.43.tgz#bc6e7a0e99826809591d38ddf1193955de32c446"
integrity sha512-7zdjv7jvoLLQg1tTvpQsm+hyNUMT2mPlNV1+d0I8fbGhkJl82spopMyBlu4wb1dviZAxpGdk5eHu/muacknnfw==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/scheduler@*":
version "0.16.3"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"
@ -1269,26 +1250,6 @@
json2php "^0.0.4"
webpack-sources "^3.2.2"
"@wordpress/element@^3.0.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@wordpress/element/-/element-3.2.0.tgz#531720b3a023a1509f13d2464b2e1d670153116e"
integrity sha512-YXJhtBF8FnFYwA9X6Dvs4k6yJf5wy1lhU04VNJVzoUDwCt/pK747RGePIPDdUWVd3X/TlyNH2yLRtcCyOC/SzQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@types/react" "^16.9.0"
"@types/react-dom" "^16.9.0"
"@wordpress/escape-html" "^2.2.0"
lodash "^4.17.21"
react "^17.0.1"
react-dom "^17.0.1"
"@wordpress/escape-html@^2.2.0":
version "2.38.0"
resolved "https://registry.yarnpkg.com/@wordpress/escape-html/-/escape-html-2.38.0.tgz#72dd11ba66e26498b4379a4d8b7d020ba26d879b"
integrity sha512-q7wg1JvXVPpyddMnEl6A8ALn9U3mA4LvyQpkDNLonntU+Q8JbvW1r91HdzoFh396rHoNJWGzDGORUTlDlb5jOw==
dependencies:
"@babel/runtime" "^7.16.0"
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
@ -1513,11 +1474,6 @@ cross-spawn@^7.0.1, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"
csstype@^3.0.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
debug@^4.1.0, debug@^4.1.1:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
@ -1774,7 +1730,7 @@ jest-worker@^27.4.5:
merge-stream "^2.0.0"
supports-color "^8.0.0"
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
@ -1845,18 +1801,6 @@ lodash.debounce@^4.0.8:
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
@ -1908,11 +1852,6 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
p-limit@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
@ -1964,6 +1903,11 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0:
dependencies:
find-up "^4.0.0"
promise-polyfill@^8.3.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.3.0.tgz#9284810268138d103807b11f4e23d5e945a4db63"
integrity sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==
punycode@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
@ -1976,23 +1920,6 @@ randombytes@^2.1.0:
dependencies:
safe-buffer "^5.1.0"
react-dom@^17.0.1:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler "^0.20.2"
react@^17.0.1:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
@ -2093,14 +2020,6 @@ sass@^1.42.1:
immutable "^4.0.0"
source-map-js ">=0.6.2 <2.0.0"
scheduler@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
schema-utils@^2.6.5:
version "2.7.1"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"

View file

@ -7,6 +7,7 @@ class ButtonModuleWatcher {
}
watchContextBootstrap(callable) {
console.log('ButtonModuleWatcher.js: watchContextBootstrap', this.contextBootstrapRegistry)
this.contextBootstrapWatchers.push(callable);
Object.values(this.contextBootstrapRegistry).forEach(callable);
}

View file

@ -26,7 +26,7 @@ export const loadPaypalScript = (config, onLoaded) => {
return;
}
options.isLoading = true;
console.log('ScriptLoading.js: loadPaypalScript', config)
// Arm a timeout so the module isn't locked on isLoading state on failure.
let loadingTimeout = setTimeout(() => {
console.error('Failed to load PayPal script.');