Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass Blocks checkout appearance on init WooPay #9075

Merged
merged 10 commits into from
Jul 19, 2024
4 changes: 4 additions & 0 deletions changelog/add-pass-blocks-checkout-appearance-on-init-woopay
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: add

Pass Blocks checkout appearance on init WooPay
4 changes: 4 additions & 0 deletions client/checkout/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
getExpressCheckoutAjaxURL,
getExpressCheckoutConfig,
} from 'utils/express-checkout';
import { getAppearance } from 'checkout/upe-styles';

/**
* Handles generic connections to the server and Stripe.
Expand Down Expand Up @@ -459,8 +460,11 @@ export default class WCPayAPI {
this.isWooPayRequesting = true;
const wcAjaxUrl = getConfig( 'wcAjaxUrl' );
const nonce = getConfig( 'initWooPayNonce' );
const appearance = getAppearance( 'blocks_checkout' );

return this.request( buildAjaxURL( wcAjaxUrl, 'init_woopay' ), {
_wpnonce: nonce,
appearance: appearance,
email: userEmail,
user_session: woopayUserSession,
order_id: getConfig( 'order_id' ),
Expand Down
29 changes: 29 additions & 0 deletions client/checkout/api/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,33 @@ jest.mock( 'wcpay/utils/checkout', () => ( {
getConfig: jest.fn(),
} ) );

const mockAppearance = {
rules: {
'.Block': {},
'.Input': {},
'.Input--invalid': {},
'.Label': {},
'.Tab': {},
'.Tab--selected': {},
'.Tab:hover': {},
'.TabIcon--selected': {
color: undefined,
},
'.TabIcon:hover': {
color: undefined,
},
'.Text': {},
'.Text--redirect': {},
},
theme: 'stripe',
variables: {
colorBackground: '#ffffff',
colorText: undefined,
fontFamily: undefined,
fontSizeBase: undefined,
},
};

describe( 'WCPayAPI', () => {
test( 'does not initialize woopay if already requesting', async () => {
buildAjaxURL.mockReturnValue( 'https://example.org/' );
Expand All @@ -48,6 +75,7 @@ describe( 'WCPayAPI', () => {
getConfig.mockImplementation( ( key ) => {
const mockProperties = {
initWooPayNonce: 'foo',
appearance: mockAppearance,
order_id: 1,
key: 'testkey',
billing_email: '[email protected]',
Expand All @@ -60,6 +88,7 @@ describe( 'WCPayAPI', () => {

expect( request ).toHaveBeenLastCalledWith( 'https://example.org/', {
_wpnonce: 'foo',
appearance: mockAppearance,
email: '[email protected]',
user_session: 'qwerty123',
order_id: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
appendRedirectionParams,
} from '../utils';
import { getTracksIdentity } from 'tracks';
import { getAppearance } from 'wcpay/checkout/upe-styles';

export const expressCheckoutIframe = async ( api, context, emailSelector ) => {
const woopayEmailInput = await getTargetElement( emailSelector );
Expand Down Expand Up @@ -106,6 +107,7 @@ export const expressCheckoutIframe = async ( api, context, emailSelector ) => {
order_id: getConfig( 'order_id' ),
key: getConfig( 'key' ),
billing_email: getConfig( 'billing_email' ),
appearance: getAppearance( 'blocks_checkout' ),
}
).then( ( response ) => {
if ( response?.data?.session ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,32 @@ describe( 'WoopayExpressCheckoutButton', () => {
const mockRequest = jest.fn().mockResolvedValue( true );
const mockAddToCart = jest.fn().mockResolvedValue( true );
const api = new WCPayAPI( {}, mockRequest );
const mockAppearance = {
rules: {
'.Block': {},
'.Input': {},
'.Input--invalid': {},
'.Label': {},
'.Tab': {},
'.Tab--selected': {},
'.Tab:hover': {},
'.TabIcon--selected': {
color: undefined,
},
'.TabIcon:hover': {
color: undefined,
},
'.Text': {},
'.Text--redirect': {},
},
theme: 'stripe',
variables: {
colorBackground: '#ffffff',
colorText: undefined,
fontFamily: undefined,
fontSizeBase: undefined,
},
};

beforeEach( () => {
expressCheckoutIframe.mockImplementation( () => jest.fn() );
Expand Down Expand Up @@ -145,6 +171,8 @@ describe( 'WoopayExpressCheckoutButton', () => {
return 'testkey';
case 'order_id':
return 1;
case 'appearance':
return mockAppearance;
default:
return 'foo';
}
Expand All @@ -170,6 +198,7 @@ describe( 'WoopayExpressCheckoutButton', () => {
order_id: 1,
key: 'testkey',
billing_email: '[email protected]',
appearance: mockAppearance,
} );
expect( expressCheckoutIframe ).not.toHaveBeenCalled();
} );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
deleteSkipWooPayCookie,
} from 'wcpay/checkout/woopay/utils';
import WooPayFirstPartyAuth from 'wcpay/checkout/woopay/express-button/woopay-first-party-auth';
import { getAppearance } from 'wcpay/checkout/upe-styles';

const BUTTON_WIDTH_THRESHOLD = 140;

Expand Down Expand Up @@ -268,6 +269,7 @@ export const WoopayExpressCheckoutButton = ( {
order_id: getConfig( 'order_id' ),
key: getConfig( 'key' ),
billing_email: getConfig( 'billing_email' ),
appearance: getAppearance( 'blocks_checkout' ),
} )
.then( async ( response ) => {
if ( response?.blog_id && response?.data?.session ) {
Expand Down
38 changes: 35 additions & 3 deletions includes/woopay/class-woopay-session.php
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,10 @@ public static function get_frontend_init_session_request() {
$key = ! empty( $_POST['key'] ) ? sanitize_text_field( wp_unslash( $_POST['key'] ) ) : null;
$billing_email = ! empty( $_POST['billing_email'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_email'] ) ) : null;
// phpcs:enable
// phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, Generic.Arrays.DisallowLongArraySyntax.Found
$appearance = ! empty( $_POST['appearance'] ) ? self::array_map_recursive( array( __CLASS__, 'sanitize_string' ), $_POST['appearance'] ) : null;

$session = self::get_init_session_request( $order_id, $key, $billing_email );
$session = self::get_init_session_request( $order_id, $key, $billing_email, null, $appearance );

return WooPay_Utilities::encrypt_and_sign_data( $session );
}
Expand Down Expand Up @@ -416,9 +418,10 @@ private static function get_user_email( $user ) {
* @param string|null $key Pay-for-order key.
* @param string|null $billing_email Pay-for-order billing email.
* @param WP_REST_Request|null $woopay_request The WooPay request object.
* @param array $appearance Merchant appearance.
* @return array The initial session request data without email and user_session.
*/
public static function get_init_session_request( $order_id = null, $key = null, $billing_email = null, $woopay_request = null ) {
public static function get_init_session_request( $order_id = null, $key = null, $billing_email = null, $woopay_request = null, $appearance = null ) {
$user = wp_get_current_user();
$is_pay_for_order = null !== $order_id;
$order = wc_get_order( $order_id );
Expand Down Expand Up @@ -500,6 +503,7 @@ public static function get_init_session_request( $order_id = null, $key = null,
],
],
'tracks_user_identity' => WC_Payments::woopay_tracker()->tracks_get_identity(),
'appearance' => $appearance,
];

$woopay_adapted_extensions = new WooPay_Adapted_Extensions();
Expand All @@ -526,6 +530,33 @@ public static function get_init_session_request( $order_id = null, $key = null,
return $request;
}

/**
* Recursively map an array.
*
* @param callable $callback The sanitize_text_field function.
* @param array $array The nested array.
*
* @return array A new appearance array.
*/
private static function array_map_recursive( $callback, $array ) {
$func = function ( $item ) use ( &$func, &$callback ) {
return is_array( $item ) ? array_map( $func, $item ) : call_user_func( $callback, $item );
};

return array_map( $func, $array );
}

/**
* Sanitize a string.
*
* @param string $item A string.
*
* @return string The sanitized string.
*/
private static function sanitize_string( $item ) {
return sanitize_text_field( wp_unslash( $item ) );
}

/**
* Used to initialize woopay session.
*
Expand All @@ -544,8 +575,9 @@ public static function ajax_init_woopay() {
$order_id = ! empty( $_POST['order_id'] ) ? absint( wp_unslash( $_POST['order_id'] ) ) : null;
$key = ! empty( $_POST['key'] ) ? sanitize_text_field( wp_unslash( $_POST['key'] ) ) : null;
$billing_email = ! empty( $_POST['billing_email'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_email'] ) ) : null;
$appearance = ! empty( $_POST['appearance'] ) ? self::array_map_recursive( array( __CLASS__, 'sanitize_string' ), $_POST['appearance'] ) : null; // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, Generic.Arrays.DisallowLongArraySyntax.Found

$body = self::get_init_session_request( $order_id, $key, $billing_email );
$body = self::get_init_session_request( $order_id, $key, $billing_email, null, $appearance );
$body['user_session'] = isset( $_REQUEST['user_session'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['user_session'] ) ) : null;

$args = [
Expand Down
Loading