diff --git a/modules/ppcp-blocks/package.json b/modules/ppcp-blocks/package.json
index 4958d3648..993b115e3 100644
--- a/modules/ppcp-blocks/package.json
+++ b/modules/ppcp-blocks/package.json
@@ -10,7 +10,7 @@
"Edge >= 14"
],
"dependencies": {
- "@paypal/react-paypal-js": "^8.2.0",
+ "@paypal/react-paypal-js": "^8.3.0",
"core-js": "^3.25.0",
"react": "^17.0.0",
"react-dom": "^17.0.0"
diff --git a/modules/ppcp-blocks/resources/js/Components/card-fields.js b/modules/ppcp-blocks/resources/js/Components/card-fields.js
new file mode 100644
index 000000000..f7ff6c7e0
--- /dev/null
+++ b/modules/ppcp-blocks/resources/js/Components/card-fields.js
@@ -0,0 +1,79 @@
+import {useEffect, useState} from '@wordpress/element';
+
+import {
+ PayPalScriptProvider,
+ PayPalCardFieldsProvider,
+ PayPalCardFieldsForm,
+} from "@paypal/react-paypal-js";
+
+import {CheckoutHandler} from "./checkout-handler";
+import {createOrder, onApprove} from "../card-fields-config";
+import {cartHasSubscriptionProducts} from "../Helper/Subscription";
+
+export function CardFields({config, eventRegistration, emitResponse, components}) {
+ const {onPaymentSetup} = eventRegistration;
+ const {responseTypes} = emitResponse;
+ const { PaymentMethodIcons } = components;
+
+ const [cardFieldsForm, setCardFieldsForm] = useState();
+ const getCardFieldsForm = (cardFieldsForm) => {
+ setCardFieldsForm(cardFieldsForm)
+ }
+
+ const getSavePayment = (savePayment) => {
+ localStorage.setItem('ppcp-save-card-payment', savePayment);
+ }
+
+ const hasSubscriptionProducts = cartHasSubscriptionProducts(config.scriptData);
+
+ useEffect(
+ () =>
+ onPaymentSetup(() => {
+ async function handlePaymentProcessing() {
+ await cardFieldsForm.submit()
+ .catch((error) => {
+ return {
+ type: responseTypes.ERROR,
+ }
+ });
+
+ return {
+ type: responseTypes.SUCCESS,
+ }
+ }
+
+ return handlePaymentProcessing();
+ }),
+ [onPaymentSetup, cardFieldsForm]
+ );
+
+ return (
+ <>
+
+ {
+ console.error(err);
+ }}
+ >
+
+
+
+
+
+ >
+ )
+}
diff --git a/modules/ppcp-blocks/resources/js/Components/checkout-handler.js b/modules/ppcp-blocks/resources/js/Components/checkout-handler.js
new file mode 100644
index 000000000..48dd0602d
--- /dev/null
+++ b/modules/ppcp-blocks/resources/js/Components/checkout-handler.js
@@ -0,0 +1,28 @@
+import {useEffect} from '@wordpress/element';
+import {usePayPalCardFields} from "@paypal/react-paypal-js";
+
+export const CheckoutHandler = ({getCardFieldsForm, getSavePayment, hasSubscriptionProducts, saveCardText, is_vaulting_enabled}) => {
+ const {cardFieldsForm} = usePayPalCardFields();
+
+ useEffect(() => {
+ getCardFieldsForm(cardFieldsForm)
+ }, []);
+
+ if (!is_vaulting_enabled) {
+ return null;
+ }
+
+ return (
+ <>
+ getSavePayment(e.target.checked)}
+ defaultChecked={hasSubscriptionProducts}
+ disabled={hasSubscriptionProducts}
+ />
+
+ >
+ )
+}
diff --git a/modules/ppcp-blocks/resources/js/advanced-card-checkout-block.js b/modules/ppcp-blocks/resources/js/advanced-card-checkout-block.js
new file mode 100644
index 000000000..6d268c122
--- /dev/null
+++ b/modules/ppcp-blocks/resources/js/advanced-card-checkout-block.js
@@ -0,0 +1,17 @@
+import { registerPaymentMethod } from '@woocommerce/blocks-registry';
+import {CardFields} from "./Components/card-fields";
+
+const config = wc.wcSettings.getSetting('ppcp-credit-card-gateway_data');
+
+registerPaymentMethod({
+ name: config.id,
+ label:
,
+ content: ,
+ edit: ,
+ ariaLabel: config.title,
+ canMakePayment: () => {return true},
+ supports: {
+ showSavedCards: true,
+ features: config.supports
+ }
+})
diff --git a/modules/ppcp-blocks/resources/js/card-fields-config.js b/modules/ppcp-blocks/resources/js/card-fields-config.js
new file mode 100644
index 000000000..37d939a5f
--- /dev/null
+++ b/modules/ppcp-blocks/resources/js/card-fields-config.js
@@ -0,0 +1,44 @@
+const config = wc.wcSettings.getSetting('ppcp-credit-card-gateway_data');
+
+export async function createOrder() {
+ return fetch(config.scriptData.ajax.create_order.endpoint, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ nonce: config.scriptData.ajax.create_order.nonce,
+ context: config.scriptData.context,
+ payment_method: 'ppcp-credit-card-gateway',
+ save_payment_method: localStorage.getItem('ppcp-save-card-payment') === 'true',
+ }),
+ })
+ .then((response) => response.json())
+ .then((order) => {
+ return order.data.id;
+ })
+ .catch((err) => {
+ console.error(err);
+ });
+}
+
+export async function onApprove(data) {
+ return fetch(config.scriptData.ajax.approve_order.endpoint, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ order_id: data.orderID,
+ nonce: config.scriptData.ajax.approve_order.nonce,
+ }),
+ })
+ .then((response) => response.json())
+ .then((data) => {
+ console.log(data)
+ localStorage.removeItem('ppcp-save-card-payment');
+ })
+ .catch((err) => {
+ console.error(err);
+ });
+}
diff --git a/modules/ppcp-blocks/services.php b/modules/ppcp-blocks/services.php
index a841e97b9..21a97f984 100644
--- a/modules/ppcp-blocks/services.php
+++ b/modules/ppcp-blocks/services.php
@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Blocks;
+use WooCommerce\PayPalCommerce\Blocks\Endpoint\GetPayPalOrderFromSession;
use WooCommerce\PayPalCommerce\Blocks\Endpoint\UpdateShippingEndpoint;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
@@ -45,6 +46,17 @@ return array(
$container->get( 'wcgateway.all-funding-sources' )
);
},
+ 'blocks.advanced-card-method' => static function( ContainerInterface $container ): AdvancedCardPaymentMethod {
+ return new AdvancedCardPaymentMethod(
+ $container->get( 'blocks.url' ),
+ $container->get( 'ppcp.asset-version' ),
+ $container->get( 'wcgateway.credit-card-gateway' ),
+ function () use ( $container ): SmartButtonInterface {
+ return $container->get( 'button.smart-button' );
+ },
+ $container->get( 'wcgateway.settings' )
+ );
+ },
'blocks.settings.final_review_enabled' => static function ( ContainerInterface $container ): bool {
$settings = $container->get( 'wcgateway.settings' );
assert( $settings instanceof ContainerInterface );
diff --git a/modules/ppcp-blocks/src/AdvancedCardPaymentMethod.php b/modules/ppcp-blocks/src/AdvancedCardPaymentMethod.php
new file mode 100644
index 000000000..2c6fd60f4
--- /dev/null
+++ b/modules/ppcp-blocks/src/AdvancedCardPaymentMethod.php
@@ -0,0 +1,142 @@
+name = CreditCardGateway::ID;
+ $this->module_url = $module_url;
+ $this->version = $version;
+ $this->gateway = $gateway;
+ $this->smart_button = $smart_button;
+ $this->settings = $settings;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function initialize() {}
+
+ /**
+ * {@inheritDoc}
+ */
+ public function is_active() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function get_payment_method_script_handles() {
+ wp_register_script(
+ 'ppcp-advanced-card-checkout-block',
+ trailingslashit( $this->module_url ) . 'assets/js/advanced-card-checkout-block.js',
+ array(),
+ $this->version,
+ true
+ );
+
+ return array( 'ppcp-advanced-card-checkout-block' );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function get_payment_method_data() {
+ $script_data = $this->smart_button_instance()->script_data();
+
+ return array(
+ 'id' => $this->name,
+ 'title' => $this->gateway->title,
+ 'description' => $this->gateway->description,
+ 'scriptData' => $script_data,
+ 'supports' => $this->gateway->supports,
+ 'save_card_text' => esc_html__( 'Save your card', 'woocommerce-paypal-payments' ),
+ 'is_vaulting_enabled' => $this->settings->has( 'vault_enabled_dcc' ) && $this->settings->get( 'vault_enabled_dcc' ),
+ 'card_icons' => $this->settings->has( 'card_icons' ) ? (array) $this->settings->get( 'card_icons' ) : array(),
+ );
+ }
+
+ /**
+ * The smart button.
+ *
+ * @return SmartButtonInterface
+ */
+ private function smart_button_instance(): SmartButtonInterface {
+ if ( $this->smart_button instanceof SmartButtonInterface ) {
+ return $this->smart_button;
+ }
+
+ if ( is_callable( $this->smart_button ) ) {
+ $this->smart_button = ( $this->smart_button )();
+ }
+
+ return $this->smart_button;
+ }
+}
diff --git a/modules/ppcp-blocks/src/BlocksModule.php b/modules/ppcp-blocks/src/BlocksModule.php
index 2599e75fa..1dd1560dd 100644
--- a/modules/ppcp-blocks/src/BlocksModule.php
+++ b/modules/ppcp-blocks/src/BlocksModule.php
@@ -61,6 +61,7 @@ class BlocksModule implements ModuleInterface {
'woocommerce_blocks_payment_method_type_registration',
function( PaymentMethodRegistry $payment_method_registry ) use ( $c ): void {
$payment_method_registry->register( $c->get( 'blocks.method' ) );
+ $payment_method_registry->register( $c->get( 'blocks.advanced-card-method' ) );
}
);
diff --git a/modules/ppcp-blocks/webpack.config.js b/modules/ppcp-blocks/webpack.config.js
index bdf508fba..44ab3e68f 100644
--- a/modules/ppcp-blocks/webpack.config.js
+++ b/modules/ppcp-blocks/webpack.config.js
@@ -10,6 +10,7 @@ module.exports = {
plugins: [ new DependencyExtractionWebpackPlugin() ],
entry: {
'checkout-block': path.resolve('./resources/js/checkout-block.js'),
+ 'advanced-card-checkout-block': path.resolve('./resources/js/advanced-card-checkout-block.js'),
"gateway": path.resolve('./resources/css/gateway.scss')
},
output: {
diff --git a/modules/ppcp-blocks/yarn.lock b/modules/ppcp-blocks/yarn.lock
index ff731f5b7..1e812a4ae 100644
--- a/modules/ppcp-blocks/yarn.lock
+++ b/modules/ppcp-blocks/yarn.lock
@@ -1005,19 +1005,19 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
-"@paypal/paypal-js@^8.0.4":
- version "8.0.4"
- resolved "https://registry.yarnpkg.com/@paypal/paypal-js/-/paypal-js-8.0.4.tgz#abe9f40f519b1d2c306adddfbe733be03eb26ce5"
- integrity sha512-91g5fhRBHGEBoikDzQT6uBn3PzlJQ75g0c3MvqVJqN0XRm5kHa9wz+6+Uaq8QQuxRzz5C2x55Zg057CW6EuwpQ==
+"@paypal/paypal-js@^8.0.5":
+ version "8.0.5"
+ resolved "https://registry.yarnpkg.com/@paypal/paypal-js/-/paypal-js-8.0.5.tgz#77bc461b4d1e5a2c6f081269e3ef0b2e3331a68c"
+ integrity sha512-yQNV7rOILeaVCNU4aVDRPqEnbIlzfxgQfFsxzsBuZW1ouqRD/4kYBWJDzczCiscSr2xOeA/Pkm7e3a9fRfnuMQ==
dependencies:
promise-polyfill "^8.3.0"
-"@paypal/react-paypal-js@^8.2.0":
- version "8.2.0"
- resolved "https://registry.yarnpkg.com/@paypal/react-paypal-js/-/react-paypal-js-8.2.0.tgz#4b1a142bbb68e62dca4a92da4a6b5568f54901f0"
- integrity sha512-SworUfu0BNNcqoh0O53Ke4MFpx2m3qJRu3hayXvlluEEXJpKqGSV5aaSGFhbsZqi8hnbsx/hZR7BQbmqsggiGQ==
+"@paypal/react-paypal-js@^8.3.0":
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/@paypal/react-paypal-js/-/react-paypal-js-8.3.0.tgz#a103080b752766b8ff59b8620887abf802e1a01b"
+ integrity sha512-SX17d2h1CMNFGI+wtjb329AEDaBR8Ziy2LCV076eDcY1Q0MFKRkfQ/v0HOAvZtk3sJoydRmYez2pq47BRblwqQ==
dependencies:
- "@paypal/paypal-js" "^8.0.4"
+ "@paypal/paypal-js" "^8.0.5"
"@paypal/sdk-constants" "^1.0.122"
"@paypal/sdk-constants@^1.0.122":
diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php
index 7d6909c2e..7925633cc 100644
--- a/modules/ppcp-button/src/Assets/SmartButton.php
+++ b/modules/ppcp-button/src/Assets/SmartButton.php
@@ -1421,7 +1421,7 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
$disable_funding,
array_diff(
array_keys( $this->all_funding_sources ),
- array( 'venmo', 'paylater', 'paypal' )
+ array( 'venmo', 'paylater', 'paypal', 'card' )
)
);
}
diff --git a/modules/ppcp-card-fields/src/CardFieldsModule.php b/modules/ppcp-card-fields/src/CardFieldsModule.php
index 6835108c3..b499891a0 100644
--- a/modules/ppcp-card-fields/src/CardFieldsModule.php
+++ b/modules/ppcp-card-fields/src/CardFieldsModule.php
@@ -105,9 +105,8 @@ class CardFieldsModule implements ModuleInterface {
add_filter(
'ppcp_create_order_request_body_data',
- function( array $data ) use ( $c ): array {
+ function( array $data, string $payment_method ) use ( $c ): array {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
- $payment_method = wc_clean( wp_unslash( $_POST['payment_method'] ?? '' ) );
if ( $payment_method !== CreditCardGateway::ID ) {
return $data;
}
@@ -134,7 +133,9 @@ class CardFieldsModule implements ModuleInterface {
}
return $data;
- }
+ },
+ 10,
+ 2
);
}
}