Add additional information block for custom checkout fields (#43274)
Co-authored-by: Mike Jolley <mike.jolley@me.com> Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
parent
5451d1ef23
commit
d8331dc3f1
|
@ -35,6 +35,7 @@ export enum noticeContexts {
|
|||
BILLING_ADDRESS = 'wc/checkout/billing-address',
|
||||
SHIPPING_METHODS = 'wc/checkout/shipping-methods',
|
||||
CHECKOUT_ACTIONS = 'wc/checkout/checkout-actions',
|
||||
ADDITIONAL_INFORMATION = 'wc/checkout/additional-information',
|
||||
}
|
||||
|
||||
export interface ResponseType extends Record< string, unknown > {
|
||||
|
|
|
@ -116,6 +116,11 @@ const settings = {
|
|||
{},
|
||||
[]
|
||||
),
|
||||
createBlock(
|
||||
'woocommerce/checkout-additional-information-block',
|
||||
{},
|
||||
[]
|
||||
),
|
||||
showOrderNotes
|
||||
? createBlock(
|
||||
'woocommerce/checkout-order-note-block',
|
||||
|
@ -154,6 +159,84 @@ const settings = {
|
|||
);
|
||||
},
|
||||
},
|
||||
// Adds the additional information block.
|
||||
{
|
||||
save( { attributes }: { attributes: { className: string } } ) {
|
||||
return (
|
||||
<div
|
||||
className={ classnames(
|
||||
'is-loading',
|
||||
attributes.className
|
||||
) }
|
||||
/>
|
||||
);
|
||||
},
|
||||
isEligible: (
|
||||
_attributes: Record< string, unknown >,
|
||||
innerBlocks: BlockInstance[]
|
||||
) => {
|
||||
const checkoutFieldsBlock = innerBlocks.find(
|
||||
( block: { name: string } ) =>
|
||||
block.name === 'woocommerce/checkout-fields-block'
|
||||
);
|
||||
|
||||
if ( ! checkoutFieldsBlock ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Top level block is the fields block, we then need to search within that for the additional information block.
|
||||
return ! checkoutFieldsBlock.innerBlocks.some(
|
||||
( block: { name: string } ) =>
|
||||
block.name ===
|
||||
'woocommerce/checkout-additional-information-block'
|
||||
);
|
||||
},
|
||||
migrate: (
|
||||
attributes: Record< string, unknown >,
|
||||
innerBlocks: BlockInstance[]
|
||||
) => {
|
||||
const checkoutFieldsBlockIndex = innerBlocks.findIndex(
|
||||
( block: { name: string } ) =>
|
||||
block.name === 'woocommerce/checkout-fields-block'
|
||||
);
|
||||
|
||||
if ( checkoutFieldsBlockIndex === -1 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const checkoutFieldsBlock =
|
||||
innerBlocks[ checkoutFieldsBlockIndex ];
|
||||
|
||||
const insertIndex = checkoutFieldsBlock.innerBlocks.findIndex(
|
||||
( block: { name: string } ) =>
|
||||
block.name ===
|
||||
'wp-block-woocommerce-checkout-payment-block'
|
||||
);
|
||||
|
||||
if ( insertIndex === -1 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
innerBlocks[ checkoutFieldsBlockIndex ] =
|
||||
checkoutFieldsBlock.innerBlocks
|
||||
.slice( 0, insertIndex )
|
||||
.concat(
|
||||
createBlock(
|
||||
'woocommerce/checkout-additional-information-block',
|
||||
{},
|
||||
[]
|
||||
)
|
||||
)
|
||||
.concat(
|
||||
innerBlocks.slice(
|
||||
insertIndex + 1,
|
||||
innerBlocks.length
|
||||
)
|
||||
);
|
||||
|
||||
return [ attributes, innerBlocks ];
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import formStepAttributes from '../../form-step/attributes';
|
||||
|
||||
export default {
|
||||
...formStepAttributes( {
|
||||
defaultTitle: __( 'Additional order information', 'woocommerce' ),
|
||||
defaultDescription: '',
|
||||
} ),
|
||||
className: {
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
lock: {
|
||||
type: 'object',
|
||||
default: {
|
||||
move: true,
|
||||
remove: true,
|
||||
},
|
||||
},
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "woocommerce/checkout-additional-information-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Additional information",
|
||||
"description": "Render additional fields in the 'Additional information' location.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false
|
||||
},
|
||||
"attributes": {
|
||||
"className": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/checkout-fields-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { noticeContexts } from '@woocommerce/base-context';
|
||||
import { StoreNoticesContainer } from '@woocommerce/blocks-components';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data';
|
||||
import { ADDITIONAL_FORM_KEYS } from '@woocommerce/block-settings';
|
||||
import { Form } from '@woocommerce/base-components/cart-checkout';
|
||||
import type { FunctionComponent } from 'react';
|
||||
|
||||
const Block: FunctionComponent = () => {
|
||||
const { additionalFields } = useSelect( ( select ) => {
|
||||
const store = select( CHECKOUT_STORE_KEY );
|
||||
return {
|
||||
additionalFields: store.getAdditionalFields(),
|
||||
};
|
||||
} );
|
||||
|
||||
const { setAdditionalFields } = useDispatch( CHECKOUT_STORE_KEY );
|
||||
|
||||
const onChangeForm = ( additionalValues ) => {
|
||||
setAdditionalFields( additionalValues );
|
||||
};
|
||||
|
||||
const additionalFieldValues = {
|
||||
...additionalFields,
|
||||
};
|
||||
|
||||
if ( ADDITIONAL_FORM_KEYS.length === 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<StoreNoticesContainer
|
||||
context={ noticeContexts.ADDITIONAL_INFORMATION }
|
||||
/>
|
||||
<Form
|
||||
id="additional-information"
|
||||
addressType="additional-information"
|
||||
onChange={ onChangeForm }
|
||||
values={ additionalFieldValues }
|
||||
fields={ ADDITIONAL_FORM_KEYS }
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
import { FormStepBlock } from '@woocommerce/blocks/checkout/form-step';
|
||||
import classnames from 'classnames';
|
||||
import { ADDITIONAL_FORM_KEYS } from '@woocommerce/block-settings';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
import './editor.scss';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
setAttributes,
|
||||
}: {
|
||||
attributes: {
|
||||
title: string;
|
||||
description: string;
|
||||
showStepNumber: boolean;
|
||||
className: string;
|
||||
};
|
||||
setAttributes: ( attributes: Record< string, unknown > ) => void;
|
||||
} ) => {
|
||||
if ( ADDITIONAL_FORM_KEYS.length === 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FormStepBlock
|
||||
setAttributes={ setAttributes }
|
||||
attributes={ attributes }
|
||||
className={ classnames(
|
||||
'wc-block-checkout__additional-information-fields',
|
||||
attributes?.className
|
||||
) }
|
||||
>
|
||||
<Block />
|
||||
</FormStepBlock>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
// Adjust padding and margins in the editor to improve selected block outlines.
|
||||
.wp-block-woocommerce-checkout-order-note-block {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
|
||||
.wc-block-checkout__add-note {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import classnames from 'classnames';
|
||||
import { FormStep } from '@woocommerce/blocks-components';
|
||||
import { ADDITIONAL_FORM_KEYS } from '@woocommerce/block-settings';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data';
|
||||
import { withFilteredAttributes } from '@woocommerce/shared-hocs';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
import attributes from './attributes';
|
||||
|
||||
const FrontendBlock = ( {
|
||||
title,
|
||||
description,
|
||||
showStepNumber,
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
title: string;
|
||||
description: string;
|
||||
showStepNumber: boolean;
|
||||
children: JSX.Element;
|
||||
className?: string;
|
||||
} ) => {
|
||||
const checkoutIsProcessing = useSelect( ( select ) =>
|
||||
select( CHECKOUT_STORE_KEY ).isProcessing()
|
||||
);
|
||||
|
||||
if ( ADDITIONAL_FORM_KEYS.length === 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FormStep
|
||||
id="additional-information-fields"
|
||||
disabled={ checkoutIsProcessing }
|
||||
className={ classnames(
|
||||
'wc-block-checkout__additional-information-fields',
|
||||
className
|
||||
) }
|
||||
title={ title }
|
||||
description={ description }
|
||||
showStepNumber={ showStepNumber }
|
||||
>
|
||||
<Block />
|
||||
{ children }
|
||||
</FormStep>
|
||||
);
|
||||
};
|
||||
|
||||
export default withFilteredAttributes( attributes )( FrontendBlock );
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Icon, customPostType } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
import './style.scss';
|
||||
import attributes from './attributes';
|
||||
|
||||
registerBlockType( 'woocommerce/checkout-additional-information-block', {
|
||||
attributes,
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ customPostType }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
|
@ -0,0 +1,29 @@
|
|||
.wc-block-checkout__add-note {
|
||||
margin: em($gap-large) 0;
|
||||
}
|
||||
|
||||
.is-mobile,
|
||||
.is-small,
|
||||
.is-medium {
|
||||
.wc-block-checkout__add-note {
|
||||
border-bottom: 1px solid $universal-border-light;
|
||||
margin-bottom: em($gap);
|
||||
margin-top: em($gap);
|
||||
padding: em($gap) 0;
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-checkout__add-note .wc-block-components-textarea {
|
||||
margin-top: $gap;
|
||||
|
||||
&:focus {
|
||||
background-color: #fff;
|
||||
color: $input-text-active;
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 1px $input-border-gray;
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-components-form .wc-block-checkout__order-notes.wc-block-components-checkout-step {
|
||||
padding-left: 0;
|
||||
}
|
|
@ -47,6 +47,7 @@ export const Edit = ( {
|
|||
[ 'woocommerce/checkout-billing-address-block', {}, [] ],
|
||||
[ 'woocommerce/checkout-shipping-methods-block', {}, [] ],
|
||||
[ 'woocommerce/checkout-payment-block', {}, [] ],
|
||||
[ 'woocommerce/checkout-additional-information-block', {}, [] ],
|
||||
[ 'woocommerce/checkout-order-note-block', {}, [] ],
|
||||
[ 'woocommerce/checkout-terms-block', {}, [] ],
|
||||
[ 'woocommerce/checkout-actions-block', {}, [] ],
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Internal dependencies
|
||||
*/
|
||||
import CHECKOUT_ACTIONS from './checkout-actions-block/block.json';
|
||||
import CHECKOUT_ADDITIONAL_INFORMATION from './checkout-additional-information-block/block.json';
|
||||
import CHECKOUT_BILLING_ADDRESS from './checkout-billing-address-block/block.json';
|
||||
import CHECKOUT_CONTACT_INFORMATION from './checkout-contact-information-block/block.json';
|
||||
import CHECKOUT_EXPRESS_PAYMENT from './checkout-express-payment-block/block.json';
|
||||
|
@ -25,6 +26,7 @@ import CHECKOUT_ORDER_SUMMARY_CART_ITEMS from './checkout-order-summary-cart-ite
|
|||
|
||||
export default {
|
||||
CHECKOUT_ACTIONS,
|
||||
CHECKOUT_ADDITIONAL_INFORMATION,
|
||||
CHECKOUT_BILLING_ADDRESS,
|
||||
CHECKOUT_CONTACT_INFORMATION,
|
||||
CHECKOUT_EXPRESS_PAYMENT,
|
||||
|
|
|
@ -8,6 +8,7 @@ import './checkout-terms-block';
|
|||
import './checkout-contact-information-block';
|
||||
import './checkout-billing-address-block';
|
||||
import './checkout-actions-block';
|
||||
import './checkout-additional-information-block';
|
||||
import './checkout-order-note-block';
|
||||
import './checkout-order-summary-block';
|
||||
import './checkout-payment-block';
|
||||
|
|
|
@ -109,6 +109,16 @@ registerCheckoutBlock( {
|
|||
),
|
||||
} );
|
||||
|
||||
registerCheckoutBlock( {
|
||||
metadata: metadata.CHECKOUT_ADDITIONAL_INFORMATION,
|
||||
component: lazy(
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "checkout-blocks/additional-information" */ './checkout-additional-information-block/frontend'
|
||||
)
|
||||
),
|
||||
} );
|
||||
|
||||
registerCheckoutBlock( {
|
||||
metadata: metadata.CHECKOUT_ORDER_NOTE,
|
||||
component: lazy(
|
||||
|
|
|
@ -55,7 +55,12 @@ export type ContactForm = CoreContactForm & Record< string, FormField >;
|
|||
export type FormFields = AddressForm & ContactForm;
|
||||
export type AddressFormValues = Omit< ShippingAddress, 'email' >;
|
||||
export type ContactFormValues = { email: string };
|
||||
export type FormType = 'billing' | 'shipping' | 'contact';
|
||||
export type AdditionalInformationFormValues = Record< string, string >;
|
||||
export type FormType =
|
||||
| 'billing'
|
||||
| 'shipping'
|
||||
| 'contact'
|
||||
| 'additional-information';
|
||||
|
||||
export interface CoreAddress {
|
||||
first_name: string;
|
||||
|
|
|
@ -32,6 +32,10 @@
|
|||
<div class="wp-block-woocommerce-checkout-payment-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-payment-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-additional-information-block -->
|
||||
<div class="wp-block-woocommerce-checkout-additional-information-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-additional-information-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-order-note-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-note-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-order-note-block -->
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: add
|
||||
Comment: Allow additional fields to be rendered at the end of the Checkout block. This is locked behind a feature flag, the fields won't show up until we remove the feature gate.
|
||||
|
|
@ -2589,6 +2589,10 @@ EOT;
|
|||
<div class="wp-block-woocommerce-checkout-payment-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-payment-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-additional-information-block -->
|
||||
<div class="wp-block-woocommerce-checkout-additional-information-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-additional-information-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-order-note-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-note-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-order-note-block -->
|
||||
|
|
|
@ -169,7 +169,8 @@ class Checkout extends AbstractBlock {
|
|||
<div data-block-name="woocommerce/checkout-shipping-address-block" class="wp-block-woocommerce-checkout-shipping-address-block"></div>
|
||||
<div data-block-name="woocommerce/checkout-billing-address-block" class="wp-block-woocommerce-checkout-billing-address-block"></div>
|
||||
<div data-block-name="woocommerce/checkout-shipping-methods-block" class="wp-block-woocommerce-checkout-shipping-methods-block"></div>
|
||||
<div data-block-name="woocommerce/checkout-payment-block" class="wp-block-woocommerce-checkout-payment-block"></div>' .
|
||||
<div data-block-name="woocommerce/checkout-payment-block" class="wp-block-woocommerce-checkout-payment-block"></div>
|
||||
<div data-block-name="woocommerce/checkout-additional-information-block" class="wp-block-woocommerce-checkout-additional-information-block"></div>' .
|
||||
( isset( $attributes['showOrderNotes'] ) && false === $attributes['showOrderNotes'] ? '' : '<div data-block-name="woocommerce/checkout-order-note-block" class="wp-block-woocommerce-checkout-order-note-block"></div>' ) .
|
||||
( isset( $attributes['showPolicyLinks'] ) && false === $attributes['showPolicyLinks'] ? '' : '<div data-block-name="woocommerce/checkout-terms-block" class="wp-block-woocommerce-checkout-terms-block"></div>' ) .
|
||||
'<div data-block-name="woocommerce/checkout-actions-block" class="wp-block-woocommerce-checkout-actions-block"></div>
|
||||
|
@ -217,6 +218,18 @@ class Checkout extends AbstractBlock {
|
|||
$content = preg_replace( $shipping_address_block_regex, $local_pickup_inner_blocks, $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the Additional Information block to checkouts missing it.
|
||||
*/
|
||||
$additional_information_inner_blocks = '$0' . PHP_EOL . PHP_EOL . '<div data-block-name="woocommerce/checkout-additional-information-block" class="wp-block-woocommerce-checkout-additional-information-block"></div>' . PHP_EOL . PHP_EOL;
|
||||
$has_additional_information_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-additional-information-block"[^>]*?>/mi';
|
||||
$has_additional_information_block = preg_match( $has_additional_information_regex, $content );
|
||||
|
||||
if ( ! $has_additional_information_block ) {
|
||||
$payment_block_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-payment-block" class="wp-block-woocommerce-checkout-payment-block"[^>]*?><\/div>/mi';
|
||||
$content = preg_replace( $payment_block_regex, $additional_information_inner_blocks, $content );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
@ -480,6 +493,7 @@ class Checkout extends AbstractBlock {
|
|||
return [
|
||||
'Checkout',
|
||||
'CheckoutActionsBlock',
|
||||
'CheckoutAdditionalInformationBlock',
|
||||
'CheckoutBillingAddressBlock',
|
||||
'CheckoutContactInformationBlock',
|
||||
'CheckoutExpressPaymentBlock',
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
namespace Automattic\WooCommerce\Blocks\BlockTypes;
|
||||
|
||||
/**
|
||||
* CheckoutAdditionalInformationBlock class.
|
||||
*/
|
||||
class CheckoutAdditionalInformationBlock extends AbstractInnerBlock {
|
||||
/**
|
||||
* Block name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $block_name = 'checkout-additional-information-block';
|
||||
}
|
Loading…
Reference in New Issue