diff --git a/plugins/woocommerce-blocks/assets/js/base/components/button/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/button/style.scss index fb6b57a0f1f..7fd81991e3d 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/button/style.scss +++ b/plugins/woocommerce-blocks/assets/js/base/components/button/style.scss @@ -32,6 +32,12 @@ } } + &:disabled { + .wc-block-components-button__text { + opacity: 0.5; + } + } + &.outlined { background: transparent; color: currentColor; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/index.js b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/index.js index a8849e5df8f..3a068a8718f 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/index.js +++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/index.js @@ -18,4 +18,5 @@ export { default as ShippingRatesControlPackage } from './shipping-rates-control export { default as PaymentMethodIcons } from './payment-method-icons'; export { default as PaymentMethodLabel } from './payment-method-label'; export { default as AdditionalFieldsPlaceholder } from './additional-fields-placeholder'; +export { default as PasswordStrengthMeter } from './password-strength-meter'; export * from './totals'; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/password-strength-meter/index.tsx b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/password-strength-meter/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/checkout/password-strength-meter/index.tsx rename to plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/password-strength-meter/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/password-strength-meter/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/password-strength-meter/style.scss similarity index 98% rename from plugins/woocommerce-blocks/assets/js/blocks/checkout/password-strength-meter/style.scss rename to plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/password-strength-meter/style.scss index ffa5f7652d7..10bdc64f939 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/password-strength-meter/style.scss +++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/password-strength-meter/style.scss @@ -60,7 +60,7 @@ } .wc-block-components-password-strength__meter[value="2"], .wc-block-components-password-strength__meter[value="2"] + .wc-block-components-password-strength__result { - color: #ff6f00; + color: $alert-red; } .wc-block-components-password-strength__meter[value="3"], .wc-block-components-password-strength__meter[value="3"] + .wc-block-components-password-strength__result { diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-contact-information-block/create-password.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-contact-information-block/create-password.tsx index 68e4b2b85df..ba874e14e13 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-contact-information-block/create-password.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-contact-information-block/create-password.tsx @@ -6,11 +6,7 @@ import { useState } from '@wordpress/element'; import { ValidatedTextInput } from '@woocommerce/blocks-components'; import { useDispatch, useSelect } from '@wordpress/data'; import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data'; - -/** - * Internal dependencies - */ -import PasswordStrengthMeter from '../../password-strength-meter'; +import PasswordStrengthMeter from '@woocommerce/base-components/cart-checkout/password-strength-meter'; const CreatePassword = () => { const [ passwordStrength, setPasswordStrength ] = useState( 0 ); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/block.json new file mode 100644 index 00000000000..9f2fb19cd51 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/block.json @@ -0,0 +1,56 @@ +{ + "name": "woocommerce/order-confirmation-create-account", + "version": "1.0.0", + "title": "Account Creation", + "description": "Allow customers to create an account after their purchase. Configure this feature in your store settings.", + "category": "woocommerce", + "keywords": [ + "WooCommerce" + ], + "attributes": { + "customerEmail": { + "type": "string", + "default": "" + }, + "nonceToken": { + "type": "string", + "default": "" + }, + "align": { + "type": "string", + "default": "wide" + }, + "className": { + "type": "string", + "default": "" + }, + "hasDarkControls": { + "type": "boolean", + "default": false + } + }, + "supports": { + "color": { + "background": true, + "text": true, + "button": true + }, + "multiple": false, + "align": [ + "wide", + "full" + ], + "html": false, + "spacing": { + "padding": true, + "margin": true, + "__experimentalDefaultControls": { + "margin": false, + "padding": false + } + } + }, + "textdomain": "woocommerce", + "apiVersion": 3, + "$schema": "https://schemas.wp.org/trunk/block.json" +} diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/edit.tsx new file mode 100644 index 00000000000..5b061b89ea6 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/edit.tsx @@ -0,0 +1,125 @@ +/** + * External dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; +import clsx from 'clsx'; +import type { TemplateArray, BlockAttributes } from '@wordpress/blocks'; +import { Disabled, PanelBody, ToggleControl } from '@wordpress/components'; +import { + InnerBlocks, + useBlockProps, + InspectorControls, +} from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import './style.scss'; +import { SITE_TITLE } from '../../../settings/shared/default-constants'; +import Form from './form'; + +const defaultTemplate = [ + [ + 'core/heading', + { + level: 3, + content: sprintf( + /* translators: %s: site name */ + __( 'Create an account with %s', 'woocommerce' ), + SITE_TITLE + ), + }, + ], + [ + 'core/list', + {}, + [ + [ + 'core/list-item', + { + content: __( 'Faster future purchases', 'woocommerce' ), + }, + ], + [ + 'core/list-item', + { + content: __( 'Securely save payment info', 'woocommerce' ), + }, + ], + [ + 'core/list-item', + { + content: __( + 'Track orders & view shopping history', + 'woocommerce' + ), + }, + ], + ], + ], +] as TemplateArray; + +type EditProps = { + attributes: { + hasDarkControls: boolean; + }; + setAttributes: ( attrs: BlockAttributes ) => void; +}; + +export const Edit = ( { + attributes, + setAttributes, +}: EditProps ): JSX.Element => { + const className = clsx( 'wc-block-order-confirmation-create-account', { + 'has-dark-controls': attributes.hasDarkControls, + } ); + const blockProps = useBlockProps( { + className, + } ); + + return ( +
+ + +
+ + + + + setAttributes( { + hasDarkControls: ! attributes.hasDarkControls, + } ) + } + /> + + +
+ ); +}; + +export const Save = (): JSX.Element => { + return ( +
+ +
+ ); +}; + +export default Edit; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/form.tsx b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/form.tsx new file mode 100644 index 00000000000..4d7446443f5 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/form.tsx @@ -0,0 +1,143 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { useState, createInterpolateElement } from '@wordpress/element'; +import Button from '@woocommerce/base-components/button'; +import PasswordStrengthMeter from '@woocommerce/base-components/cart-checkout/password-strength-meter'; +import { PRIVACY_URL, TERMS_URL } from '@woocommerce/block-settings'; +import { ValidatedTextInput } from '@woocommerce/blocks-components'; +import { useSelect } from '@wordpress/data'; +import { VALIDATION_STORE_KEY } from '@woocommerce/block-data'; + +const termsPageLink = TERMS_URL ? ( + + { __( 'Terms', 'woocommerce' ) } + +) : ( + { __( 'Terms', 'woocommerce' ) } +); + +const privacyPageLink = PRIVACY_URL ? ( + + { __( 'Privacy Policy', 'woocommerce' ) } + +) : ( + { __( 'Privacy Policy', 'woocommerce' ) } +); + +const Form = ( { + attributes: blockAttributes, + isEditor, +}: { + attributes?: { customerEmail?: string; nonceToken?: string }; + isEditor: boolean; +} ) => { + const [ isLoading, setIsLoading ] = useState( false ); + const [ password, setPassword ] = useState( '' ); + const [ passwordStrength, setPasswordStrength ] = useState( 0 ); + const hasValidationError = useSelect( ( select ) => + select( VALIDATION_STORE_KEY ).getValidationError( 'account-password' ) + ); + const customerEmail = + blockAttributes?.customerEmail || + ( isEditor ? 'customer@email.com' : '' ); + const nonceToken = blockAttributes?.nonceToken || ''; + + return ( + { + if ( hasValidationError ) { + event.preventDefault(); + return; + } + setIsLoading( true ); + } } + > +

+ { createInterpolateElement( + __( 'Set a password for ', 'woocommerce' ), + { + email: { customerEmail }, + } + ) } +

+
+ { + if ( + validity.valueMissing || + validity.badInput || + validity.typeMismatch + ) { + return __( + 'Please enter a valid password', + 'woocommerce' + ); + } + } } + customValidation={ ( inputObject ) => { + if ( passwordStrength < 2 ) { + inputObject.setCustomValidity( + __( + 'Please create a stronger password', + 'woocommerce' + ) + ); + return false; + } + return true; + } } + onChange={ ( value: string ) => setPassword( value ) } + feedback={ + + setPasswordStrength( strength ) + } + /> + } + /> +
+ + + + + +

+ { createInterpolateElement( + /* translators: %1$s terms page link, %2$s privacy page link. */ + __( + 'By creating an account you agree to our and .', + 'woocommerce' + ), + { terms: termsPageLink, privacy: privacyPageLink } + ) } +

+ + ); +}; + +export default Form; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/frontend.tsx b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/frontend.tsx new file mode 100644 index 00000000000..8af1238fb5e --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/frontend.tsx @@ -0,0 +1,24 @@ +/** + * External dependencies + */ +import { renderFrontend } from '@woocommerce/base-utils'; + +/** + * Internal dependencies + */ +import Block from './form'; +import { parseAttributes } from './utils'; + +const getProps = ( el: HTMLElement ) => { + return { + attributes: parseAttributes( el.dataset ), + isEditor: false, + }; +}; + +// This does not replace the entire block markup, just the form part. +renderFrontend( { + selector: '.woocommerce-order-confirmation-create-account-form', + Block, + getProps, +} ); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/index.tsx new file mode 100644 index 00000000000..d12ff49337c --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/index.tsx @@ -0,0 +1,45 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import { Icon, people } from '@wordpress/icons'; +import { isExperimentalBlocksEnabled } from '@woocommerce/block-settings'; +import { ExternalLink } from '@wordpress/components'; +import { ADMIN_URL } from '@woocommerce/settings'; + +/** + * Internal dependencies + */ +import metadata from './block.json'; +import { Save, Edit } from './edit'; + +if ( isExperimentalBlocksEnabled() ) { + registerBlockType( metadata, { + apiVersion: 3, + description: ( + <> + { metadata.description } +
+ + { __( 'Manage account settings', 'woocommerce' ) } + + + ), + icon: { + src: ( + + ), + }, + attributes: { + ...metadata.attributes, + }, + edit: Edit, + save: Save, + } ); +} diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/style.scss new file mode 100644 index 00000000000..8da053ef4e1 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/style.scss @@ -0,0 +1,82 @@ +.wc-block-order-confirmation-create-account { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + gap: $gap; + padding: $gap-larger; + margin-top: $gap-larger !important; + margin-bottom: $gap-larger !important; + background: rgba(0, 0, 0, 0.04); + box-sizing: border-box; + + > div { + flex: 1; + } + + p { + margin-top: 0; + margin-bottom: 0; + } + + .woocommerce-order-confirmation-create-account-content, + .block-editor-block-list__layout { + > :first-child { + margin-top: 0 !important; + } + > :last-child { + margin-bottom: 0 !important; + } + ul { + li { + margin-bottom: $gap; + } + } + * { + color: inherit; + } + } + + form { + display: flex; + flex-direction: column; + gap: $gap; + + p, + .wc-block-components-text-input { + margin-top: 0; + margin-bottom: 0; + } + + .wc-block-components-button { + width: 100%; + padding: 1em; + } + + .wc-block-order-confirmation-create-account-terms { + @include font-size(small); + text-align: center; + + a, + span { + white-space: nowrap; + } + } + + .wc-block-components-password-strength.hidden { + display: none; + } + } + + .woocommerce-order-confirmation-create-account-success { + text-align: center; + padding: $gap-larger 0; + + > :first-child { + margin-top: 0 !important; + } + > :last-child { + margin-bottom: 0 !important; + } + } +} diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/utils.ts b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/utils.ts new file mode 100644 index 00000000000..51040951d07 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/utils.ts @@ -0,0 +1,6 @@ +export const parseAttributes = ( data: Record< string, unknown > ) => { + return { + customerEmail: data?.customerEmail || '', + nonceToken: data?.nonceToken || '', + }; +}; diff --git a/plugins/woocommerce-blocks/bin/webpack-entries.js b/plugins/woocommerce-blocks/bin/webpack-entries.js index a3adb0662fc..11a84832ef5 100644 --- a/plugins/woocommerce-blocks/bin/webpack-entries.js +++ b/plugins/woocommerce-blocks/bin/webpack-entries.js @@ -163,6 +163,10 @@ const blocks = { 'order-confirmation-additional-fields': { customDir: 'order-confirmation/additional-fields', }, + 'order-confirmation-create-account': { + customDir: 'order-confirmation/create-account', + isExperimental: true, + }, }; // Intentional separation of cart and checkout entry points to allow for better code splitting. diff --git a/plugins/woocommerce-blocks/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md b/plugins/woocommerce-blocks/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md index 2254ddb6d82..f35c9a00d2d 100644 --- a/plugins/woocommerce-blocks/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md +++ b/plugins/woocommerce-blocks/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md @@ -58,6 +58,10 @@ The majority of our feature flagging is blocks, this is a list of them: - [PHP flag](https://github.com/woocommerce/woocommerce/blob/a0f9d159e5196983d93064762fd20a510de57d55/plugins/woocommerce/src/Blocks/BlockTypesController.php#L303) - [Webpack flag](https://github.com/woocommerce/woocommerce/blob/a0f9d159e5196983d93064762fd20a510de57d55/plugins/woocommerce-blocks/bin/webpack-entries.js#L101) - [JS flag](https://github.com/woocommerce/woocommerce/blob/a0f9d159e5196983d93064762fd20a510de57d55/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/index.tsx#L15) +- Delayed Account Creation (Experimental) + - [PHP flag](https://github.com/woocommerce/woocommerce/blob/9897737880dcbef9831ee41799684dab1960d94f/plugins/woocommerce/src/Blocks/BlockTypesController.php#L417) + - [Webpack flag](https://github.com/woocommerce/woocommerce/blob/9897737880dcbef9831ee41799684dab1960d94f/plugins/woocommerce-blocks/bin/webpack-entries.js#L168) + - [JS flag](https://github.com/woocommerce/woocommerce/blob/9897737880dcbef9831ee41799684dab1960d94f/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/create-account/index.tsx#L14) ## Features behind flags diff --git a/plugins/woocommerce-blocks/packages/components/validation-input-error/index.tsx b/plugins/woocommerce-blocks/packages/components/validation-input-error/index.tsx index 759468951df..7959d855b9e 100644 --- a/plugins/woocommerce-blocks/packages/components/validation-input-error/index.tsx +++ b/plugins/woocommerce-blocks/packages/components/validation-input-error/index.tsx @@ -3,6 +3,7 @@ */ import { useSelect } from '@wordpress/data'; import { VALIDATION_STORE_KEY } from '@woocommerce/block-data'; +import { Icon, warning } from '@wordpress/icons'; /** * Internal dependencies @@ -38,7 +39,10 @@ export const ValidationInputError = ( { return (
-

{ errorMessage }

+

+ + { errorMessage } +

); }; diff --git a/plugins/woocommerce-blocks/packages/components/validation-input-error/style.scss b/plugins/woocommerce-blocks/packages/components/validation-input-error/style.scss index ff5f571d745..3819f68a499 100644 --- a/plugins/woocommerce-blocks/packages/components/validation-input-error/style.scss +++ b/plugins/woocommerce-blocks/packages/components/validation-input-error/style.scss @@ -6,7 +6,17 @@ > p { margin: 0; - padding: $gap-smallest 0 0 0; + padding: $gap-smaller 0 0 0; + display: flex; + align-items: center; + gap: 2px; + } + + svg { + fill: currentColor; + width: 1.5em; + height: 1.5em; + margin-top: -1px; } } diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/checkout/checkout-block.shopper.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/checkout/checkout-block.shopper.block_theme.spec.ts index de86eff5685..d3b78538f47 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/checkout/checkout-block.shopper.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/checkout/checkout-block.shopper.block_theme.spec.ts @@ -482,6 +482,8 @@ test.describe( 'Shopper → Checkout Form Errors (guest user)', () => { await frontendUtils.goToCheckout(); await page.getByLabel( 'Email address' ).clear(); + // Notices on the email field will move content when the field loses focus. This can cause the click to "miss". + await page.getByRole( 'button', { name: 'Place order' } ).focus(); await page.getByRole( 'button', { name: 'Place order' } ).click(); // Verify that all required fields show the correct warning. diff --git a/plugins/woocommerce/changelog/add-delayed-account-creation-block-50632 b/plugins/woocommerce/changelog/add-delayed-account-creation-block-50632 new file mode 100644 index 00000000000..ffd1d6f1c9b --- /dev/null +++ b/plugins/woocommerce/changelog/add-delayed-account-creation-block-50632 @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Added experimental delayed order creation block. diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/AbstractOrderConfirmationBlock.php b/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/AbstractOrderConfirmationBlock.php index 09c9881c8b6..4887dd04e30 100644 --- a/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/AbstractOrderConfirmationBlock.php +++ b/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/AbstractOrderConfirmationBlock.php @@ -186,7 +186,13 @@ abstract class AbstractOrderConfirmationBlock extends AbstractBlock { */ protected function is_email_verified( $order ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash - if ( empty( $_POST ) || ! isset( $_POST['email'] ) || ! wp_verify_nonce( $_POST['check_submission'] ?? '', 'wc_verify_email' ) ) { + if ( empty( $_POST ) || ! isset( $_POST['email'], $_POST['_wpnonce'] ) ) { + return false; + } + + $nonce_value = sanitize_key( wp_unslash( $_POST['_wpnonce'] ?? '' ) ); + + if ( ! wp_verify_nonce( $nonce_value, 'wc_verify_email' ) && ! wp_verify_nonce( $nonce_value, 'wc_create_account' ) ) { return false; } diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/CreateAccount.php b/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/CreateAccount.php new file mode 100644 index 00000000000..6f355cc02ba --- /dev/null +++ b/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/CreateAccount.php @@ -0,0 +1,174 @@ +register_block_type() + * @param string $key Data to get, or default to everything. + * @return array|string + */ + protected function get_block_type_script( $key = null ) { + $script = [ + 'handle' => 'wc-order-confirmation-create-account-block-frontend', + 'path' => $this->asset_api->get_block_asset_build_path( 'order-confirmation-create-account-frontend' ), + 'dependencies' => [], + ]; + return $key ? $script[ $key ] : $script; + } + + /** + * Process posted account form. + * + * @param \WC_Order $order Order object. + * @return \WP_Error|int + */ + protected function process_form_post( $order ) { + if ( ! isset( $_POST['create-account'], $_POST['email'], $_POST['password'], $_POST['_wpnonce'] ) ) { + return 0; + } + + if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['_wpnonce'] ?? '' ) ), 'wc_create_account' ) ) { + return new \WP_Error( 'invalid_nonce', __( 'Unable to create account. Please try again.', 'woocommerce' ) ); + } + + $user_email = sanitize_email( wp_unslash( $_POST['email'] ) ); + $password = wp_unslash( $_POST['password'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + + // Does order already have user? + if ( $order->get_customer_id() ) { + return new \WP_Error( 'order_already_has_user', __( 'This order is already linked to a user account.', 'woocommerce' ) ); + } + + // Check given details match the current viewed order. + if ( $order->get_billing_email() !== $user_email ) { + return new \WP_Error( 'email_mismatch', __( 'The email address provided does not match the email address on this order.', 'woocommerce' ) ); + } + + if ( empty( $password ) || strlen( $password ) < 8 ) { + return new \WP_Error( 'password_too_short', __( 'Password must be at least 8 characters.', 'woocommerce' ) ); + } + + $customer_id = wc_create_new_customer( + $user_email, + '', + $password, + [ + 'first_name' => $order->get_billing_first_name(), + 'last_name' => $order->get_billing_last_name(), + 'source' => 'delayed-account-creation', + ] + ); + + if ( is_wp_error( $customer_id ) ) { + return $customer_id; + } + + // Associate customer with the order. + $order->set_customer_id( $customer_id ); + $order->save(); + + // Associate addresses from the order with the customer. + $order_controller = new OrderController(); + $order_controller->sync_customer_data_with_order( $order ); + + // Set the customer auth cookie. + wc_set_customer_auth_cookie( $customer_id ); + + return $customer_id; + } + + /** + * This renders the content of the block within the wrapper. + * + * @param \WC_Order $order Order object. + * @param string|false $permission If the current user can view the order details or not. + * @param array $attributes Block attributes. + * @param string $content Original block content. + * @return string + */ + protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) { + if ( ! $permission ) { + return ''; + } + + // Check registration is possible for this order/customer, and if not, return early. + if ( is_user_logged_in() || email_exists( $order->get_billing_email() ) ) { + return ''; + } + + $result = $this->process_form_post( $order ); + + if ( is_wp_error( $result ) ) { + $notice = wc_print_notice( $result->get_error_message(), 'error', [], true ); + } elseif ( $result ) { + return $this->render_confirmation(); + } + + $processor = new \WP_HTML_Tag_Processor( + $content . + '
' . + $notice . + '' . + '
' + ); + + if ( ! $processor->next_tag( array( 'class_name' => 'wp-block-woocommerce-order-confirmation-create-account' ) ) ) { + return $content; + } + + $processor->set_attribute( 'class', '' ); + $processor->set_attribute( 'style', '' ); + $processor->add_class( 'woocommerce-order-confirmation-create-account-content' ); + + if ( ! $processor->next_tag( array( 'class_name' => 'woocommerce-order-confirmation-create-account-form' ) ) ) { + return $content; + } + + $processor->set_attribute( 'data-customer-email', $order->get_billing_email() ); + $processor->set_attribute( 'data-nonce-token', wp_create_nonce( 'wc_create_account' ) ); + + if ( ! empty( $attributes['hasDarkControls'] ) ) { + $processor->add_class( 'has-dark-controls' ); + } + + return $processor->get_updated_html(); + } + + /** + * Render the block when an account has been registered. + * + * @return string + */ + protected function render_confirmation() { + $content = '
'; + $content .= '

' . esc_html__( 'Your account has been successfully created', 'woocommerce' ) . '

'; + $content .= '

' . sprintf( + /* translators: 1: link to my account page, 2: link to shipping and billing addresses, 3: link to account details, 4: closing tag */ + esc_html__( 'You can now %1$sview your recent orders%4$s, manage your %2$sshipping and billing addresses%4$s, and edit your %3$spassword and account details%4$s.', 'woocommerce' ), + '', + '', + '', + '' + ) . '

'; + $content .= '
'; + + return $content; + } +} diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/Status.php b/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/Status.php index 6cc50f68d3a..9c38143c870 100644 --- a/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/Status.php +++ b/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/Status.php @@ -265,7 +265,7 @@ class Status extends AbstractOrderConfirmationBlock {

', esc_attr( 'verify-email-submit' ), esc_html__( 'Confirm email and view order', 'woocommerce' ), - wp_nonce_field( 'wc_verify_email', 'check_submission', true, false ), + wp_nonce_field( 'wc_verify_email', '_wpnonce', true, false ), esc_attr( wc_wp_theme_get_element_class_name( 'button' ) ) ) . ''; diff --git a/plugins/woocommerce/src/Blocks/BlockTypesController.php b/plugins/woocommerce/src/Blocks/BlockTypesController.php index f6d84ecc051..059152fd7fc 100644 --- a/plugins/woocommerce/src/Blocks/BlockTypesController.php +++ b/plugins/woocommerce/src/Blocks/BlockTypesController.php @@ -414,6 +414,7 @@ final class BlockTypesController { $block_types[] = 'ProductFilterRating'; $block_types[] = 'ProductFilterActive'; $block_types[] = 'ProductFilterClearButton'; + $block_types[] = 'OrderConfirmation\CreateAccount'; } /**