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 (
+
+ );
+};
+
+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 .
+ ''
+ );
+
+ 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';
}
/**