diff --git a/.eslintrc.js b/.eslintrc.js index 535ec7280..234cd4db2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,5 @@ module.exports = { + root: true, extends: [ 'plugin:@woocommerce/eslint-plugin/recommended', 'plugin:you-dont-need-lodash-underscore/compatible', @@ -29,11 +30,14 @@ module.exports = { '@woocommerce/settings', '@woocommerce/shared-context', '@woocommerce/shared-hocs', + '@woocommerce/data', '@wordpress/a11y', '@wordpress/api-fetch', '@wordpress/block-editor', '@wordpress/compose', '@wordpress/data', + '@wordpress/core-data', + '@wordpress/editor', '@wordpress/escape-html', '@wordpress/hooks', '@wordpress/keycodes', diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ac7d5023b..eeaedccd2 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,7 +2,7 @@ Thanks for your interest in contributing to WooCommerce Blocks! -If you wish to contribute code, to get started we recommend first reading our [Getting Started Guide](../docs/contributors/getting-started.md). +If you wish to contribute code, to get started we recommend first reading our [Getting Started Guide](../docs/contributors/contributing/getting-started.md). All other documentation for contributors can be found [in the docs directory](../docs/README.md). diff --git a/.github/automate-team-review-assignment-config.yml b/.github/automate-team-review-assignment-config.yml index 95d9d5fc3..55e04ebd6 100644 --- a/.github/automate-team-review-assignment-config.yml +++ b/.github/automate-team-review-assignment-config.yml @@ -9,9 +9,9 @@ when: - rubik - author: teamIs: - - kirigami + - woo-fse ignore: nameIs: assign: teams: - - kirigami + - woo-fse diff --git a/.github/patch-initial-checklist.md b/.github/patch-initial-checklist.md index cfab58509..aa189b8d6 100644 --- a/.github/patch-initial-checklist.md +++ b/.github/patch-initial-checklist.md @@ -71,11 +71,23 @@ Each porter is responsible for testing the PRs that fall under the focus of thei This only needs done if the patch release needs to be included in WooCommerce Core. -* [ ] Create a pull request for updating the package in WooCommerce core (based off of the WooCommerce core release branch this is deployed for). - - Create the pull request in the [WooCommerce Core Repository](https://github.com/woocommerce/woocommerce/) that [bumps the package version](https://github.com/woocommerce/woocommerce/blob/master/composer.json) for the blocks package to the version being pulled in. - - The content for the pull release can follow [this example](https://github.com/woocommerce/woocommerce/pull/27676). Essentially you link to all the important things that have already been prepared. Note, you need to make sure you link to all the related documents for the feature plugin releases since the last package version bump in Woo Core. - - The PR's changelog should be aggregated from all the releases included in the package bump. This changelog will be used in the release notes for the WooCommerce release. That's why it should only list the PRs that have WooCoomerce Core in the WooCommerce Visibility section of their description. Don't include changes available in the feature plugin or development builds. - - Run through the testing checklist to ensure everything works in that branch for that package bump. **Note:** Testing should include ensuring any features/new blocks that are supposed to be behind feature gating for the core merge of this package update are working as expected. + - [ ] Create a pull request for updating the package in WooCommerce core (based off of the WooCommerce core release branch this is deployed for). + - The content for the pull release can follow [this example](https://github.com/woocommerce/woocommerce/pull/32627). + - [ ] Increase the version of `woocommerce/woocommerce-blocks` in the `plugins/woocommerce/composer.json` file + - [ ] Run `composer update woocommerce/woocommerce-blocks` and make sure `composer-lock.json` was updated + - [ ] Add a new file similar to this one [plugins/woocommerce/changelog/update-woocommerce-blocks-7.4.1](https://github.com/woocommerce/woocommerce/blob/5040a10d01896bcf40fd0ac538f2b7bc584ffe0a/plugins/woocommerce/changelog/update-woocommerce-blocks-7.4.1) with a similar content as below. For the Significance entry we’ll always use `minor`, or `patch` when including a patch release + + ``` + Significance: minor + Type: update + + Update WooCommerce Blocks to 7.4.1 + ``` + + - The PR description can follow [this example](https://github.com/woocommerce/woocommerce/pull/32627). + - It lists all the WooCommerce Blocks versions that are being included since the last version that you edited in `plugins/woocommerce/composer.json`. Each version should have a link for the `Release PR`, `Testing instructions` and `Release post` (if available). + - The changelog should be aggregated from all the releases included in the package bump and grouped per type: `Enhancements`, `Bug Fixes`, `Various` etc. This changelog will be used in the release notes for the WooCommerce release. That's why it should only list the PRs that have WooCoomerce Core in the WooCommerce Visibility section of their description. Don't include changes available in the feature plugin or development builds. + - Run through the testing checklist to ensure everything works in that branch for that package bump. **Note:** Testing should ensure any features/new blocks that are supposed to be behind feature gating for the core merge of this package update are working as expected. - Testing should include completing the [Smoke testing checklist](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/docs/internal-developers/testing/smoke-testing.md). It's up to you to verify that those tests have been done. - Verify and make any additional edits to the pull request description for things like: Changelog to be included with WooCommerce core, additional communication that might be needed elsewhere, additional marketing communication notes that may be needed etc. - After the checklist is complete and the testing is done, it will be up to the WooCommerce core team to approve and merge the pull request. diff --git a/.github/release-initial-checklist.md b/.github/release-initial-checklist.md index 872cc7c08..5f28818c4 100644 --- a/.github/release-initial-checklist.md +++ b/.github/release-initial-checklist.md @@ -22,7 +22,7 @@ The release pull request has been created! This checklist is a guide to follow f * [ ] Run `npm ci` * [ ] Run `npm run package-plugin:deploy`. This will create a zip of the current branch build locally. * Note: The zip file is functionally equivalent to what gets released except the version bump. -* [ ] Create the testing notes for the release. +* [ ] Create the testing notes for the release. * [ ] For each pull request that belongs to the current release, grab the `User Facing Testing` notes from the PR's description. Be sure that the `Do not include in the Testing Notes is not flagged` checkbox is unchecked. * [ ] Add the notes to `docs/internal-developers/testing/releases` * [ ] Update the `docs/internal-developers/testing/releases/README.md` file index. @@ -63,7 +63,7 @@ Each porter is responsible for testing the PRs that fall under the focus of thei * Note: the script automatically updates version numbers on Github (commits on your behalf). * **ALERT**: This script will ask you if this release will be deployed to WordPress.org. You should answer yes for this release even if it is a pre-release. * A GitHub release will automatically be created and this will trigger a workflow that automatically deploys the plugin to WordPress.org. - + ## If this release is deployed to WordPress.org... @@ -93,25 +93,27 @@ Each porter is responsible for testing the PRs that fall under the focus of thei This only needs to be done if this release is the last release of the feature plugin before code freeze in the WooCommerce core cycle. If this condition doesn't exist you can skip this section. -* [ ] Remind whoever is porter this week to audit our codebase to ensure this [experimental interface document](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/docs/blocks/feature-flags-and-experimental-interfaces.md) is up to date. See Pca54o-rM-p2 for more details. -* [ ] Create a pull request for updating the package in the [WooCommerce Core Repository](https://github.com/woocommerce/woocommerce/) that [bumps the package version](https://github.com/woocommerce/woocommerce/blob/747cb6b7184ba9fdc875ab104da5839cfda8b4be/plugins/woocommerce/composer.json) for the Woo Blocks package to the version being pulled in. - * The content for the pull release can follow [this example](https://github.com/woocommerce/woocommerce/pull/32627). - * In the PR description you will link to all the important things that have already been prepared since the version you replaced. Note, you need to make sure you link to all the related documents for the plugin releases since the last package version bump in Woo Core. - * The PR's changelog should be aggregated from all the releases included in the package bump. This changelog will be used in the release notes for the WooCommerce release. That's why it should only list the PRs that have WooCoomerce Core in the WooCommerce Visibility section of their description. Don't include changes available in the feature plugin or development builds. - * Update the `plugins/woocommerce/composer.json` file and then run `composer update`. - - * Since WooCommerce Blocks 7.4.0, the changelog entry for WooCommerce core must include the fields `Significance` and `Type`. In our case, we're using the following definition as seen on [plugins/woocommerce/changelog/update-woocommerce-blocks-7.4.0](https://github.com/woocommerce/woocommerce/pull/32627/commits/99bf4afd262280ad4e45386ce4ad00ce3425af93) file: - ``` - // We’ll always use minor, or patch when including a patch release - Significance: minor - Type: update - - Woo Blocks 7.3.0 & 7.4.0 - ``` - * Run through the testing checklist to ensure everything works in that branch for that package bump. **Note:** Testing should include ensuring any features/new blocks that are supposed to be behind feature gating for the core merge of this package update are working as expected. - * Testing should include completing the [Smoke testing checklist](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/docs/internal-developers/testing/smoke-testing.md). It's up to you to verify that those tests have been done. - * Verify and make any additional edits to the pull request description for things like: Changelog to be included with WooCommerce core, additional communication that might be needed elsewhere, additional marketing communication notes that may be needed etc. - * After the checklist is complete and the testing is done, it will be up to the WooCommerce core team to approve and merge the pull request. +* [ ] Remind whoever is porter this week to audit our codebase to ensure this [experimental interface document](https://github.com/woocommerce/woocommerce-blocks/blob/trunk/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md) is up to date. See Pca54o-rM-p2 for more details. +* [ ] Create a pull request for updating the package in the [WooCommerce Core Repository](https://github.com/woocommerce/woocommerce/) that [bumps the package version](https://github.com/woocommerce/woocommerce/blob/747cb6b7184ba9fdc875ab104da5839cfda8b4be/plugins/woocommerce/composer.json) for the Woo Blocks package to the version you are releasing. + - The content for the pull release can follow [this example](https://github.com/woocommerce/woocommerce/pull/32627). + - [ ] Increase the version of `woocommerce/woocommerce-blocks` in the `plugins/woocommerce/composer.json` file + - [ ] Run `composer update woocommerce/woocommerce-blocks` and make sure `composer-lock.json` was updated + - [ ] Add a new file similar to this one [plugins/woocommerce/changelog/update-woocommerce-blocks-7.4.1](https://github.com/woocommerce/woocommerce/blob/5040a10d01896bcf40fd0ac538f2b7bc584ffe0a/plugins/woocommerce/changelog/update-woocommerce-blocks-7.4.1) with a similar content as below. For the Significance entry we’ll always use `minor`, or `patch` when including a patch release + + ``` + Significance: minor + Type: update + + Update WooCommerce Blocks to 7.4.1 + ``` + + - The PR description can follow [this example](https://github.com/woocommerce/woocommerce/pull/32627). + - It lists all the WooCommerce Blocks versions that are being included since the last version that you edited in `plugins/woocommerce/composer.json`. Each version should have a link for the `Release PR`, `Testing instructions` and `Release post` (if available). + - The changelog should be aggregated from all the releases included in the package bump and grouped per type: `Enhancements`, `Bug Fixes`, `Various` etc. This changelog will be used in the release notes for the WooCommerce release. That's why it should only list the PRs that have WooCoomerce Core in the WooCommerce Visibility section of their description. Don't include changes available in the feature plugin or development builds. + - Run through the testing checklist to ensure everything works in that branch for that package bump. **Note:** Testing should ensure any features/new blocks that are supposed to be behind feature gating for the core merge of this package update are working as expected. + - Testing should include completing the [Smoke testing checklist](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/docs/internal-developers/testing/smoke-testing.md). It's up to you to verify that those tests have been done. + - Verify and make any additional edits to the pull request description for things like: Changelog to be included with WooCommerce core, additional communication that might be needed elsewhere, additional marketing communication notes that may be needed, etc. + - After the checklist is complete and the testing is done, it will be up to the WooCommerce core team to approve and merge the pull request. * [ ] Make sure you join the `#woo-core-releases` Slack channel to represent Woo Blocks for the release of WooCommerce core this version is included in. * [ ] Search the release thread of the WooCommerce core version in WooCommerce P2 (example: p6q8Tx-2gl-p2). * [ ] Subscribe to it, so you are aware of any news/changes. diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml index f100b57c2..d54aa60ec 100644 --- a/.github/workflows/close-stale-issues.yml +++ b/.github/workflows/close-stale-issues.yml @@ -13,9 +13,11 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 60 - days-before-close: 10 + days-before-pr-stale: 7 + days-before-close: -1 remove-stale-when-updated: true - exempt-issue-labels: 'priority: critical,priority: high,Epic' + exempt-issue-labels: 'priority: critical,priority: high,Epic,type: technical debt,category: refactor,type: documentation,plugin incompatibility' + exempt-pr-labels: 'priority: critical,priority: high,Epic,type: technical debt,category: refactor,type: documentation,plugin incompatibility' stale-issue-message: "This issue has been marked as `stale` because it has not seen any activity within the past 60 days. Our team uses this tool to help surface issues for review. If you are the author of the issue there's no need to comment as it will be looked at. \n\n###### Internal: After 10 days with no activity this issue will be automatically be closed." stale-pr-message: "This PR has been marked as `stale` because it has not seen any activity within the past 60 days. Our team uses this tool to help surface pull requests that have slipped through review. \n\n###### If deemed still relevant, the pr can be kept active by ensuring it's up to date with the main branch and removing the stale label - otherwise it will automatically be closed after 10 days." stale-issue-label: 'stale' diff --git a/README.md b/README.md index a4a6fa609..d02f103c1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # WooCommerce Blocks [![Latest Tag](https://img.shields.io/github/tag/woocommerce/woocommerce-gutenberg-products-block.svg?style=flat&label=Latest%20Tag)](https://github.com/woocommerce/woocommerce-gutenberg-products-block/releases) -[![View](https://img.shields.io/badge/Project%20Components-brightgreen.svg?style=flat)](https://woocommerce.github.io/woocommerce-gutenberg-products-block) +[![View](https://img.shields.io/badge/Project%20Components-brightgreen.svg?style=flat)](https://woocommerce.github.io/woocommerce-blocks/) ![JavaScript and CSS Linting](https://github.com/woocommerce/woocommerce-gutenberg-products-block/workflows/JavaScript%20and%20CSS%20Linting/badge.svg?branch=trunk) ![PHP Coding Standards](https://github.com/woocommerce/woocommerce-gutenberg-products-block/workflows/PHP%20Coding%20Standards/badge.svg?branch=trunk) ![Automated tests](https://github.com/woocommerce/woocommerce-gutenberg-products-block/workflows/Automated%20tests/badge.svg?branch=trunk) @@ -66,7 +66,7 @@ Run through the ["Writing Your First Block Type" tutorial](https://wordpress.org For deeper dive, try looking at the [core blocks code,](https://github.com/WordPress/gutenberg/tree/master/packages/block-library/src) or see what [components are available.](https://github.com/WordPress/gutenberg/tree/master/packages/components/src) -To begin contributing to the WooCommerce Blocks plugin, see our [getting started guide](./docs/contributors/getting-started.md) and [developer handbook](./docs/README.md). +To begin contributing to the WooCommerce Blocks plugin, see our [getting started guide](./docs/contributors/contributing/getting-started.md) and [developer handbook](./docs/README.md). Other useful docs to explore: diff --git a/assets/js/atomic/blocks/product-elements/category-list/constants.tsx b/assets/js/atomic/blocks/product-elements/category-list/constants.tsx index f47e5355e..d72577a54 100644 --- a/assets/js/atomic/blocks/product-elements/category-list/constants.tsx +++ b/assets/js/atomic/blocks/product-elements/category-list/constants.tsx @@ -12,6 +12,6 @@ export const BLOCK_ICON: JSX.Element = ( ); export const BLOCK_DESCRIPTION: string = __( - 'Display a list of categories belonging to a product.', + 'Display the list of categories that are assigned to a product.', 'woo-gutenberg-products-block' ); diff --git a/assets/js/atomic/blocks/product-elements/image/attributes.js b/assets/js/atomic/blocks/product-elements/image/attributes.ts similarity index 75% rename from assets/js/atomic/blocks/product-elements/image/attributes.js rename to assets/js/atomic/blocks/product-elements/image/attributes.ts index 1a2f60f9d..1e7a8e775 100644 --- a/assets/js/atomic/blocks/product-elements/image/attributes.js +++ b/assets/js/atomic/blocks/product-elements/image/attributes.ts @@ -1,4 +1,4 @@ -export const blockAttributes = { +export const attributes = { showProductLink: { type: 'boolean', default: true, @@ -19,6 +19,8 @@ export const blockAttributes = { type: 'number', default: 0, }, + isDescendentOfQueryLoop: { + type: 'boolean', + default: false, + }, }; - -export default blockAttributes; diff --git a/assets/js/atomic/blocks/product-elements/image/block.js b/assets/js/atomic/blocks/product-elements/image/block.js index f9554e6e5..e55f875c1 100644 --- a/assets/js/atomic/blocks/product-elements/image/block.js +++ b/assets/js/atomic/blocks/product-elements/image/block.js @@ -2,7 +2,7 @@ * External dependencies */ import PropTypes from 'prop-types'; -import { useState, Fragment } from '@wordpress/element'; +import { Fragment } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import classnames from 'classnames'; import { PLACEHOLDER_IMG_SRC } from '@woocommerce/settings'; @@ -21,18 +21,19 @@ import { useStoreEvents } from '@woocommerce/base-context/hooks'; /** * Internal dependencies */ -import ProductSaleBadge from './../sale-badge/block'; +import ProductSaleBadge from '../sale-badge/block'; import './style.scss'; /** * Product Image Block Component. * - * @param {Object} props Incoming props. - * @param {string} [props.className] CSS Class name for the component. - * @param {string} [props.imageSizing] Size of image to use. - * @param {boolean} [props.showProductLink] Whether or not to display a link to the product page. - * @param {boolean} [props.showSaleBadge] Whether or not to display the on sale badge. - * @param {string} [props.saleBadgeAlign] How should the sale badge be aligned if displayed. + * @param {Object} props Incoming props. + * @param {string} [props.className] CSS Class name for the component. + * @param {string} [props.imageSizing] Size of image to use. + * @param {boolean} [props.showProductLink] Whether or not to display a link to the product page. + * @param {boolean} [props.showSaleBadge] Whether or not to display the on sale badge. + * @param {string} [props.saleBadgeAlign] How should the sale badge be aligned if displayed. + * @param {boolean} [props.isDescendentOfQueryLoop] Whether or not be a children of Query Loop Block. * @return {*} The component. */ export const Block = ( props ) => { @@ -45,8 +46,8 @@ export const Block = ( props ) => { } = props; const { parentClassName } = useInnerBlockLayoutContext(); - const { product } = useProductDataContext(); - const [ imageLoaded, setImageLoaded ] = useState( false ); + const { product, isLoading } = useProductDataContext(); + const { dispatchStoreEvent } = useStoreEvents(); const typographyProps = useTypographyProps( props ); @@ -119,8 +120,7 @@ export const Block = ( props ) => { setImageLoaded( true ) } - loaded={ imageLoaded } + loaded={ ! isLoading } showFullSize={ imageSizing !== 'cropped' } /> @@ -134,11 +134,10 @@ const ImagePlaceholder = () => { ); }; -const Image = ( { image, onLoad, loaded, showFullSize, fallbackAlt } ) => { +const Image = ( { image, loaded, showFullSize, fallbackAlt } ) => { const { thumbnail, src, srcset, sizes, alt } = image || {}; const imageProps = { alt: alt || fallbackAlt, - onLoad, hidden: ! loaded, src: thumbnail, ...( showFullSize && { src, srcSet: srcset, sizes } ), @@ -150,7 +149,7 @@ const Image = ( { image, onLoad, loaded, showFullSize, fallbackAlt } ) => { /* eslint-disable-next-line jsx-a11y/alt-text */ ) } - { ! loaded && } + { ! image && } ); }; diff --git a/assets/js/atomic/blocks/product-elements/image/constants.js b/assets/js/atomic/blocks/product-elements/image/constants.js deleted file mode 100644 index d5d7f1f2d..000000000 --- a/assets/js/atomic/blocks/product-elements/image/constants.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { image, Icon } from '@wordpress/icons'; - -export const BLOCK_TITLE = __( - 'Product Image', - 'woo-gutenberg-products-block' -); -export const BLOCK_ICON = ( - -); -export const BLOCK_DESCRIPTION = __( - 'Display the main product image', - 'woo-gutenberg-products-block' -); diff --git a/assets/js/atomic/blocks/product-elements/image/edit.js b/assets/js/atomic/blocks/product-elements/image/edit.js index f0deda5fc..7d18c6461 100644 --- a/assets/js/atomic/blocks/product-elements/image/edit.js +++ b/assets/js/atomic/blocks/product-elements/image/edit.js @@ -3,8 +3,9 @@ */ import { __ } from '@wordpress/i18n'; import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; -import { createInterpolateElement } from '@wordpress/element'; -import { getAdminLink } from '@woocommerce/settings'; +import { createInterpolateElement, useEffect } from '@wordpress/element'; +import { getAdminLink, getSettingWithCoercion } from '@woocommerce/settings'; +import { isBoolean } from '@woocommerce/types'; import { Disabled, PanelBody, @@ -19,15 +20,32 @@ import { * Internal dependencies */ import Block from './block'; -import withProductSelector from '../shared/with-product-selector'; -import { BLOCK_TITLE, BLOCK_ICON } from './constants'; -const Edit = ( { attributes, setAttributes } ) => { +const Edit = ( { attributes, setAttributes, context } ) => { const { showProductLink, imageSizing, showSaleBadge, saleBadgeAlign } = attributes; const blockProps = useBlockProps(); + const isDescendentOfQueryLoop = Number.isFinite( context.queryId ); + + useEffect( + () => setAttributes( { isDescendentOfQueryLoop } ), + [ setAttributes, isDescendentOfQueryLoop ] + ); + + const isBlockThemeEnabled = getSettingWithCoercion( + 'is_block_theme_enabled', + false, + isBoolean + ); + + useEffect( () => { + if ( isBlockThemeEnabled && attributes.imageSizing !== 'full-size' ) { + setAttributes( { imageSizing: 'full-size' } ); + } + }, [ attributes.imageSizing, isBlockThemeEnabled, setAttributes ] ); + return (
@@ -56,7 +74,7 @@ const Edit = ( { attributes, setAttributes } ) => { 'woo-gutenberg-products-block' ) } help={ __( - 'Overlay a "sale" badge if the product is on-sale.', + 'Display a “sale” badge if the product is on-sale.', 'woo-gutenberg-products-block' ) } checked={ showSaleBadge } @@ -100,63 +118,58 @@ const Edit = ( { attributes, setAttributes } ) => { /> ) } - Customizer.', - 'woo-gutenberg-products-block' - ), - { - a: ( - // eslint-disable-next-line jsx-a11y/anchor-has-content - - ), - } - ) } - value={ imageSizing } - onChange={ ( value ) => - setAttributes( { imageSizing: value } ) - } - > - - Customizer.', + 'woo-gutenberg-products-block' + ), + { + a: ( + // eslint-disable-next-line jsx-a11y/anchor-has-content + + ), + } ) } - /> - + value={ imageSizing } + onChange={ ( value ) => + setAttributes( { imageSizing: value } ) + } + > + + + + ) } - +
); }; -export default withProductSelector( { - icon: BLOCK_ICON, - label: BLOCK_TITLE, - description: __( - 'Choose a product to display its image.', - 'woo-gutenberg-products-block' - ), -} )( Edit ); +export default Edit; diff --git a/assets/js/atomic/blocks/product-elements/image/frontend.js b/assets/js/atomic/blocks/product-elements/image/frontend.js index b6c773996..2add7452a 100644 --- a/assets/js/atomic/blocks/product-elements/image/frontend.js +++ b/assets/js/atomic/blocks/product-elements/image/frontend.js @@ -7,6 +7,6 @@ import { withFilteredAttributes } from '@woocommerce/shared-hocs'; * Internal dependencies */ import Block from './block'; -import attributes from './attributes'; +import { attributes } from './attributes'; export default withFilteredAttributes( attributes )( Block ); diff --git a/assets/js/atomic/blocks/product-elements/image/index.js b/assets/js/atomic/blocks/product-elements/image/index.js index d132b276e..41bed967a 100644 --- a/assets/js/atomic/blocks/product-elements/image/index.js +++ b/assets/js/atomic/blocks/product-elements/image/index.js @@ -2,30 +2,45 @@ * External dependencies */ import { registerBlockType } from '@wordpress/blocks'; +import { image, Icon } from '@wordpress/icons'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import sharedConfig from '../shared/config'; -import attributes from './attributes'; -import { supports } from './supports'; -import { Save } from './save'; import edit from './edit'; -import { - BLOCK_TITLE as title, - BLOCK_ICON as icon, - BLOCK_DESCRIPTION as description, -} from './constants'; + +import { supports } from './supports'; +import { attributes } from './attributes'; +import sharedConfig from '../shared/config'; const blockConfig = { apiVersion: 2, - title, - description, - icon: { src: icon }, + name: 'woocommerce/product-image', + title: __( 'Product Image', 'woo-gutenberg-products-block' ), + icon: { + src: ( + + ), + }, + keywords: [ 'WooCommerce' ], + description: __( + 'Display the main product image.', + 'woo-gutenberg-products-block' + ), + usesContext: [ 'query', 'queryId', 'postId' ], + parent: [ + '@woocommerce/all-products', + '@woocommerce/single-product', + 'core/post-template', + ], + textdomain: 'woo-gutenberg-products-block', attributes, - edit, supports, - save: Save, + edit, }; registerBlockType( 'woocommerce/product-image', { diff --git a/assets/js/atomic/blocks/product-elements/image/save.tsx b/assets/js/atomic/blocks/product-elements/image/save.tsx deleted file mode 100644 index 03a720e27..000000000 --- a/assets/js/atomic/blocks/product-elements/image/save.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/** - * External dependencies - */ -import { useBlockProps } from '@wordpress/block-editor'; -import classnames from 'classnames'; - -type Props = { - attributes: Record< string, unknown > & { - className?: string; - }; -}; - -export const Save = ( { attributes }: Props ): JSX.Element => { - return ( -
- ); -}; diff --git a/assets/js/atomic/blocks/product-elements/image/supports.ts b/assets/js/atomic/blocks/product-elements/image/supports.ts index 15b724aa9..0a60da1c9 100644 --- a/assets/js/atomic/blocks/product-elements/image/supports.ts +++ b/assets/js/atomic/blocks/product-elements/image/supports.ts @@ -2,13 +2,14 @@ * External dependencies */ import { isFeaturePluginBuild } from '@woocommerce/block-settings'; +import { hasSpacingStyleSupport } from '@woocommerce/utils'; /** * Internal dependencies */ -import { hasSpacingStyleSupport } from '../../../../utils/global-style'; export const supports = { + html: false, ...( isFeaturePluginBuild() && { __experimentalBorder: { radius: true, diff --git a/assets/js/atomic/blocks/product-elements/save.js b/assets/js/atomic/blocks/product-elements/save.js index d99801c45..1bf167d2d 100644 --- a/assets/js/atomic/blocks/product-elements/save.js +++ b/assets/js/atomic/blocks/product-elements/save.js @@ -4,6 +4,10 @@ import classnames from 'classnames'; const save = ( { attributes } ) => { + if ( attributes.isDescendentOfQueryLoop ) { + return null; + } + return (
); diff --git a/assets/js/atomic/blocks/product-elements/shared/config.tsx b/assets/js/atomic/blocks/product-elements/shared/config.tsx index fece0dcb9..a300985e7 100644 --- a/assets/js/atomic/blocks/product-elements/shared/config.tsx +++ b/assets/js/atomic/blocks/product-elements/shared/config.tsx @@ -3,7 +3,6 @@ */ import { __ } from '@wordpress/i18n'; import { Icon, grid } from '@wordpress/icons'; -import { isExperimentalBuild } from '@woocommerce/block-settings'; import type { BlockConfiguration } from '@wordpress/blocks'; /** @@ -29,9 +28,7 @@ const sharedConfig: Omit< BlockConfiguration, 'attributes' | 'title' > = { supports: { html: false, }, - parent: isExperimentalBuild() - ? undefined - : [ '@woocommerce/all-products', '@woocommerce/single-product' ], + parent: [ '@woocommerce/all-products', '@woocommerce/single-product' ], save, deprecated: [ { diff --git a/assets/js/atomic/blocks/product-elements/tag-list/constants.js b/assets/js/atomic/blocks/product-elements/tag-list/constants.js index 296e21685..313221244 100644 --- a/assets/js/atomic/blocks/product-elements/tag-list/constants.js +++ b/assets/js/atomic/blocks/product-elements/tag-list/constants.js @@ -12,6 +12,6 @@ export const BLOCK_ICON = ( ); export const BLOCK_DESCRIPTION = __( - 'Display a list of tags belonging to a product.', + 'Display the list of tags that are assigned to a product.', 'woo-gutenberg-products-block' ); diff --git a/assets/js/base/components/README.md b/assets/js/base/components/README.md index 23e3a6619..3e4c68c26 100644 --- a/assets/js/base/components/README.md +++ b/assets/js/base/components/README.md @@ -1,5 +1,5 @@ # WooCommerce Blocks - General Purpose Components -These are shared components used in WooCommerce blocks, and may be used in the store front end (shopper experience) as well as the editor or admin dashboard. +These are shared components used in WooCommerce blocks, and may be used in the store front end (shopper experience) as well as the editor or admin dashboard. -See [_Components & Storybook_](docs/contributors/storybook.md) doc for more information. +See [_Components & Storybook_](../../../../docs/contributors/contributing/storybook-and-components.md) doc for more information. diff --git a/assets/js/base/components/cart-checkout/product-details/index.tsx b/assets/js/base/components/cart-checkout/product-details/index.tsx index 5e851df92..90298a24e 100644 --- a/assets/js/base/components/cart-checkout/product-details/index.tsx +++ b/assets/js/base/components/cart-checkout/product-details/index.tsx @@ -1,7 +1,6 @@ /** * External dependencies */ -import { kebabCase } from 'lodash'; import { decodeEntities } from '@wordpress/html-entities'; import type { ProductResponseItemData } from '@woocommerce/type-defs/product-response'; @@ -32,15 +31,10 @@ const ProductDetails = ( { { details.map( ( detail ) => { // Support both `key` and `name` props const name = detail?.key || detail.name || ''; - const className = name - ? `wc-block-components-product-details__${ kebabCase( - name - ) }` - : ''; return (
  • { name && ( <> diff --git a/assets/js/base/components/cart-checkout/product-details/test/__snapshots__/index.js.snap b/assets/js/base/components/cart-checkout/product-details/test/__snapshots__/index.js.snap index 37a5d3cef..bfce44143 100644 --- a/assets/js/base/components/cart-checkout/product-details/test/__snapshots__/index.js.snap +++ b/assets/js/base/components/cart-checkout/product-details/test/__snapshots__/index.js.snap @@ -5,7 +5,7 @@ exports[`ProductDetails should not render hidden details 1`] = ` className="wc-block-components-product-details" >
  • { +}: ReturnToCartButtonProps ): JSX.Element | null => { + const cartLink = link || CART_URL; + if ( ! cartLink ) { + return null; + } return ( diff --git a/assets/js/base/components/cart-checkout/shipping-rates-control/index.tsx b/assets/js/base/components/cart-checkout/shipping-rates-control/index.tsx index eea684b19..ec34bc47d 100644 --- a/assets/js/base/components/cart-checkout/shipping-rates-control/index.tsx +++ b/assets/js/base/components/cart-checkout/shipping-rates-control/index.tsx @@ -65,9 +65,7 @@ const Packages = ( { packageData={ packageData } collapsible={ !! collapsible } collapse={ !! collapse } - showItems={ - showItems || packageData?.shipping_rates?.length > 1 - } + showItems={ showItems || packages.length > 1 } noResultsMessage={ noResultsMessage } renderOption={ renderOption } /> diff --git a/assets/js/base/components/checkbox-list/index.tsx b/assets/js/base/components/checkbox-list/index.tsx index 198dc6146..8b4c05068 100644 --- a/assets/js/base/components/checkbox-list/index.tsx +++ b/assets/js/base/components/checkbox-list/index.tsx @@ -4,6 +4,7 @@ import { __, _n, sprintf } from '@wordpress/i18n'; import { Fragment, useMemo, useState } from '@wordpress/element'; import classNames from 'classnames'; +import { CheckboxControl } from '@woocommerce/blocks-checkout'; /** * Internal dependencies @@ -132,19 +133,15 @@ const CheckboxList = ( { ! showExpanded && index >= limit && { hidden: true } ) } > - { - onChange( event.target.value ); - } } + className="wc-block-checkbox-list__checkbox" + label={ option.label } checked={ checked.includes( option.value ) } - disabled={ isDisabled } + onChange={ () => { + onChange( option.value ); + } } /> -
  • { shouldTruncateOptions && index === limit - 1 && diff --git a/assets/js/base/components/chip/style.scss b/assets/js/base/components/chip/style.scss index d8c23a9f1..58a3ebf0c 100644 --- a/assets/js/base/components/chip/style.scss +++ b/assets/js/base/components/chip/style.scss @@ -3,7 +3,7 @@ align-items: center; border: 0; display: inline-flex; - padding: em($gap-smallest * 0.5) 0.5em em($gap-smallest); + padding: em($gap-smallest) 0.5em; margin: 0 0.365em 0.365em 0; border-radius: 0; line-height: 1; @@ -14,8 +14,9 @@ &:hover, &:focus, &:active { - background: $gray-200; - color: $gray-900; + background: transparent; + color: inherit; + border: 1px solid; } &.wc-block-components-chip--radius-small { @@ -27,27 +28,28 @@ &.wc-block-components-chip--radius-large { border-radius: 2em; padding-left: 0.75em; - padding-right: 0.75em; + padding-right: 0.25em; } .wc-block-components-chip__text { flex-grow: 1; } - &.is-removable { - padding-right: 0.5em; - } &.is-removable .wc-block-components-chip__text { - padding-right: 0.25em; + padding-right: 0.5em; } .wc-block-components-chip__remove { - @include font-size(smaller); - background: transparent; + background: $gray-200; border: 0; + border-radius: 25px; appearance: none; padding: 0; + height: 16px; + width: 16px; + line-height: 16px; + margin: 0; } .wc-block-components-chip__remove-icon { - vertical-align: middle; + fill: $gray-900; } } @@ -67,11 +69,15 @@ button.wc-block-components-chip:hover > .wc-block-components-chip__remove, button.wc-block-components-chip:focus > .wc-block-components-chip__remove, .wc-block-components-chip__remove:hover, .wc-block-components-chip__remove:focus { - fill: $alert-red; + background: $gray-600; + + .wc-block-components-chip__remove-icon { + fill: #fff; + } } button.wc-block-components-chip:disabled > .wc-block-components-chip__remove, .wc-block-components-chip__remove:disabled { - fill: $gray-600; + fill: #fff; cursor: not-allowed; } diff --git a/assets/js/base/components/filter-element-label/index.tsx b/assets/js/base/components/filter-element-label/index.tsx index e7d3714a9..4806d3bfb 100644 --- a/assets/js/base/components/filter-element-label/index.tsx +++ b/assets/js/base/components/filter-element-label/index.tsx @@ -14,7 +14,7 @@ interface FilterElementLabelProps { count: number | null; } /** - * The label for an filter elements. + * The label for a filter element. * * @param {Object} props Incoming props for the component. * @param {string} props.name The name for the label. @@ -27,7 +27,7 @@ const FilterElementLabel = ( { return ( <> { name } - { count && Number.isFinite( count ) && ( + { count !== null && Number.isFinite( count ) && (
    ); diff --git a/assets/js/blocks/active-filters/edit.tsx b/assets/js/blocks/active-filters/edit.tsx index c001bd714..f7edb12e6 100644 --- a/assets/js/blocks/active-filters/edit.tsx +++ b/assets/js/blocks/active-filters/edit.tsx @@ -21,6 +21,7 @@ import { */ import Block from './block'; import type { Attributes } from './types'; +import './editor.scss'; const Edit = ( { attributes, @@ -37,7 +38,7 @@ const Edit = ( { @@ -52,6 +53,7 @@ const Edit = ( { displayStyle: value, } ) } + className="wc-block-active-filter__style-toggle" > { + if ( ! isLoading ) { + return null; + } + + return ( + <> + { [ ...Array( displayStyle === 'list' ? 2 : 3 ) ].map( ( x, i ) => ( +
  • + +
  • + ) ) } + + ); +}; + +export default FilterPlaceholders; diff --git a/assets/js/blocks/active-filters/index.tsx b/assets/js/blocks/active-filters/index.tsx index b1cb933b8..3f3e35a6e 100644 --- a/assets/js/blocks/active-filters/index.tsx +++ b/assets/js/blocks/active-filters/index.tsx @@ -19,7 +19,7 @@ import { Attributes } from './types'; registerBlockType( metadata, { title: __( 'Active Product Filters', 'woo-gutenberg-products-block' ), description: __( - 'Show the currently active product filters. Works in combination with the All Products and filters blocks.', + 'Display the currently active product filters.', 'woo-gutenberg-products-block' ), icon: { diff --git a/assets/js/blocks/active-filters/style.scss b/assets/js/blocks/active-filters/style.scss index 16e9ee3eb..30adf7fd4 100644 --- a/assets/js/blocks/active-filters/style.scss +++ b/assets/js/blocks/active-filters/style.scss @@ -1,14 +1,37 @@ +.wp-block-woocommerce-active-filters { + h1, + h2, + h3, + h4, + h5, + h6 { + text-transform: inherit; + } + + .wc-block-filter-title-placeholder { + .wc-block-active-filters__title { + height: 1em; + } + } + + > .wc-block-active-filters__title { + margin-top: $gap-small; + margin-bottom: $gap-small; + } +} + .wc-block-active-filters { margin-bottom: $gap-large; overflow: hidden; .wc-block-active-filters__clear-all { - @include font-size(regular); - float: right; + @include font-size(small); border: none; + margin-top: 15px; padding: 0; text-decoration: underline; cursor: pointer; + float: right; &, &:hover, @@ -19,17 +42,39 @@ } } + .wc-block-active-filters__clear-all-placeholder { + @include placeholder(); + display: inline-block; + width: 80px; + height: 1em; + float: right; + border-radius: 0; + } + .wc-block-active-filters__list { margin: 0 0 $gap-smallest; padding: 0; list-style: none outside; clear: both; + &.wc-block-active-filters--loading { + margin-top: $gap-small; + display: flex; + flex-direction: column; + flex-wrap: nowrap; + + &.wc-block-active-filters__list--chips { + flex-direction: row; + flex-wrap: wrap; + align-items: flex-end; + gap: 0 10px; + } + } + li { - margin: 0; + margin: 9px 0 0; padding: 0; list-style: none outside; - clear: both; ul { margin: 0; @@ -43,10 +88,54 @@ } } } + > li:first-child { + margin: 0; + } + li.show-loading-state-list { + display: inline-block; + + > span { + @include placeholder(); + display: inline-block; + box-shadow: none; + border-radius: 0; + height: 1em; + width: 100%; + } + } + + li.show-loading-state-chips { + display: inline-block; + + > span { + @include placeholder(); + display: inline-block; + box-shadow: none; + border-radius: 13px; + height: 1em; + width: 100%; + min-width: 70px; + margin-right: 15px !important; + } + + &:last-of-type > span { + margin-right: 0 !important; + } + + &:nth-child(3) { + flex-grow: 1; + max-width: 200px; + } + } + + > .wc-block-active-filters__list-item .wc-block-active-filters__list-item-name { + margin: 9px 0 0; + } } .wc-block-active-filters__list-item-type { @include font-size(smaller); + font-weight: bold; text-transform: uppercase; letter-spacing: 0.1em; margin: $gap 0 0; @@ -59,24 +148,39 @@ } .wc-block-active-filters__list-item-name { - font-weight: bold; - display: block; + display: flex; + align-items: center; position: relative; - padding: 0 16px 0 0; + padding: 0; } .wc-block-active-filters__list-item-remove { - background: transparent; + @include font-size(smaller); + background: $gray-200; border: 0; + border-radius: 25px; appearance: none; + padding: 0; height: 16px; width: 16px; + line-height: 16px; padding: 0; - position: absolute; - right: 0; - top: 50%; - margin: -8px 0 0 0; + margin: 0 0.5em 0 0; color: currentColor; + + &:hover, + &:focus { + background: $gray-600; + + .wc-block-components-chip__remove-icon { + fill: #fff; + } + } + + &:disabled { + color: $gray-200; + cursor: not-allowed; + } } .wc-block-active-filters__list--chips { @@ -90,7 +194,6 @@ } .wc-block-components-chip { - @include font-size(small); margin-top: em($gap-small * 0.25); margin-bottom: em($gap-small * 0.25); } diff --git a/assets/js/blocks/active-filters/utils.tsx b/assets/js/blocks/active-filters/utils.tsx index 7cc3efa44..7786ebae0 100644 --- a/assets/js/blocks/active-filters/utils.tsx +++ b/assets/js/blocks/active-filters/utils.tsx @@ -7,6 +7,7 @@ import { RemovableChip } from '@woocommerce/base-components/chip'; import Label from '@woocommerce/base-components/label'; import { getQueryArgs, addQueryArgs, removeQueryArgs } from '@wordpress/url'; import { changeUrl } from '@woocommerce/utils'; +import { Icon, closeSmall } from '@wordpress/icons'; /** * Format a min/max price range to display. @@ -44,6 +45,7 @@ interface RemovableListItemProps { name: string; prefix?: string | JSX.Element; showLabel?: boolean; + isLoading?: boolean; displayStyle: string; removeCallback?: () => void; } @@ -103,47 +105,18 @@ export const renderRemovableListItem = ( { /> ) : ( - { prefixedName } + { prefixedName } ) } @@ -191,6 +164,35 @@ export const removeArgsFromFilterUrl = ( changeUrl( newUrl ); }; +/** + * Prefixes typically expected before filters in the URL. + */ +const FILTER_QUERY_VALUES = [ + 'min_price', + 'max_price', + 'rating_filter', + 'filter_', + 'query_type_', +]; + +/** + * Check if the URL contains arguments that could be Woo filter keys. + */ +const keyIsAFilter = ( key: string ): boolean => { + let keyIsFilter = false; + + for ( let i = 0; FILTER_QUERY_VALUES.length > i; i++ ) { + const keyToMatch = FILTER_QUERY_VALUES[ i ]; + const trimmedKey = key.substring( 0, keyToMatch.length ); + if ( keyToMatch === trimmedKey ) { + keyIsFilter = true; + break; + } + } + + return keyIsFilter; +}; + /** * Clean the filter URL. */ @@ -205,13 +207,7 @@ export const cleanFilterUrl = () => { const remainingArgs = Object.fromEntries( Object.keys( args ) .filter( ( arg ) => { - if ( - arg.includes( 'min_price' ) || - arg.includes( 'max_price' ) || - arg.includes( 'rating_filter' ) || - arg.includes( 'filter_' ) || - arg.includes( 'query_type_' ) - ) { + if ( keyIsAFilter( arg ) ) { return false; } @@ -224,3 +220,60 @@ export const cleanFilterUrl = () => { changeUrl( newUrl ); }; + +export const maybeUrlContainsFilters = (): boolean => { + if ( ! window ) { + return false; + } + + const url = window.location.href; + const args = getQueryArgs( url ); + const filterKeys = Object.keys( args ); + let maybeHasFilter = false; + + for ( let i = 0; filterKeys.length > i; i++ ) { + const key = filterKeys[ i ]; + if ( keyIsAFilter( key ) ) { + maybeHasFilter = true; + break; + } + } + + return maybeHasFilter; +}; + +interface StoreAttributes { + attribute_id: string; + attribute_label: string; + attribute_name: string; + attribute_orderby: string; + attribute_public: number; + attribute_type: string; +} + +export const urlContainsAttributeFilter = ( + attributes: StoreAttributes[] +): boolean => { + if ( ! window ) { + return false; + } + + const storeAttributeKeys = attributes.map( + ( attr ) => `filter_${ attr.attribute_name }` + ); + + const url = window.location.href; + const args = getQueryArgs( url ); + const urlFilterKeys = Object.keys( args ); + let filterIsInUrl = false; + + for ( let i = 0; urlFilterKeys.length > i; i++ ) { + const urlKey = urlFilterKeys[ i ]; + if ( storeAttributeKeys.includes( urlKey ) ) { + filterIsInUrl = true; + break; + } + } + + return filterIsInUrl; +}; diff --git a/assets/js/blocks/attribute-filter/block.json b/assets/js/blocks/attribute-filter/block.json index 86d313b11..38625f302 100644 --- a/assets/js/blocks/attribute-filter/block.json +++ b/assets/js/blocks/attribute-filter/block.json @@ -1,8 +1,8 @@ { "name": "woocommerce/attribute-filter", "version": "1.0.0", - "title": "Filter Products by Attribute", - "description": "Allow customers to filter the grid by product attribute, such as color. Works in combination with the All Products block.", + "title": "Filter by Attribute", + "description": "Enable customers to filter the product grid by selecting one or more attributes, such as color.", "category": "woocommerce", "keywords": [ "WooCommerce" ], "supports": { @@ -48,7 +48,7 @@ }, "selectType": { "type": "string", - "default": "multiple" + "default": "multiple" }, "isPreview": { "type": "boolean", diff --git a/assets/js/blocks/attribute-filter/block.tsx b/assets/js/blocks/attribute-filter/block.tsx index 3e42739a1..a7b2a13d2 100644 --- a/assets/js/blocks/attribute-filter/block.tsx +++ b/assets/js/blocks/attribute-filter/block.tsx @@ -14,8 +14,8 @@ import { useCollectionData, } from '@woocommerce/base-context/hooks'; import { useCallback, useEffect, useState, useMemo } from '@wordpress/element'; -import CheckboxList from '@woocommerce/base-components/checkbox-list'; import Label from '@woocommerce/base-components/filter-element-label'; +import FilterResetButton from '@woocommerce/base-components/filter-reset-button'; import FilterSubmitButton from '@woocommerce/base-components/filter-submit-button'; import isShallowEqual from '@wordpress/is-shallow-equal'; import { decodeEntities } from '@wordpress/html-entities'; @@ -29,6 +29,7 @@ import { isString, objectHasProp, } from '@woocommerce/types'; +import { Icon, chevronDown } from '@wordpress/icons'; import { changeUrl, PREFIX_QUERY_ARG_FILTER_TYPE, @@ -36,7 +37,8 @@ import { } from '@woocommerce/utils'; import { difference } from 'lodash'; import FormTokenField from '@woocommerce/base-components/form-token-field'; -import classNames from 'classnames'; +import FilterTitlePlaceholder from '@woocommerce/base-components/filter-placeholder'; +import classnames from 'classnames'; /** * Internal dependencies @@ -52,8 +54,10 @@ import { isQueryArgsEqual, parseTaxonomyToGenerateURL, formatSlug, + generateUniqueId, } from './utils'; import { BlockAttributes, DisplayOption } from './types'; +import CheckboxFilter from './checkbox-filter'; /** * Formats filter values into a string for the URL parameters needed for filtering PHP templates. @@ -111,6 +115,13 @@ const AttributeFilterBlock = ( { const [ checked, setChecked ] = useState( initialFilters ); + /* + FormTokenField forces the dropdown to reopen on reset, so we create a unique ID to use as the components key. + This will force the component to remount on reset when we change this value. + More info: https://github.com/woocommerce/woocommerce-blocks/pull/6920#issuecomment-1222402482 + */ + const [ remountKey, setRemountKey ] = useState( generateUniqueId() ); + const [ displayedOptions, setDisplayedOptions ] = useState< DisplayOption[] >( @@ -227,6 +238,7 @@ const AttributeFilterBlock = ( { .filter( ( option ): option is DisplayOption => !! option ); setDisplayedOptions( newOptions ); + setRemountKey( generateUniqueId() ); }, [ attributeObject?.taxonomy, attributeTerms, @@ -431,7 +443,7 @@ const AttributeFilterBlock = ( { ] ); /** - * Try get the current attribute filter from the URl. + * Try to get the current attribute filter from the URl. */ useEffect( () => { if ( hasSetFilterDefaultsFromUrl || attributeTermsLoading ) { @@ -483,137 +495,189 @@ const AttributeFilterBlock = ( {

    { __( - 'The selected attribute does not have any term assigned to products.', + 'There are no products with the selected attributes.', 'woo-gutenberg-products-block' ) }

    ); } - return null; } const TagName = `h${ blockAttributes.headingLevel }` as keyof JSX.IntrinsicElements; - const isLoading = ! blockAttributes.isPreview && attributeTermsLoading; - const isDisabled = ! blockAttributes.isPreview && filteredCountsLoading; + const termsLoading = ! blockAttributes.isPreview && attributeTermsLoading; + const countsLoading = ! blockAttributes.isPreview && filteredCountsLoading; + + const isLoading = + ( termsLoading || countsLoading ) && displayedOptions.length === 0; + + if ( ! isLoading && displayedOptions.length === 0 ) { + return null; + } + + const heading = ( + + { blockAttributes.heading } + + ); + + const filterHeading = isLoading ? ( + { heading } + ) : ( + heading + ); return ( <> - { ! isEditor && - blockAttributes.heading && - displayedOptions.length > 0 && ( - - { blockAttributes.heading } - - ) } + { ! isEditor && blockAttributes.heading && filterHeading }
    { blockAttributes.displayStyle === 'dropdown' ? ( - ! checked.includes( option.value ) - ) - .map( ( option ) => option.formattedValue ) } - disabled={ isDisabled } - placeholder={ sprintf( - /* translators: %s attribute name. */ - __( 'Any %s', 'woo-gutenberg-products-block' ), - attributeObject.label - ) } - onChange={ ( tokens: string[] ) => { - if ( ! multiple && tokens.length > 1 ) { - tokens = [ tokens[ tokens.length - 1 ] ]; - } - - tokens = tokens.map( ( token ) => { - const displayOption = displayedOptions.find( + <> + - option.formattedValue === token - ); - - return displayOption - ? displayOption.value - : token; - } ); - - const added = difference( tokens, checked ); - - if ( added.length === 1 ) { - return onChange( added[ 0 ] ); - } - - const removed = difference( checked, tokens ); - if ( removed.length === 1 ) { - onChange( removed[ 0 ] ); - } - } } - value={ checked } - displayTransform={ ( value: string ) => { - const result = displayedOptions.find( ( option ) => - [ - option.value, - option.formattedValue, - ].includes( value ) - ); - return result ? result.textLabel : value; - } } - saveTransform={ formatSlug } - messages={ { - added: sprintf( - /* translators: %s is the attribute label. */ + ! checked.includes( option.value ) + ) + .map( ( option ) => option.formattedValue ) } + disabled={ isLoading } + placeholder={ sprintf( + /* translators: %s attribute name. */ __( - '%s filter added.', + 'Select %s', 'woo-gutenberg-products-block' ), attributeObject.label - ), - removed: sprintf( - /* translators: %s is the attribute label. */ - __( - '%s filter removed.', - 'woo-gutenberg-products-block' + ) } + onChange={ ( tokens: string[] ) => { + if ( ! multiple && tokens.length > 1 ) { + tokens = [ tokens[ tokens.length - 1 ] ]; + } + + tokens = tokens.map( ( token ) => { + const displayOption = displayedOptions.find( + ( option ) => + option.formattedValue === token + ); + + return displayOption + ? displayOption.value + : token; + } ); + + const added = difference( tokens, checked ); + + if ( added.length === 1 ) { + return onChange( added[ 0 ] ); + } + + const removed = difference( checked, tokens ); + if ( removed.length === 1 ) { + onChange( removed[ 0 ] ); + } + } } + value={ checked } + displayTransform={ ( value: string ) => { + const result = displayedOptions.find( + ( option ) => + [ + option.value, + option.formattedValue, + ].includes( value ) + ); + return result ? result.textLabel : value; + } } + saveTransform={ formatSlug } + messages={ { + added: sprintf( + /* translators: %s is the attribute label. */ + __( + '%s filter added.', + 'woo-gutenberg-products-block' + ), + attributeObject.label ), - attributeObject.label - ), - remove: sprintf( - /* translators: %s is the attribute label. */ - __( - 'Remove %s filter.', - 'woo-gutenberg-products-block' + removed: sprintf( + /* translators: %s is the attribute label. */ + __( + '%s filter removed.', + 'woo-gutenberg-products-block' + ), + attributeObject.label ), - attributeObject.label.toLocaleLowerCase() - ), - __experimentalInvalid: sprintf( - /* translators: %s is the attribute label. */ - __( - 'Invalid %s filter.', - 'woo-gutenberg-products-block' + remove: sprintf( + /* translators: %s is the attribute label. */ + __( + 'Remove %s filter.', + 'woo-gutenberg-products-block' + ), + attributeObject.label.toLocaleLowerCase() ), - attributeObject.label.toLocaleLowerCase() - ), - } } - /> + __experimentalInvalid: sprintf( + /* translators: %s is the attribute label. */ + __( + 'Invalid %s filter.', + 'woo-gutenberg-products-block' + ), + attributeObject.label.toLocaleLowerCase() + ), + } } + /> + { multiple && ( + + ) } + ) : ( - + ) } +
    + +
    + { checked.length > 0 && ! isLoading && ( + { + setChecked( [] ); + setRemountKey( generateUniqueId() ); + if ( hasSetFilterDefaultsFromUrl ) { + onSubmit( [] ); + } + } } + screenReaderLabel={ __( + 'Reset attribute filter', + 'woo-gutenberg-products-block' + ) } /> ) } { blockAttributes.showFilterButton && ( onSubmit( checked ) } /> ) } diff --git a/assets/js/blocks/attribute-filter/checkbox-filter.tsx b/assets/js/blocks/attribute-filter/checkbox-filter.tsx new file mode 100644 index 000000000..6213f7411 --- /dev/null +++ b/assets/js/blocks/attribute-filter/checkbox-filter.tsx @@ -0,0 +1,47 @@ +/** + * External dependencies + */ +import CheckboxList from '@woocommerce/base-components/checkbox-list'; +/** + * Internal dependencies + */ +import { DisplayOption } from './types'; + +interface CheckboxFilterProps { + className?: string; + isLoading?: boolean; + isDisabled?: boolean; + limit?: number; + checked?: string[]; + onChange: ( value: string ) => void; + options?: DisplayOption[]; +} + +const CheckboxFilter = ( { + isLoading = false, + options, + checked, + onChange, +}: CheckboxFilterProps ) => { + if ( isLoading ) { + return ( + <> + + + + ); + } + + return ( + + ); +}; + +export default CheckboxFilter; diff --git a/assets/js/blocks/attribute-filter/edit.tsx b/assets/js/blocks/attribute-filter/edit.tsx index cecedb246..5c44864cf 100644 --- a/assets/js/blocks/attribute-filter/edit.tsx +++ b/assets/js/blocks/attribute-filter/edit.tsx @@ -166,24 +166,16 @@ const Edit = ( { attributes, setAttributes, debouncedSpeak }: EditProps ) => { return ( setAttributes( { @@ -206,13 +198,6 @@ const Edit = ( { attributes, setAttributes, debouncedSpeak }: EditProps ) => { setAttributes( { headingLevel: newLevel } ) } /> - - { selectType: value, } ) } + className="wc-block-attribute-filter__multiple-toggle" > { { selectType === 'multiple' && ( { queryType: value, } ) } + className="wc-block-attribute-filter__conditions-toggle" > @@ -291,6 +278,7 @@ const Edit = ( { attributes, setAttributes, debouncedSpeak }: EditProps ) => { displayStyle: value, } ) } + className="wc-block-attribute-filter__display-toggle" > { { { className="wc-block-attribute-filter" icon={ } label={ __( - 'Filter Products by Attribute', + 'Filter by Attribute', 'woo-gutenberg-products-block' ) } instructions={ __( - 'Display a list of filters based on a chosen attribute.', + 'Display a list of filters based on the selected attributes.', 'woo-gutenberg-products-block' ) } > @@ -388,7 +376,7 @@ const Edit = ( { attributes, setAttributes, debouncedSpeak }: EditProps ) => { setIsEditing( false ); debouncedSpeak( __( - 'Showing Filter Products by Attribute block preview.', + 'Now displaying a preview of the Filter Products by Attribute block.', 'woo-gutenberg-products-block' ) ); @@ -400,11 +388,11 @@ const Edit = ( { attributes, setAttributes, debouncedSpeak }: EditProps ) => { className="wc-block-attribute-filter" icon={ } label={ __( - 'Filter Products by Attribute', + 'Filter by Attribute', 'woo-gutenberg-products-block' ) } instructions={ __( - 'Display a list of filters based on a chosen attribute.', + 'Display a list of filters based on the selected attributes.', 'woo-gutenberg-products-block' ) } > diff --git a/assets/js/blocks/attribute-filter/index.tsx b/assets/js/blocks/attribute-filter/index.tsx index 450565fdd..7081fd2b2 100644 --- a/assets/js/blocks/attribute-filter/index.tsx +++ b/assets/js/blocks/attribute-filter/index.tsx @@ -17,9 +17,9 @@ import { blockAttributes } from './attributes'; import metadata from './block.json'; registerBlockType( metadata, { - title: __( 'Filter Products by Attribute', 'woo-gutenberg-products-block' ), + title: __( 'Filter by Attribute', 'woo-gutenberg-products-block' ), description: __( - 'Allow customers to filter the grid by product attribute, such as color. Works in combination with the All Products block.', + 'Enable customers to filter the product grid by selecting one or more attributes, such as color.', 'woo-gutenberg-products-block' ), icon: { diff --git a/assets/js/blocks/attribute-filter/style.scss b/assets/js/blocks/attribute-filter/style.scss index 7e025a827..22d5cba7a 100644 --- a/assets/js/blocks/attribute-filter/style.scss +++ b/assets/js/blocks/attribute-filter/style.scss @@ -2,24 +2,53 @@ // We need to override it because by default the global styles applied the border-style: solid; // Our goal is not to have a border on main wrapper DOM element border-style: none !important; + + h1, + h2, + h3, + h4, + h5, + h6 { + text-transform: inherit; + } + + > .wc-block-attribute-filter__title { + margin-top: $gap-small; + margin-bottom: $gap-small; + } } .wc-block-attribute-filter { - margin-bottom: $gap-large; + margin-bottom: $gap; border-radius: inherit; border-color: inherit; + .is-loading { + @include placeholder(); + box-shadow: none; + border-radius: 0; + height: 1em; + margin-top: $gap; + } + &.style-dropdown { + position: relative; display: flex; gap: $gap; - border-radius: inherit; - border-color: inherit; align-items: flex-start; .wc-block-components-filter-submit-button { height: 36px; line-height: 1; } + + > svg { + position: absolute; + right: 8px; + top: 50%; + transform: translateY(-50%); + pointer-events: none; + } } .wc-block-attribute-filter-list { @@ -42,12 +71,122 @@ flex-grow: 1; max-width: unset; width: 0; + height: max-content; + + &:not(.is-loading) { + border: 1px solid $gray-700 !important; + border-radius: 4px; + } + + &.is-loading { + border-radius: em(4px); + } + } + + .wc-blocks-components-form-token-field-wrapper .components-form-token-field__input-container { + border: 0; + padding: $gap-smaller; + + .components-form-token-field__input::placeholder { + color: $black; + } + + .components-form-token-field__suggestions-list { + border: 1px solid $gray-700; + border-radius: 4px; + margin-top: $gap-smaller; + max-height: 21em; + + .components-form-token-field__suggestion { + color: $black; + border: 1px solid $gray-400; + border-radius: 4px; + margin: $gap-small; + padding: $gap-small; + } + } + } +} + +.wc-block-attribute-filter__multiple-toggle, +.wc-block-attribute-filter__conditions-toggle, +.wc-block-attribute-filter__display-toggle { + width: 100%; +} + +.woocommerce-product-attributes { + .woocommerce-search-list__search { + .components-base-control__label { + @include reset-typography(); + @include font-size(regular); + color: $gray-700; + } } +} + +.wc-block-attribute-filter__actions { + align-items: center; + display: flex; + gap: $gap; + justify-content: flex-end; + + .wc-block-components-filter-submit-button { + margin-left: 0; + &:disabled { + opacity: 0.6; + cursor: auto; + } + } - .is-single .wc-block-attribute-filter-list-count, - .wc-blocks-components-form-token-field-wrapper .wc-block-attribute-filter-list-count { - opacity: 0.6; + .wc-block-filter-submit-button.wc-block-components-filter-submit-button.wc-block-attribute-filter__button { + margin-top: 0; } +} + +.editor-styles-wrapper .wc-block-components-checkbox { + margin-top: em($gap); +} + +.wc-block-components-checkbox { + margin-top: em($gap); +} + +.wc-blocks-components-form-token-field-wrapper:not(.single-selection) .components-form-token-field__input-container { + padding: $gap-smallest 30px $gap-smallest $gap-smaller; + + .components-form-token-field__token-text { + background-color: $white; + border: 1px solid; + border-right: 0; + border-radius: 25px 0 0 25px; + padding: em($gap-smallest) em($gap-smaller) em($gap-smallest) em($gap-small); + line-height: 22px; + } + + > .components-form-token-field__input { + margin: em($gap-smallest) 0; + } + + .components-button.components-form-token-field__remove-token { + background-color: $white; + border: 1px solid; + border-left: 0; + border-radius: 0 25px 25px 0; + padding: 1px em($gap-smallest) 0 0; + + &.has-icon svg { + background-color: $gray-200; + border-radius: 25px; + } + } +} +.editor-styles-wrapper .wc-block-attribute-filter__button.wc-block-attribute-filter__button, +.wc-block-attribute-filter__button.wc-block-attribute-filter__button { + padding: em($gap-smaller) em($gap); + @include font-size(small); + height: max-content; + line-height: normal; + width: max-content; } diff --git a/assets/js/blocks/attribute-filter/utils.ts b/assets/js/blocks/attribute-filter/utils.ts index 78d7363d9..754ce1bf4 100644 --- a/assets/js/blocks/attribute-filter/utils.ts +++ b/assets/js/blocks/attribute-filter/utils.ts @@ -16,6 +16,10 @@ interface Param { slug: Array< string >; } +export function generateUniqueId() { + return Math.floor( Math.random() * Date.now() ); +} + export const parseTaxonomyToGenerateURL = ( taxonomy: string ) => taxonomy.replace( 'pa_', '' ); diff --git a/assets/js/blocks/cart-checkout-shared/block-settings/index.tsx b/assets/js/blocks/cart-checkout-shared/block-settings/index.tsx new file mode 100644 index 000000000..1b2e4a691 --- /dev/null +++ b/assets/js/blocks/cart-checkout-shared/block-settings/index.tsx @@ -0,0 +1,39 @@ +/** + * External dependencies + */ +import { InspectorControls } from '@wordpress/block-editor'; +import { PanelBody, ToggleControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { BlockAttributes } from '@wordpress/blocks'; + +export const BlockSettings = ( { + attributes, + setAttributes, +}: { + attributes: BlockAttributes; + setAttributes: ( attrs: BlockAttributes ) => void; +} ) => { + const { hasDarkControls } = attributes; + return ( + + + + setAttributes( { + hasDarkControls: ! hasDarkControls, + } ) + } + /> + + + ); +}; diff --git a/assets/js/blocks/cart-checkout-shared/index.js b/assets/js/blocks/cart-checkout-shared/index.js index 802e11a9e..e739d7a87 100644 --- a/assets/js/blocks/cart-checkout-shared/index.js +++ b/assets/js/blocks/cart-checkout-shared/index.js @@ -2,3 +2,5 @@ export * from './hacks'; export * from './use-forced-layout'; export * from './editor-utils'; export * from './use-view-switcher'; +export * from './sidebar-notices'; +export * from './block-settings'; diff --git a/assets/js/blocks/cart-checkout-shared/payment-methods/express-payment/cart-express-payment.js b/assets/js/blocks/cart-checkout-shared/payment-methods/express-payment/cart-express-payment.js index 760a03f04..aa3509613 100644 --- a/assets/js/blocks/cart-checkout-shared/payment-methods/express-payment/cart-express-payment.js +++ b/assets/js/blocks/cart-checkout-shared/payment-methods/express-payment/cart-express-payment.js @@ -66,7 +66,7 @@ const CartExpressPayment = () => {
    { /* translators: Shown in the Cart block between the express payment methods and the Proceed to Checkout button */ } - { __( 'Or', 'woo-gutenberg-products-block' ) } + { __( 'Any', 'woo-gutenberg-products-block' ) }
    ); diff --git a/assets/js/blocks/cart-checkout-shared/payment-methods/no-payment-methods/index.js b/assets/js/blocks/cart-checkout-shared/payment-methods/no-payment-methods/index.js index 92500e882..f6677acaa 100644 --- a/assets/js/blocks/cart-checkout-shared/payment-methods/no-payment-methods/index.js +++ b/assets/js/blocks/cart-checkout-shared/payment-methods/no-payment-methods/index.js @@ -38,7 +38,7 @@ const NoPaymentMethodsPlaceholder = () => { > { __( - 'Your store does not have any payment methods configured that support the checkout block. Once you have configured a compatible payment method it will be shown here.', + 'Your store does not have any payment methods that support the Checkout block. Once you have configured a compatible payment method it will be displayed here.', 'woo-gutenberg-products-block' ) } diff --git a/assets/js/blocks/cart-checkout-shared/payment-methods/payment-method-error-boundary.js b/assets/js/blocks/cart-checkout-shared/payment-methods/payment-method-error-boundary.js index 3cf7013c1..aef36cc8a 100644 --- a/assets/js/blocks/cart-checkout-shared/payment-methods/payment-method-error-boundary.js +++ b/assets/js/blocks/cart-checkout-shared/payment-methods/payment-method-error-boundary.js @@ -24,7 +24,7 @@ class PaymentMethodErrorBoundary extends Component { if ( hasError ) { let errorText = __( - 'This site is experiencing difficulties with this payment method. Please contact the owner of the site for assistance.', + 'We are experiencing difficulties with this payment method. Please contact us for assistance.', 'woo-gutenberg-products-block' ); if ( isEditor || CURRENT_USER_IS_ADMIN ) { diff --git a/assets/js/blocks/cart-checkout-shared/sidebar-notices/index.tsx b/assets/js/blocks/cart-checkout-shared/sidebar-notices/index.tsx new file mode 100644 index 000000000..d2e5e5f63 --- /dev/null +++ b/assets/js/blocks/cart-checkout-shared/sidebar-notices/index.tsx @@ -0,0 +1,105 @@ +/** + * External dependencies + */ +import { createHigherOrderComponent } from '@wordpress/compose'; +import { + InspectorControls, + store as blockEditorStore, +} from '@wordpress/block-editor'; +import { addFilter, hasFilter } from '@wordpress/hooks'; +import type { StoreDescriptor } from '@wordpress/data'; +import { CartCheckoutSidebarCompatibilityNotice } from '@woocommerce/editor-components/sidebar-compatibility-notice'; +import { + DefaultNotice, + LegacyNotice, +} from '@woocommerce/editor-components/default-notice'; +import { useSelect } from '@wordpress/data'; +import { CartCheckoutFeedbackPrompt } from '@woocommerce/editor-components/feedback-prompt'; +import { isWcVersion } from '@woocommerce/settings'; +declare module '@wordpress/editor' { + let store: StoreDescriptor; +} + +declare module '@wordpress/core-data' { + let store: StoreDescriptor; +} + +declare module '@wordpress/block-editor' { + let store: StoreDescriptor; +} + +const withSidebarNotices = createHigherOrderComponent( + ( BlockEdit ) => ( props ) => { + const addressFieldOrAccountBlocks = [ + 'woocommerce/checkout-shipping-address-block', + 'woocommerce/checkout-billing-address-block', + 'woocommerce/checkout-contact-information-block', + 'woocommerce/checkout-fields-block', + ]; + const { clientId } = props; + const { isCart, isCheckout, isAddressFieldBlock } = useSelect( + ( select ) => { + const { getBlockParentsByBlockName, getBlockName } = + select( blockEditorStore ); + const parent = getBlockParentsByBlockName( clientId, [ + 'woocommerce/cart', + 'woocommerce/checkout', + ] ).map( getBlockName ); + const currentBlockName = getBlockName( clientId ); + return { + isCart: + parent.includes( 'woocommerce/cart' ) || + currentBlockName === 'woocommerce/cart', + isCheckout: + parent.includes( 'woocommerce/checkout' ) || + currentBlockName === 'woocommerce/checkout', + isAddressFieldBlock: + addressFieldOrAccountBlocks.includes( + currentBlockName + ), + }; + } + ); + return ( + <> + { ( isCart || isCheckout ) && ( + + { isWcVersion( '6.9.0', '>=' ) ? ( + + ) : ( + + ) } + + + { isAddressFieldBlock ? null : ( + + ) } + + ) } + + + + ); + }, + 'withSidebarNotices' +); + +if ( + ! hasFilter( + 'editor.BlockEdit', + 'woocommerce/add/sidebar-compatibility-notice' + ) +) { + addFilter( + 'editor.BlockEdit', + 'woocommerce/add/sidebar-compatibility-notice', + withSidebarNotices, + 11 + ); +} diff --git a/assets/js/blocks/cart/block.js b/assets/js/blocks/cart/block.js index 17e869010..98f1767f1 100644 --- a/assets/js/blocks/cart/block.js +++ b/assets/js/blocks/cart/block.js @@ -74,7 +74,10 @@ const ScrollOnError = ( { scrollToTop } ) => { }; const Block = ( { attributes, children, scrollToTop } ) => ( { - const { hasDarkControls } = attributes; - const { currentPostId } = useEditorContext(); - return ( - - { currentPostId !== CART_PAGE_ID && ( - - { createInterpolateElement( - __( - 'If you would like to use this block as your default cart you must update your
    page settings in WooCommerce.', - 'woo-gutenberg-products-block' - ), - { - a: ( - // eslint-disable-next-line jsx-a11y/anchor-has-content - - ), - } - ) } - - ) } - - - setAttributes( { - hasDarkControls: ! hasDarkControls, - } ) - } - /> - - - - ); -}; - export const Edit = ( { className, attributes, setAttributes, clientId } ) => { const { hasDarkControls } = attributes; const { currentView, component: ViewSwitcherComponent } = useViewSwitcher( @@ -135,8 +73,15 @@ export const Edit = ( { className, attributes, setAttributes, clientId } ) => { registeredBlocks: ALLOWED_BLOCKS, defaultTemplate, } ); + return (
    + + + { currentView={ currentView } previewData={ { previewCart } } > - - - { ViewSwitcherComponent } - + { ViewSwitcherComponent } { -
    ); }; diff --git a/assets/js/blocks/cart/editor.scss b/assets/js/blocks/cart/editor.scss index a88f6759d..175359367 100644 --- a/assets/js/blocks/cart/editor.scss +++ b/assets/js/blocks/cart/editor.scss @@ -1,7 +1,3 @@ -.wc-block-cart__page-notice { - margin: 0; -} - body.wc-lock-selected-block--move { .block-editor-block-mover__move-button-container, .block-editor-block-mover { diff --git a/assets/js/blocks/cart/index.js b/assets/js/blocks/cart/index.js index f7364d5af..c3f1bd7c7 100644 --- a/assets/js/blocks/cart/index.js +++ b/assets/js/blocks/cart/index.js @@ -6,8 +6,7 @@ import classnames from 'classnames'; import { InnerBlocks } from '@wordpress/block-editor'; import { cart } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; -import { createBlock } from '@wordpress/blocks'; +import { registerBlockType, createBlock } from '@wordpress/blocks'; /** * Internal dependencies */ @@ -36,7 +35,6 @@ const settings = { align: [ 'wide' ], html: false, multiple: false, - __experimentalExposeControlsToChildren: true, }, example: { attributes: { @@ -111,4 +109,4 @@ const settings = { ], }; -registerFeaturePluginBlockType( blockName, settings ); +registerBlockType( blockName, settings ); diff --git a/assets/js/blocks/cart/inner-blocks/cart-accepted-payment-methods-block/index.tsx b/assets/js/blocks/cart/inner-blocks/cart-accepted-payment-methods-block/index.tsx index d69772b7e..c1daab6d8 100644 --- a/assets/js/blocks/cart/inner-blocks/cart-accepted-payment-methods-block/index.tsx +++ b/assets/js/blocks/cart/inner-blocks/cart-accepted-payment-methods-block/index.tsx @@ -1,7 +1,7 @@ /** * External dependencies */ -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; import { Icon, payment } from '@wordpress/icons'; /** @@ -9,18 +9,15 @@ import { Icon, payment } from '@wordpress/icons'; */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( - 'woocommerce/cart-accepted-payment-methods-block', - { - icon: { - src: ( - - ), - }, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/cart-accepted-payment-methods-block', { + icon: { + src: ( + + ), + }, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/cart/inner-blocks/cart-express-payment-block/edit.tsx b/assets/js/blocks/cart/inner-blocks/cart-express-payment-block/edit.tsx index 8d7fc22c1..7b2710df5 100644 --- a/assets/js/blocks/cart/inner-blocks/cart-express-payment-block/edit.tsx +++ b/assets/js/blocks/cart/inner-blocks/cart-express-payment-block/edit.tsx @@ -27,7 +27,7 @@ const NoExpressPaymentMethodsPlaceholder = () => { > { __( - "Your store doesn't have any Payment Methods that support the Express Checkout Block. If they are added, they will be shown here.", + 'Your store does not have any payment methods that support the Express Checkout block. Once you have configured a compatible payment method, it will be displayed here.', 'woo-gutenberg-products-block' ) } diff --git a/assets/js/blocks/cart/inner-blocks/cart-express-payment-block/index.tsx b/assets/js/blocks/cart/inner-blocks/cart-express-payment-block/index.tsx index 87bbc0bac..eaee14e11 100644 --- a/assets/js/blocks/cart/inner-blocks/cart-express-payment-block/index.tsx +++ b/assets/js/blocks/cart/inner-blocks/cart-express-payment-block/index.tsx @@ -2,14 +2,14 @@ * External dependencies */ import { Icon, payment } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( 'woocommerce/cart-express-payment-block', { +registerBlockType( 'woocommerce/cart-express-payment-block', { icon: { src: ( - ), - }, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/cart-order-summary-discount-block', { + icon: { + src: ( + + ), + }, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/cart/inner-blocks/cart-order-summary-fee/index.tsx b/assets/js/blocks/cart/inner-blocks/cart-order-summary-fee/index.tsx index a2c81308d..185553829 100644 --- a/assets/js/blocks/cart/inner-blocks/cart-order-summary-fee/index.tsx +++ b/assets/js/blocks/cart/inner-blocks/cart-order-summary-fee/index.tsx @@ -3,14 +3,14 @@ */ import { totals } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( 'woocommerce/cart-order-summary-fee-block', { +registerBlockType( 'woocommerce/cart-order-summary-fee-block', { icon: { src: ( - ), - }, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/cart-order-summary-heading-block', { + icon: { + src: ( + + ), + }, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/index.tsx b/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/index.tsx index a347933ee..9f300d474 100644 --- a/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/index.tsx +++ b/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/index.tsx @@ -3,7 +3,7 @@ */ import { totals } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies @@ -11,19 +11,16 @@ import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; import { Edit, Save } from './edit'; import attributes from './attributes'; -registerFeaturePluginBlockType( - 'woocommerce/cart-order-summary-shipping-block', - { - icon: { - src: ( - - ), - }, - attributes, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/cart-order-summary-shipping-block', { + icon: { + src: ( + + ), + }, + attributes, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/cart/inner-blocks/cart-order-summary-subtotal/index.tsx b/assets/js/blocks/cart/inner-blocks/cart-order-summary-subtotal/index.tsx index 1f88b0c55..6ffe89c26 100644 --- a/assets/js/blocks/cart/inner-blocks/cart-order-summary-subtotal/index.tsx +++ b/assets/js/blocks/cart/inner-blocks/cart-order-summary-subtotal/index.tsx @@ -3,25 +3,22 @@ */ import { totals } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( - 'woocommerce/cart-order-summary-subtotal-block', - { - icon: { - src: ( - - ), - }, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/cart-order-summary-subtotal-block', { + icon: { + src: ( + + ), + }, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/cart/inner-blocks/cart-order-summary-taxes/index.tsx b/assets/js/blocks/cart/inner-blocks/cart-order-summary-taxes/index.tsx index 0ad9966f6..35b936007 100644 --- a/assets/js/blocks/cart/inner-blocks/cart-order-summary-taxes/index.tsx +++ b/assets/js/blocks/cart/inner-blocks/cart-order-summary-taxes/index.tsx @@ -3,7 +3,7 @@ */ import { totals } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies @@ -11,7 +11,7 @@ import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; import { Edit, Save } from './edit'; import attributes from './attributes'; -registerFeaturePluginBlockType( 'woocommerce/cart-order-summary-taxes-block', { +registerBlockType( 'woocommerce/cart-order-summary-taxes-block', { icon: { src: ( JSX.Element | null; }; -export const CheckoutBlockContext = createContext< CheckoutBlockContextProps >( - { +export const CheckoutBlockContext: React.Context< CheckoutBlockContextProps > = + createContext< CheckoutBlockContextProps >( { allowCreateAccount: false, showCompanyField: false, showApartmentField: false, @@ -38,10 +38,9 @@ export const CheckoutBlockContext = createContext< CheckoutBlockContextProps >( showReturnToCart: true, cartPageId: 0, showRateAfterTaxName: false, - } -); + } ); -export const CheckoutBlockControlsContext = +export const CheckoutBlockControlsContext: React.Context< CheckoutBlockControlsContextProps > = createContext< CheckoutBlockControlsContextProps >( { addressFieldControls: () => null, accountControls: () => null, diff --git a/assets/js/blocks/checkout/edit.tsx b/assets/js/blocks/checkout/edit.tsx index 3d1f87131..2e7087526 100644 --- a/assets/js/blocks/checkout/edit.tsx +++ b/assets/js/blocks/checkout/edit.tsx @@ -9,11 +9,7 @@ import { InspectorControls, } from '@wordpress/block-editor'; import { SidebarLayout } from '@woocommerce/base-components/sidebar-layout'; -import { - CheckoutProvider, - EditorProvider, - useEditorContext, -} from '@woocommerce/base-context'; +import { CheckoutProvider, EditorProvider } from '@woocommerce/base-context'; import { previewCart, previewSavedPaymentMethods, @@ -21,15 +17,10 @@ import { import { PanelBody, ToggleControl, - Notice, CheckboxControl, } from '@wordpress/components'; -import { CartCheckoutFeedbackPrompt } from '@woocommerce/editor-components/feedback-prompt'; -import { CHECKOUT_PAGE_ID } from '@woocommerce/block-settings'; -import { createInterpolateElement } from '@wordpress/element'; -import { getAdminLink } from '@woocommerce/settings'; -import { CartCheckoutCompatibilityNotice } from '@woocommerce/editor-components/compatibility-notices'; import type { TemplateArray } from '@wordpress/blocks'; +import { CartCheckoutFeedbackPrompt } from '@woocommerce/editor-components/feedback-prompt'; /** * Internal dependencies @@ -38,8 +29,10 @@ import './inner-blocks'; import './styles/editor.scss'; import { addClassToBody, + BlockSettings, useBlockPropsWithLocking, } from '../cart-checkout-shared'; +import '../cart-checkout-shared/sidebar-notices'; import { CheckoutBlockContext, CheckoutBlockControlsContext } from './context'; import type { Attributes } from './types'; @@ -52,67 +45,6 @@ const ALLOWED_BLOCKS: string[] = [ 'woocommerce/checkout-totals-block', ]; -const BlockSettings = ( { - attributes, - setAttributes, -}: { - attributes: Attributes; - setAttributes: ( attributes: Record< string, unknown > ) => undefined; -} ): JSX.Element => { - const { hasDarkControls } = attributes; - const { currentPostId } = useEditorContext(); - - return ( - - { currentPostId !== CHECKOUT_PAGE_ID && ( - - { createInterpolateElement( - __( - 'If you would like to use this block as your default checkout you must update your
    page settings in WooCommerce.', - 'woo-gutenberg-products-block' - ), - { - a: ( - // eslint-disable-next-line jsx-a11y/anchor-has-content - - ), - } - ) } - - ) } - - - setAttributes( { - hasDarkControls: ! hasDarkControls, - } ) - } - /> - - - - ); -}; - export const Edit = ( { attributes, setAttributes, @@ -166,6 +98,7 @@ export const Edit = ( { } /> + ); @@ -225,18 +158,21 @@ export const Edit = ( { /> ) } + ); const blockProps = useBlockPropsWithLocking(); return (
    - + + + -
    ); }; diff --git a/assets/js/blocks/checkout/index.tsx b/assets/js/blocks/checkout/index.tsx index 9aa7ca122..e17c4f789 100644 --- a/assets/js/blocks/checkout/index.tsx +++ b/assets/js/blocks/checkout/index.tsx @@ -4,8 +4,7 @@ import classnames from 'classnames'; import { fields } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; -import { createBlock } from '@wordpress/blocks'; +import { registerBlockType, createBlock } from '@wordpress/blocks'; import type { BlockInstance } from '@wordpress/blocks'; /** @@ -140,4 +139,4 @@ const settings = { ], }; -registerFeaturePluginBlockType( metadata, settings ); +registerBlockType( metadata, settings ); diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-actions-block/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-actions-block/index.tsx index 35742f0ad..f13017aef 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-actions-block/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-actions-block/index.tsx @@ -2,7 +2,7 @@ * External dependencies */ import { Icon, button } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies @@ -10,7 +10,7 @@ import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; import attributes from './attributes'; import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( 'woocommerce/checkout-actions-block', { +registerBlockType( 'woocommerce/checkout-actions-block', { icon: { src: ( - ), - }, - attributes, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/checkout-contact-information-block', { + icon: { + src: ( + + ), + }, + attributes, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/edit.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/edit.tsx index e93ad860a..8ad880a65 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/edit.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/edit.tsx @@ -27,7 +27,7 @@ const NoExpressPaymentMethodsPlaceholder = () => { > { __( - "Your store doesn't have any Payment Methods that support the Express Checkout Block. If they are added, they will be shown here.", + 'Your store does not have any payment methods that support the Express Checkout block. Once you have configured a compatible payment method, it will be displayed here.', 'woo-gutenberg-products-block' ) } diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/index.tsx index 8b9e69c4b..aef02ba8f 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/index.tsx @@ -2,14 +2,14 @@ * External dependencies */ import { Icon, payment } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( 'woocommerce/checkout-express-payment-block', { +registerBlockType( 'woocommerce/checkout-express-payment-block', { icon: { src: ( - ), - }, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/checkout-order-summary-cart-items-block', { + icon: { + src: ( + + ), + }, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-coupon-form/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-coupon-form/index.tsx index 28441776d..74b33e10f 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-coupon-form/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-coupon-form/index.tsx @@ -2,25 +2,22 @@ * External dependencies */ import { Icon, tag } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( - 'woocommerce/checkout-order-summary-coupon-form-block', - { - icon: { - src: ( - - ), - }, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/checkout-order-summary-coupon-form-block', { + icon: { + src: ( + + ), + }, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-discount/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-discount/index.tsx index fb206bd1e..5b8cb9dd6 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-discount/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-discount/index.tsx @@ -3,25 +3,22 @@ */ import { totals } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( - 'woocommerce/checkout-order-summary-discount-block', - { - icon: { - src: ( - - ), - }, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/checkout-order-summary-discount-block', { + icon: { + src: ( + + ), + }, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-fee/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-fee/index.tsx index 419b02a8e..734abe15b 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-fee/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-fee/index.tsx @@ -3,25 +3,22 @@ */ import { totals } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( - 'woocommerce/checkout-order-summary-fee-block', - { - icon: { - src: ( - - ), - }, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/checkout-order-summary-fee-block', { + icon: { + src: ( + + ), + }, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-shipping/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-shipping/index.tsx index 4303d250f..d5ae8ad86 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-shipping/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-shipping/index.tsx @@ -3,25 +3,22 @@ */ import { totals } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( - 'woocommerce/checkout-order-summary-shipping-block', - { - icon: { - src: ( - - ), - }, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/checkout-order-summary-shipping-block', { + icon: { + src: ( + + ), + }, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-subtotal/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-subtotal/index.tsx index b20dfefaf..6bd6946d8 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-subtotal/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-subtotal/index.tsx @@ -3,25 +3,22 @@ */ import { totals } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( - 'woocommerce/checkout-order-summary-subtotal-block', - { - icon: { - src: ( - - ), - }, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/checkout-order-summary-subtotal-block', { + icon: { + src: ( + + ), + }, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-taxes/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-taxes/index.tsx index a0af3bcf5..18c860c43 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-taxes/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-taxes/index.tsx @@ -3,7 +3,7 @@ */ import { totals } from '@woocommerce/icons'; import { Icon } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies @@ -11,19 +11,16 @@ import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; import { Edit, Save } from './edit'; import attributes from './attributes'; -registerFeaturePluginBlockType( - 'woocommerce/checkout-order-summary-taxes-block', - { - icon: { - src: ( - - ), - }, - attributes, - edit: Edit, - save: Save, - } -); +registerBlockType( 'woocommerce/checkout-order-summary-taxes-block', { + icon: { + src: ( + + ), + }, + attributes, + edit: Edit, + save: Save, +} ); diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/index.tsx index 136c00f1b..f1e78b8a7 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/index.tsx @@ -2,7 +2,7 @@ * External dependencies */ import { Icon, payment } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies @@ -10,7 +10,7 @@ import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; import { Edit, Save } from './edit'; import attributes from './attributes'; -registerFeaturePluginBlockType( 'woocommerce/checkout-payment-block', { +registerBlockType( 'woocommerce/checkout-payment-block', { icon: { src: (

    { __( - 'You currently have the following shipping integrations active.', + 'The following shipping integrations are active on your store.', 'woo-gutenberg-products-block' ) }

    diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/index.tsx index 4eebcd528..972723db9 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/index.tsx @@ -2,7 +2,7 @@ * External dependencies */ import { Icon, shipping } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies @@ -10,7 +10,7 @@ import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; import { Edit, Save } from './edit'; import attributes from './attributes'; -registerFeaturePluginBlockType( 'woocommerce/checkout-shipping-methods-block', { +registerBlockType( 'woocommerce/checkout-shipping-methods-block', { icon: { src: ( ${ __( + ? `
    ${ __( 'Terms and Conditions', 'woo-gutenberg-products-block' ) }` : __( 'Terms and Conditions', 'woo-gutenberg-products-block' ); const privacyPageLink = PRIVACY_URL - ? `${ __( + ? `${ __( 'Privacy Policy', 'woo-gutenberg-products-block' ) }` diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/edit.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/edit.tsx index d7752894c..005d5ee36 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/edit.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/edit.tsx @@ -134,7 +134,7 @@ export const Edit = ( { >

    { __( - "You don't seem to have a Terms and Conditions and/or a Privacy Policy pages setup.", + "You don't have any Terms and Conditions and/or Privacy Policy pages set up.", 'woo-gutenberg-products-block' ) }

    diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/index.tsx index fc34879e5..60ff1e045 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-terms-block/index.tsx @@ -2,13 +2,13 @@ * External dependencies */ import { Icon, customPostType } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( 'woocommerce/checkout-terms-block', { +registerBlockType( 'woocommerce/checkout-terms-block', { icon: { src: ( { expect( queryByText( container, - "You don't seem to have a Terms and Conditions and/or a Privacy Policy pages setup." + "You don't have any Terms and Conditions and/or Privacy Policy pages set up." ) ).toBeInTheDocument(); } ); diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-totals-block/index.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-totals-block/index.tsx index 1ef8f8850..aa3581bbf 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-totals-block/index.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-totals-block/index.tsx @@ -2,14 +2,14 @@ * External dependencies */ import { Icon, column } from '@wordpress/icons'; -import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; +import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; -registerFeaturePluginBlockType( 'woocommerce/checkout-totals-block', { +registerBlockType( 'woocommerce/checkout-totals-block', { icon: { src: ( { allowCreateAccount: boolean; hasDarkControls: boolean; showCompanyField: boolean; diff --git a/assets/js/blocks/classic-template/constants.ts b/assets/js/blocks/classic-template/constants.ts index f75f9f78b..dfeb37b33 100644 --- a/assets/js/blocks/classic-template/constants.ts +++ b/assets/js/blocks/classic-template/constants.ts @@ -2,10 +2,14 @@ * External dependencies */ import { __ } from '@wordpress/i18n'; - export const BLOCK_SLUG = 'woocommerce/legacy-template'; -export const TEMPLATES: Record< string, Record< string, string > > = { +/** + * Internal dependencies + */ +import { TemplateDetails } from './types'; + +export const TEMPLATES: TemplateDetails = { 'single-product': { title: __( 'WooCommerce Single Product Block', diff --git a/assets/js/blocks/classic-template/index.tsx b/assets/js/blocks/classic-template/index.tsx index 2bbf623b1..a6df1fecc 100644 --- a/assets/js/blocks/classic-template/index.tsx +++ b/assets/js/blocks/classic-template/index.tsx @@ -2,7 +2,6 @@ * External dependencies */ import { - Block, BlockEditProps, createBlock, getBlockType, @@ -26,6 +25,11 @@ import { useEffect } from '@wordpress/element'; import './editor.scss'; import './style.scss'; import { BLOCK_SLUG, TEMPLATES } from './constants'; +import { + isClassicTemplateBlockRegisteredWithAnotherTitle, + hasTemplateSupportForClassicTemplateBlock, + getTemplateDetailsBySlug, +} from './utils'; type Attributes = { template: string; @@ -40,10 +44,12 @@ const Edit = ( { const { replaceBlock } = useDispatch( 'core/block-editor' ); const blockProps = useBlockProps(); - const templateTitle = - TEMPLATES[ attributes.template ]?.title ?? attributes.template; - const templatePlaceholder = - TEMPLATES[ attributes.template ]?.placeholder ?? 'fallback'; + const templateDetails = getTemplateDetailsBySlug( + attributes.template, + TEMPLATES + ); + const templateTitle = templateDetails?.title ?? attributes.template; + const templatePlaceholder = templateDetails?.placeholder ?? 'fallback'; useEffect( () => @@ -65,12 +71,12 @@ const Edit = ( {

    { __( - 'Attention: Do not remove this block!', + 'Do not remove this block!', 'woo-gutenberg-products-block' ) } { ' ' } { __( - 'Removal will cause unintended effects on your store.', + 'Removing this will cause unintended effects on your store.', 'woo-gutenberg-products-block' ) }

    @@ -78,7 +84,7 @@ const Edit = ( { { sprintf( /* translators: %s is the template title */ __( - 'This is an editor placeholder for the %s. On your store this will be replaced by the template and display with your product image(s), title, price, etc. You can move this placeholder around and add further blocks around it to extend the template.', + 'This is a placeholder for the %s. In your store it will display the actual product image, title, price, etc. You can move this placeholder around and add more blocks around it to customize the template.', 'woo-gutenberg-products-block' ), templateTitle @@ -118,8 +124,6 @@ const Edit = ( { ); }; -const templates = Object.keys( TEMPLATES ); - const registerClassicTemplateBlock = ( { template, inserter, @@ -136,12 +140,13 @@ const registerClassicTemplateBlock = ( { * See https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues/5861 for more context */ registerBlockType( BLOCK_SLUG, { - title: template - ? TEMPLATES[ template ].title - : __( - 'WooCommerce Classic Template', - 'woo-gutenberg-products-block' - ), + title: + template && TEMPLATES[ template ] + ? TEMPLATES[ template ].title + : __( + 'WooCommerce Classic Template', + 'woo-gutenberg-products-block' + ), icon: ( | undefined, - parsedTemplate: string -) => block?.title !== TEMPLATES[ parsedTemplate ].title; - -const hasTemplateSupportForClassicTemplateBlock = ( parsedTemplate: string ) => - templates.includes( parsedTemplate ); - // @todo Refactor when there will be possible to show a block according on a template/post with a Gutenberg API. https://github.com/WordPress/gutenberg/pull/41718 let currentTemplateId: string | undefined; @@ -235,7 +231,10 @@ if ( isExperimentalBuild() ) { if ( block !== undefined && - ( ! hasTemplateSupportForClassicTemplateBlock( parsedTemplate ) || + ( ! hasTemplateSupportForClassicTemplateBlock( + parsedTemplate, + TEMPLATES + ) || isClassicTemplateBlockRegisteredWithAnotherTitle( block, parsedTemplate @@ -248,7 +247,10 @@ if ( isExperimentalBuild() ) { if ( block === undefined && - hasTemplateSupportForClassicTemplateBlock( parsedTemplate ) + hasTemplateSupportForClassicTemplateBlock( + parsedTemplate, + TEMPLATES + ) ) { registerClassicTemplateBlock( { template: parsedTemplate, diff --git a/assets/js/blocks/classic-template/test/utils.ts b/assets/js/blocks/classic-template/test/utils.ts new file mode 100644 index 000000000..8f413c21a --- /dev/null +++ b/assets/js/blocks/classic-template/test/utils.ts @@ -0,0 +1,47 @@ +/** + * Internal dependencies + */ +import { getTemplateDetailsBySlug } from '../utils'; + +const TEMPLATES = { + 'single-product': { + title: 'Single Product Title', + placeholder: 'Single Product Placeholder', + }, + 'archive-product': { + title: 'Product Archive Title', + placeholder: 'Product Archive Placeholder', + }, + 'archive-product': { + title: 'Product Archive Title', + placeholder: 'Product Archive Placeholder', + }, + 'taxonomy-product_cat': { + title: 'Product Taxonomy Title', + placeholder: 'Product Taxonomy Placeholder', + }, +}; + +describe( 'getTemplateDetailsBySlug', function () { + it( 'should return single-product object when given an exact match', () => { + expect( + getTemplateDetailsBySlug( 'single-product', TEMPLATES ) + ).toBeTruthy(); + expect( + getTemplateDetailsBySlug( 'single-product', TEMPLATES ) + ).toStrictEqual( TEMPLATES[ 'single-product' ] ); + } ); + + it( 'should return single-product object when given a partial match', () => { + expect( + getTemplateDetailsBySlug( 'single-product-hoodie', TEMPLATES ) + ).toBeTruthy(); + expect( + getTemplateDetailsBySlug( 'single-product-hoodie', TEMPLATES ) + ).toStrictEqual( TEMPLATES[ 'single-product' ] ); + } ); + + it( 'should return null object when given an incorrect match', () => { + expect( getTemplateDetailsBySlug( 'void', TEMPLATES ) ).toBeNull(); + } ); +} ); diff --git a/assets/js/blocks/classic-template/types.ts b/assets/js/blocks/classic-template/types.ts new file mode 100644 index 000000000..3e28296b6 --- /dev/null +++ b/assets/js/blocks/classic-template/types.ts @@ -0,0 +1 @@ +export type TemplateDetails = Record< string, Record< string, string > >; diff --git a/assets/js/blocks/classic-template/utils.ts b/assets/js/blocks/classic-template/utils.ts new file mode 100644 index 000000000..76a31299b --- /dev/null +++ b/assets/js/blocks/classic-template/utils.ts @@ -0,0 +1,49 @@ +/** + * External dependencies + */ +import { Block } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { TEMPLATES } from './constants'; +import { TemplateDetails } from './types'; + +// Finds the most appropriate template details object for specific template keys such as single-product-hoodie. +export function getTemplateDetailsBySlug( + parsedTemplate: string, + templates: TemplateDetails +) { + const templateKeys = Object.keys( templates ); + let templateDetails = null; + + for ( let i = 0; templateKeys.length > i; i++ ) { + const keyToMatch = parsedTemplate.substr( 0, templateKeys[ i ].length ); + const maybeTemplate = templates[ keyToMatch ]; + if ( maybeTemplate ) { + templateDetails = maybeTemplate; + break; + } + } + + return templateDetails; +} + +export function isClassicTemplateBlockRegisteredWithAnotherTitle( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + block: Block< any > | undefined, + parsedTemplate: string +) { + const templateDetails = getTemplateDetailsBySlug( + parsedTemplate, + TEMPLATES + ); + return block?.title !== templateDetails?.title; +} + +export function hasTemplateSupportForClassicTemplateBlock( + parsedTemplate: string, + templates: TemplateDetails +): boolean { + return getTemplateDetailsBySlug( parsedTemplate, templates ) ? true : false; +} diff --git a/assets/js/blocks/featured-items/featured-category/block.json b/assets/js/blocks/featured-items/featured-category/block.json index 00e75c843..1a9655716 100644 --- a/assets/js/blocks/featured-items/featured-category/block.json +++ b/assets/js/blocks/featured-items/featured-category/block.json @@ -3,15 +3,19 @@ "version": "1.0.0", "title": "Featured Category", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "description": "Visually highlight a product category and encourage prompt action.", "supports": { - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "color": { "background": true, - "text": true, - "__experimentalDuotone": ".wc-block-featured-category__background-image" + "text": true }, "spacing": { "padding": true, @@ -95,16 +99,9 @@ "showDesc": { "type": "boolean", "default": true - }, - "style": { - "type": "object", - "default": { - "color": { - "text": "#ffffff" - } - } } }, "textdomain": "woo-gutenberg-products-block", - "apiVersion": 2 + "apiVersion": 2, + "$schema": "https://schemas.wp.org/trunk/block.json" } diff --git a/assets/js/blocks/featured-items/featured-product/block.json b/assets/js/blocks/featured-items/featured-product/block.json index 119ecb2e2..cde0cdac4 100644 --- a/assets/js/blocks/featured-items/featured-product/block.json +++ b/assets/js/blocks/featured-items/featured-product/block.json @@ -2,7 +2,7 @@ "name": "woocommerce/featured-product", "version": "1.0.0", "title": "Featured Product", - "description": "Visually highlight a product or variation and encourage prompt action.", + "description": "Highlight a product or variation.", "category": "woocommerce", "keywords": [ "WooCommerce" ], "supports": { @@ -10,8 +10,7 @@ "html": false, "color": { "background": true, - "text": true, - "__experimentalDuotone": ".wc-block-featured-product__background-image" + "text": true }, "spacing": { "padding": true, @@ -101,16 +100,9 @@ "showPrice": { "type": "boolean", "default": true - }, - "style": { - "type": "object", - "default": { - "color": { - "text": "#ffffff" - } - } } }, "textdomain": "woo-gutenberg-products-block", - "apiVersion": 2 + "apiVersion": 2, + "$schema": "https://schemas.wp.org/trunk/block.json" } diff --git a/assets/js/blocks/featured-items/featured-product/block.tsx b/assets/js/blocks/featured-items/featured-product/block.tsx index 29d9f80a2..7978c8456 100644 --- a/assets/js/blocks/featured-items/featured-product/block.tsx +++ b/assets/js/blocks/featured-items/featured-product/block.tsx @@ -41,7 +41,7 @@ const CONTENT_CONFIG = { const EDIT_MODE_CONFIG = { ...GENERIC_CONFIG, description: __( - 'Visually highlight a product or variation and encourage prompt action', + 'Highlight a product or variation.', 'woo-gutenberg-products-block' ), editLabel: __( diff --git a/assets/js/blocks/featured-items/inspector-controls.tsx b/assets/js/blocks/featured-items/inspector-controls.tsx index 0daaaf72c..51663867f 100644 --- a/assets/js/blocks/featured-items/inspector-controls.tsx +++ b/assets/js/blocks/featured-items/inspector-controls.tsx @@ -162,13 +162,13 @@ export const InspectorControls = ( { } } > { __( - 'Choose “Cover” if you want the image to scale automatically to always fit its container.', + 'Select “Cover” to have the image automatically fit its container.', 'woo-gutenberg-products-block' ) } { __( - 'Note: by choosing “Cover” you will lose the ability to freely move the focal point precisely.', + 'This may affect your ability to freely move the focal point of the image.', 'woo-gutenberg-products-block' ) } diff --git a/assets/js/blocks/handpicked-products/edit-mode.tsx b/assets/js/blocks/handpicked-products/edit-mode.tsx index 111fe4e76..3a36e0708 100644 --- a/assets/js/blocks/handpicked-products/edit-mode.tsx +++ b/assets/js/blocks/handpicked-products/edit-mode.tsx @@ -30,7 +30,7 @@ export const HandpickedProductsEditMode = ( setIsEditing( ! isEditing ); debouncedSpeak( __( - 'Showing Hand-picked Products block preview.', + 'Now displaying a preview of the Hand-picked Products block.', 'woo-gutenberg-products-block' ) ); diff --git a/assets/js/blocks/mini-cart/edit.tsx b/assets/js/blocks/mini-cart/edit.tsx index d37968ae7..b8b51e42b 100644 --- a/assets/js/blocks/mini-cart/edit.tsx +++ b/assets/js/blocks/mini-cart/edit.tsx @@ -111,7 +111,7 @@ const Edit = ( { attributes, setAttributes }: Props ): ReactElement => { >

    { __( - 'Edit the appearance of your empty and filled mini cart contents.', + 'Edit the appearance of the Mini Cart.', 'woo-gutenberg-products-block' ) }

    diff --git a/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/empty-mini-cart-contents-block/block.json b/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/empty-mini-cart-contents-block/block.json index b8017ef7c..7b32de681 100644 --- a/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/empty-mini-cart-contents-block/block.json +++ b/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/empty-mini-cart-contents-block/block.json @@ -1,8 +1,8 @@ { "name": "woocommerce/empty-mini-cart-contents-block", "version": "1.0.0", - "title": "Empty Mini Cart Contents", - "description": "Contains blocks that are displayed when the mini cart is empty.", + "title": "Empty Mini Cart view.", + "description": "Blocks that are displayed when the Mini Cart is empty.", "category": "woocommerce", "supports": { "align": false, diff --git a/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/filled-mini-cart-contents-block/block.json b/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/filled-mini-cart-contents-block/block.json index 2f529ee20..f40d4d300 100644 --- a/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/filled-mini-cart-contents-block/block.json +++ b/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/filled-mini-cart-contents-block/block.json @@ -1,8 +1,8 @@ { "name": "woocommerce/filled-mini-cart-contents-block", "version": "1.0.0", - "title": "Filled Mini Cart Contents", - "description": "Contains blocks that are displayed when the mini cart has products.", + "title": "Filled Mini Cart view", + "description": "Contains blocks that display the content of the Mini Cart.", "category": "woocommerce", "supports": { "align": false, diff --git a/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-shopping-button-block/block.json b/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-shopping-button-block/block.json index 397a99d95..c81b1c38c 100644 --- a/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-shopping-button-block/block.json +++ b/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-shopping-button-block/block.json @@ -2,7 +2,7 @@ "name": "woocommerce/mini-cart-shopping-button-block", "version": "1.0.0", "title": "Mini Cart Shopping Button", - "description": "Block that displays the shopping button for the Mini Cart block.", + "description": "Block that displays the shopping button when the Mini Cart is empty.", "category": "woocommerce", "supports": { "align": false, diff --git a/assets/js/blocks/price-filter/block.json b/assets/js/blocks/price-filter/block.json index 3219b6739..8142a609a 100644 --- a/assets/js/blocks/price-filter/block.json +++ b/assets/js/blocks/price-filter/block.json @@ -1,8 +1,8 @@ { "name": "woocommerce/price-filter", "version": "1.0.0", - "title": "Filter Products by Price", - "description": "Allow customers to filter the products by choosing a lower or upper price limit. Works in combination with the All Products block.", + "title": "Filter by Price", + "description": "Enable customers to filter the product grid by choosing a price range.", "category": "woocommerce", "keywords": [ "WooCommerce" ], "supports": { @@ -27,6 +27,10 @@ "type": "boolean", "default": true }, + "inlineInput": { + "type": "boolean", + "default": false + }, "showFilterButton": { "type": "boolean", "default": false diff --git a/assets/js/blocks/price-filter/block.tsx b/assets/js/blocks/price-filter/block.tsx index cb75ad626..4e191b556 100644 --- a/assets/js/blocks/price-filter/block.tsx +++ b/assets/js/blocks/price-filter/block.tsx @@ -9,6 +9,7 @@ import { } from '@woocommerce/base-context/hooks'; import { useCallback, useState, useEffect } from '@wordpress/element'; import PriceSlider from '@woocommerce/base-components/price-slider'; +import FilterTitlePlaceholder from '@woocommerce/base-components/filter-placeholder'; import { useDebouncedCallback } from 'use-debounce'; import PropTypes from 'prop-types'; import { getCurrencyFromPriceResponse } from '@woocommerce/price-format'; @@ -164,6 +165,8 @@ const PriceFilterBlock = ( { setMinPriceQuery, ] ); + const [ isUpdating, setIsUpdating ] = useState( isLoading ); + // Updates the query based on slider values. const onSubmit = useCallback( ( newMinPrice, newMaxPrice ) => { @@ -206,6 +209,7 @@ const PriceFilterBlock = ( { // Callback when slider or input fields are changed. const onChange = useCallback( ( prices ) => { + setIsUpdating( true ); if ( prices[ 0 ] !== minPrice ) { setMinPrice( prices[ 0 ] ); } @@ -303,13 +307,26 @@ const PriceFilterBlock = ( { const TagName = `h${ attributes.headingLevel }` as keyof JSX.IntrinsicElements; + if ( ! isLoading && isUpdating ) { + setIsUpdating( false ); + } + + const heading = ( + + { attributes.heading } + + ); + + const filterHeading = + isLoading && isUpdating ? ( + { heading } + ) : ( + heading + ); + return ( <> - { ! isEditor && attributes.heading && ( - - { attributes.heading } - - ) } + { ! isEditor && attributes.heading && filterHeading }
    onSubmit( minPrice, maxPrice ) } isLoading={ isLoading } + isUpdating={ isUpdating } />
    diff --git a/assets/js/blocks/price-filter/edit.tsx b/assets/js/blocks/price-filter/edit.tsx index df8300236..fca50c6d9 100644 --- a/assets/js/blocks/price-filter/edit.tsx +++ b/assets/js/blocks/price-filter/edit.tsx @@ -32,8 +32,13 @@ export default function ( { attributes, setAttributes, }: BlockEditProps< Attributes > ) { - const { heading, headingLevel, showInputFields, showFilterButton } = - attributes; + const { + heading, + headingLevel, + showInputFields, + inlineInput, + showFilterButton, + } = attributes; const blockProps = useBlockProps(); @@ -41,14 +46,11 @@ export default function ( { return ( + { showInputFields && ( + + setAttributes( { + inlineInput: ! inlineInput, + } ) + } + help={ __( + 'Show input fields inline with the slider.', + 'woo-gutenberg-products-block' + ) } + /> + ) } } - label={ __( - 'Filter Products by Price', - 'woo-gutenberg-products-block' - ) } + label={ __( 'Filter by Price', 'woo-gutenberg-products-block' ) } instructions={ __( 'Display a slider to filter products in your store by price.', 'woo-gutenberg-products-block' @@ -131,7 +149,7 @@ export default function ( { >

    { __( - "Products with prices are needed for filtering by price. You haven't created any products yet.", + 'To filter your products by price you first need to assign prices to your products.', 'woo-gutenberg-products-block' ) }

    diff --git a/assets/js/blocks/price-filter/editor.scss b/assets/js/blocks/price-filter/editor.scss index 44c62d27d..f5b54119e 100644 --- a/assets/js/blocks/price-filter/editor.scss +++ b/assets/js/blocks/price-filter/editor.scss @@ -6,15 +6,25 @@ &::-webkit-slider-thumb { pointer-events: none; } + &::-moz-range-thumb { pointer-events: none; } + &::-ms-thumb { pointer-events: none; } } } +.wc-block-price-filter__price-range-toggle { + width: 100%; + + > div { + flex-grow: 1; + } +} + .wc-block-price-slider { .components-placeholder__instructions { border-bottom: 1px solid #e0e2e6; @@ -22,13 +32,16 @@ padding-bottom: 1em; margin-bottom: 2em; } + .components-placeholder__label svg { fill: currentColor; margin-right: 1ch; } + .components-placeholder__fieldset { display: block; /* Disable flex box */ } + .wc-block-price-slider__add-product-button { margin: 0 0 1em; vertical-align: middle; @@ -41,6 +54,7 @@ vertical-align: middle; } } + .wc-block-price-slider__read_more_button { display: block; margin-bottom: 1em; diff --git a/assets/js/blocks/price-filter/frontend.ts b/assets/js/blocks/price-filter/frontend.ts index ac4e2badb..ef69736b0 100644 --- a/assets/js/blocks/price-filter/frontend.ts +++ b/assets/js/blocks/price-filter/frontend.ts @@ -14,6 +14,7 @@ const getProps = ( el: HTMLElement ) => { return { attributes: { showInputFields: el.dataset.showinputfields === 'true', + inlineInput: el.dataset.inlineInput === 'true', showFilterButton: el.dataset.showfilterbutton === 'true', heading: el.dataset.heading || blockAttributes.heading.default, headingLevel: el.dataset.headingLevel diff --git a/assets/js/blocks/price-filter/index.tsx b/assets/js/blocks/price-filter/index.tsx index 407c62b3d..744d6f688 100644 --- a/assets/js/blocks/price-filter/index.tsx +++ b/assets/js/blocks/price-filter/index.tsx @@ -5,7 +5,6 @@ import { __ } from '@wordpress/i18n'; import { createBlock, registerBlockType } from '@wordpress/blocks'; import classNames from 'classnames'; import { Icon, currencyDollar } from '@wordpress/icons'; -import { isFeaturePluginBuild } from '@woocommerce/block-settings'; import { useBlockProps } from '@wordpress/block-editor'; /** @@ -16,9 +15,9 @@ import metadata from './block.json'; import { blockAttributes } from './attributes'; registerBlockType( metadata, { - title: __( 'Filter Products by Price', 'woo-gutenberg-products-block' ), + title: __( 'Filter by Price', 'woo-gutenberg-products-block' ), description: __( - 'Allow customers to filter the products by choosing a lower or upper price limit. Works in combination with the All Products block.', + 'Allow customers to filter products by price range.', 'woo-gutenberg-products-block' ), icon: { @@ -29,16 +28,6 @@ registerBlockType( metadata, { /> ), }, - supports: { - ...metadata.supports, - ...( isFeaturePluginBuild() && { - __experimentalBorder: { - radius: true, - color: true, - width: false, - }, - } ), - }, attributes: { ...metadata.attributes, ...blockAttributes, @@ -62,6 +51,7 @@ registerBlockType( metadata, { 'woo-gutenberg-products-block' ), headingLevel: 3, + inlineInput: false, } ), }, ], diff --git a/assets/js/blocks/price-filter/style.scss b/assets/js/blocks/price-filter/style.scss index daf012103..0a7e79283 100644 --- a/assets/js/blocks/price-filter/style.scss +++ b/assets/js/blocks/price-filter/style.scss @@ -1,5 +1,21 @@ .wp-block-woocommerce-price-filter { + border-color: $gray-700; + border-radius: 4px; border-style: none !important; + + h1, + h2, + h3, + h4, + h5, + h6 { + text-transform: inherit; + } + + > .wc-block-price-filter__title { + margin-top: $gap-small; + margin-bottom: $gap-small; + } } .wc-block-price-slider { @@ -12,14 +28,27 @@ border-color: inherit; } - .wc-block-price-filter__controls { border-radius: inherit; border-color: inherit; + // Force inheriting style is required for global style. input { border-radius: inherit !important; border-color: inherit !important; border-style: solid; } + + .input-loading { + @include placeholder(); + border-radius: 0; + height: em(32px); + width: em(90px); + } +} + +.editor-styles-wrapper .wc-block-price-filter__button.wc-block-components-price-slider__button, +.wc-block-price-filter__button.wc-block-components-price-slider__button { + padding: em($gap-smaller) em($gap); + @include font-size(small); } diff --git a/assets/js/blocks/price-filter/types.ts b/assets/js/blocks/price-filter/types.ts index 429c29899..bb574ff66 100644 --- a/assets/js/blocks/price-filter/types.ts +++ b/assets/js/blocks/price-filter/types.ts @@ -1,6 +1,7 @@ export interface Attributes { showFilterButton: boolean; showInputFields: boolean; + inlineInput: boolean; heading: string; headingLevel: number; className?: string; diff --git a/assets/js/blocks/product-best-sellers/block.json b/assets/js/blocks/product-best-sellers/block.json index 5804158f1..7e60e2309 100644 --- a/assets/js/blocks/product-best-sellers/block.json +++ b/assets/js/blocks/product-best-sellers/block.json @@ -88,7 +88,7 @@ "title", "menu_order" ], - "default": "date" + "default": "popularity" } }, "textdomain": "woo-gutenberg-products-block", diff --git a/assets/js/blocks/product-categories/block.js b/assets/js/blocks/product-categories/block.js index 854d15657..fdcc604d7 100644 --- a/assets/js/blocks/product-categories/block.js +++ b/assets/js/blocks/product-categories/block.js @@ -27,7 +27,7 @@ const EmptyPlaceholder = () => ( className="wc-block-product-categories" > { __( - "This block shows product categories for your store. To use it, you'll first need to create a product and assign it to a category.", + 'This block displays the product categories for your store. To use it you first need to create a product and assign it to a category.', 'woo-gutenberg-products-block' ) } @@ -92,17 +92,6 @@ const ProductCategoriesBlock = ( { attributes, setAttributes, name } ) => { 'Show product count', 'woo-gutenberg-products-block' ) } - help={ - hasCount - ? __( - 'Product count is visible.', - 'woo-gutenberg-products-block' - ) - : __( - 'Product count is hidden.', - 'woo-gutenberg-products-block' - ) - } checked={ hasCount } onChange={ () => setAttributes( { hasCount: ! hasCount } ) @@ -136,17 +125,6 @@ const ProductCategoriesBlock = ( { attributes, setAttributes, name } ) => { 'Show hierarchy', 'woo-gutenberg-products-block' ) } - help={ - isHierarchical - ? __( - 'Hierarchy is visible.', - 'woo-gutenberg-products-block' - ) - : __( - 'Hierarchy is hidden.', - 'woo-gutenberg-products-block' - ) - } checked={ isHierarchical } onChange={ () => setAttributes( { @@ -159,17 +137,6 @@ const ProductCategoriesBlock = ( { attributes, setAttributes, name } ) => { 'Show empty categories', 'woo-gutenberg-products-block' ) } - help={ - hasEmpty - ? __( - 'Empty categories are visible.', - 'woo-gutenberg-products-block' - ) - : __( - 'Empty categories are hidden.', - 'woo-gutenberg-products-block' - ) - } checked={ hasEmpty } onChange={ () => setAttributes( { hasEmpty: ! hasEmpty } ) diff --git a/assets/js/blocks/product-categories/block.json b/assets/js/blocks/product-categories/block.json new file mode 100644 index 000000000..3842a4ccf --- /dev/null +++ b/assets/js/blocks/product-categories/block.json @@ -0,0 +1,53 @@ +{ + "name": "woocommerce/product-categories", + "title": "Product Categories List", + "category": "woocommerce", + "description": "Show all product categories as a list or dropdown.", + "keywords": [ "WooCommerce" ], + "supports": { + "align": [ "wide", "full" ], + "html": false, + "color": { + "background": false, + "link": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + } + }, + "attributes": { + "align": { + "type": "string" + }, + "hasCount": { + "type": "boolean", + "default": true + }, + "hasImage": { + "type": "boolean", + "default": false + }, + "hasEmpty": { + "type": "boolean", + "default": false + }, + "isDropdown": { + "type": "boolean", + "default": false + }, + "isHierarchical": { + "type": "boolean", + "default": true + } + }, + "example": { + "attributes": { + "hasCount": true, + "hasImage": false + } + }, + "textdomain": "woo-gutenberg-products-block", + "apiVersion": 2, + "$schema": "https://schemas.wp.org/trunk/block.json" +} diff --git a/assets/js/blocks/product-categories/edit.tsx b/assets/js/blocks/product-categories/edit.tsx new file mode 100644 index 000000000..d8fe566c4 --- /dev/null +++ b/assets/js/blocks/product-categories/edit.tsx @@ -0,0 +1,20 @@ +/** + * External dependencies + */ +import { useBlockProps } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import Block from './block'; +import './editor.scss'; + +export const Edit = ( props: unknown ): JSX.Element => { + const blockProps = useBlockProps(); + + return ( +
    + +
    + ); +}; diff --git a/assets/js/blocks/product-categories/index.js b/assets/js/blocks/product-categories/index.tsx similarity index 61% rename from assets/js/blocks/product-categories/index.js rename to assets/js/blocks/product-categories/index.tsx index 9715d879d..9c205df30 100644 --- a/assets/js/blocks/product-categories/index.js +++ b/assets/js/blocks/product-categories/index.tsx @@ -1,21 +1,18 @@ /** * External dependencies */ -import { __ } from '@wordpress/i18n'; import { createBlock, registerBlockType } from '@wordpress/blocks'; import { Icon, listView } from '@wordpress/icons'; -import { isFeaturePluginBuild } from '@woocommerce/block-settings'; /** * Internal dependencies */ import './editor.scss'; +import metadata from './block.json'; import './style.scss'; -import Block from './block.js'; +import { Edit } from './edit'; -registerBlockType( 'woocommerce/product-categories', { - apiVersion: 2, - title: __( 'Product Categories List', 'woo-gutenberg-products-block' ), +registerBlockType( metadata, { icon: { src: ( ), }, - category: 'woocommerce', - keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], - description: __( - 'Show all product categories as a list or dropdown.', - 'woo-gutenberg-products-block' - ), - supports: { - align: [ 'wide', 'full' ], - html: false, - ...( isFeaturePluginBuild() && { - color: { - background: false, - link: true, - }, - typography: { - fontSize: true, - lineHeight: true, - }, - } ), - }, - example: { - attributes: { - hasCount: true, - hasImage: false, - }, - }, - attributes: { - /** - * Alignment of the block. - */ - align: { - type: 'string', - }, - - /** - * Whether to show the product count in each category. - */ - hasCount: { - type: 'boolean', - default: true, - }, - - /** - * Whether to show the category image in each category. - */ - hasImage: { - type: 'boolean', - default: false, - }, - - /** - * Whether to show empty categories in the list. - */ - hasEmpty: { - type: 'boolean', - default: false, - }, - - /** - * Whether to display product categories as a dropdown (true) or list (false). - */ - isDropdown: { - type: 'boolean', - default: false, - }, - - /** - * Whether the product categories should display with hierarchy. - */ - isHierarchical: { - type: 'boolean', - default: true, - }, - }, - transforms: { from: [ { @@ -197,14 +119,7 @@ registerBlockType( 'woocommerce/product-categories', { }, ], - /** - * Renders and manages the block. - * - * @param {Object} props Props to pass to block. - */ - edit( props ) { - return ; - }, + edit: Edit, /** * Save nothing; rendered by server. diff --git a/assets/js/blocks/product-category/edit-mode.tsx b/assets/js/blocks/product-category/edit-mode.tsx index e2de7e090..fa2cef297 100644 --- a/assets/js/blocks/product-category/edit-mode.tsx +++ b/assets/js/blocks/product-category/edit-mode.tsx @@ -47,7 +47,7 @@ export const ProductsByCategoryEditMode = ( save(); debouncedSpeak( __( - 'Showing Products by Category block preview.', + 'Now displaying a preview of the reviews for the products in the selected categories.', 'woo-gutenberg-products-block' ) ); @@ -57,7 +57,7 @@ export const ProductsByCategoryEditMode = ( stopEditing(); debouncedSpeak( __( - 'Showing Products by Category block preview.', + 'Now displaying a preview of the reviews for the products in the selected categories.', 'woo-gutenberg-products-block' ) ); diff --git a/assets/js/blocks/product-query/constants.ts b/assets/js/blocks/product-query/constants.ts new file mode 100644 index 000000000..1c05f1276 --- /dev/null +++ b/assets/js/blocks/product-query/constants.ts @@ -0,0 +1,55 @@ +/** + * External dependencies + */ +import { InnerBlockTemplate } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { QueryBlockQuery } from './types'; + +export const QUERY_DEFAULT_ATTRIBUTES: { + query: QueryBlockQuery; + displayLayout: { + type: 'flex' | 'list'; + columns?: number; + }; +} = { + displayLayout: { + type: 'flex', + columns: 3, + }, + query: { + perPage: 6, + pages: 0, + offset: 0, + postType: 'product', + order: 'desc', + orderBy: 'date', + author: '', + search: '', + exclude: [], + sticky: '', + inherit: false, + }, +}; + +export const INNER_BLOCKS_TEMPLATE: InnerBlockTemplate[] = [ + [ + 'core/post-template', + {}, + [ + [ 'woocommerce/product-image', undefined, [] ], + [ + 'core/post-title', + { + level: 3, + fontSize: 'large', + }, + [], + ], + ], + ], + [ 'core/query-pagination', undefined, [] ], + [ 'core/query-no-results', undefined, [] ], +]; diff --git a/assets/js/blocks/product-query/index.tsx b/assets/js/blocks/product-query/index.tsx new file mode 100644 index 000000000..dbdb98e29 --- /dev/null +++ b/assets/js/blocks/product-query/index.tsx @@ -0,0 +1,36 @@ +/** + * External dependencies + */ +import { Block } from '@wordpress/blocks'; +import { addFilter } from '@wordpress/hooks'; + +/** + * Internal dependencies + */ +import './inspector-controls'; +import './variations/product-query'; +import './variations/products-on-sale'; + +function registerProductQueryVariationAttributes( + props: Block, + blockName: string +) { + if ( blockName === 'core/query' ) { + // Gracefully handle if settings.attributes is undefined. + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore -- We need this because `attributes` is marked as `readonly` + props.attributes = { + ...props.attributes, + __woocommerceVariationProps: { + type: 'object', + }, + }; + } + return props; +} + +addFilter( + 'blocks.registerBlockType', + 'core/custom-class-name/attribute', + registerProductQueryVariationAttributes +); diff --git a/assets/js/blocks/product-query/inspector-controls.tsx b/assets/js/blocks/product-query/inspector-controls.tsx new file mode 100644 index 000000000..a3e2768b0 --- /dev/null +++ b/assets/js/blocks/product-query/inspector-controls.tsx @@ -0,0 +1,57 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { InspectorControls } from '@wordpress/block-editor'; +import { ToggleControl } from '@wordpress/components'; +import { addFilter } from '@wordpress/hooks'; +import { EditorBlock } from '@woocommerce/types'; +import { ElementType } from 'react'; + +/** + * Internal dependencies + */ +import { ProductQueryBlock } from './types'; +import { isWooQueryBlockVariation, setCustomQueryAttribute } from './utils'; + +export const INSPECTOR_CONTROLS = { + onSale: ( props: ProductQueryBlock ) => ( + { + setCustomQueryAttribute( props, { onSale } ); + } } + /> + ), +}; + +export const withProductQueryControls = + < T extends EditorBlock< T > >( BlockEdit: ElementType ) => + ( props: ProductQueryBlock ) => { + return isWooQueryBlockVariation( props ) ? ( + <> + + + { Object.entries( INSPECTOR_CONTROLS ).map( + ( [ key, Control ] ) => + props.attributes.__woocommerceVariationProps.attributes?.disabledInspectorControls?.includes( + key + ) ? null : ( + + ) + ) } + + + ) : ( + + ); + }; + +addFilter( 'editor.BlockEdit', 'core/query', withProductQueryControls ); diff --git a/assets/js/blocks/product-query/types.ts b/assets/js/blocks/product-query/types.ts new file mode 100644 index 000000000..3329005a3 --- /dev/null +++ b/assets/js/blocks/product-query/types.ts @@ -0,0 +1,79 @@ +/** + * External dependencies + */ +import { BlockInstance } from '@wordpress/blocks'; +import type { EditorBlock } from '@woocommerce/types'; + +export interface ProductQueryArguments { + /** + * Display only products on sale. + * + * Will generate the following `meta_query`: + * + * ``` + * array( + * 'relation' => 'OR', + * array( // Simple products type + * 'key' => '_sale_price', + * 'value' => 0, + * 'compare' => '>', + * 'type' => 'numeric', + * ), + * array( // Variable products type + * 'key' => '_min_variation_sale_price', + * 'value' => 0, + * 'compare' => '>', + * 'type' => 'numeric', + * ), + * ) + * ``` + */ + onSale?: boolean; +} + +export type ProductQueryBlock = + WooCommerceBlockVariation< ProductQueryAttributes >; + +export interface ProductQueryAttributes { + /** + * An array of controls to disable in the inspector. + * + * @example `[ 'stockStatus' ]` will not render the dropdown for stock status. + */ + disabledInspectorControls?: string[]; + /** + * Query attributes that define which products will be fetched. + */ + query?: ProductQueryArguments; +} + +export interface QueryBlockQuery { + author?: string; + exclude?: string[]; + inherit: boolean; + offset?: number; + order: 'asc' | 'desc'; + orderBy: 'date' | 'relevance'; + pages?: number; + parents?: number[]; + perPage?: number; + postType: string; + search?: string; + sticky?: string; + taxQuery?: string; +} + +export enum QueryVariation { + /** The main, fully customizable, Product Query block */ + PRODUCT_QUERY = 'product-query', + /** Only shows products on sale */ + PRODUCTS_ON_SALE = 'query-products-on-sale', +} + +export type WooCommerceBlockVariation< T > = EditorBlock< { + // Disabling naming convention because we are namespacing our + // custom attributes inside a core block. Prefixing with underscores + // will help signify our intentions. + // eslint-disable-next-line @typescript-eslint/naming-convention + __woocommerceVariationProps: Partial< BlockInstance< T > >; +} >; diff --git a/assets/js/blocks/product-query/utils.tsx b/assets/js/blocks/product-query/utils.tsx new file mode 100644 index 000000000..61be85d5e --- /dev/null +++ b/assets/js/blocks/product-query/utils.tsx @@ -0,0 +1,54 @@ +/** + * Internal dependencies + */ +import { + ProductQueryArguments, + ProductQueryBlock, + QueryVariation, +} from './types'; + +/** + * Identifies if a block is a Query block variation from our conventions + * + * We are extending Gutenberg's core Query block with our variations, and + * also adding extra namespaced attributes. If those namespaced attributes + * are present, we can be fairly sure it is our own registered variation. + */ +export function isWooQueryBlockVariation( block: ProductQueryBlock ) { + return ( + block.name === 'core/query' && + block.attributes.__woocommerceVariationProps && + Object.values( QueryVariation ).includes( + block.attributes.__woocommerceVariationProps + .name as unknown as QueryVariation + ) + ); +} + +/** + * Sets the new query arguments of a Product Query block + * + * Because we add a new set of deeply nested attributes to the query + * block, this utility function makes it easier to change just the + * options relating to our custom query, while keeping the code + * clean. + */ +export function setCustomQueryAttribute( + block: ProductQueryBlock, + attributes: Partial< ProductQueryArguments > +) { + const { __woocommerceVariationProps } = block.attributes; + + block.setAttributes( { + __woocommerceVariationProps: { + ...__woocommerceVariationProps, + attributes: { + ...__woocommerceVariationProps.attributes, + query: { + ...__woocommerceVariationProps.attributes?.query, + ...attributes, + }, + }, + }, + } ); +} diff --git a/assets/js/blocks/product-query/variations/product-query.tsx b/assets/js/blocks/product-query/variations/product-query.tsx new file mode 100644 index 000000000..3a53dbd9a --- /dev/null +++ b/assets/js/blocks/product-query/variations/product-query.tsx @@ -0,0 +1,42 @@ +/** + * External dependencies + */ +import { isExperimentalBuild } from '@woocommerce/block-settings'; +import { registerBlockVariation } from '@wordpress/blocks'; +import { Icon } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { sparkles } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import { INNER_BLOCKS_TEMPLATE, QUERY_DEFAULT_ATTRIBUTES } from '../constants'; + +if ( isExperimentalBuild() ) { + registerBlockVariation( 'core/query', { + name: 'woocommerce/product-query', + title: __( 'Product Query', 'woo-gutenberg-products-block' ), + isActive: ( attributes ) => { + return ( + attributes?.__woocommerceVariationProps?.name === + 'product-query' + ); + }, + icon: { + src: ( + + ), + }, + attributes: { + ...QUERY_DEFAULT_ATTRIBUTES, + __woocommerceVariationProps: { + name: 'product-query', + }, + }, + innerBlocks: INNER_BLOCKS_TEMPLATE, + scope: [ 'block', 'inserter' ], + } ); +} diff --git a/assets/js/blocks/product-query/variations/products-on-sale.tsx b/assets/js/blocks/product-query/variations/products-on-sale.tsx new file mode 100644 index 000000000..a76c9b8a4 --- /dev/null +++ b/assets/js/blocks/product-query/variations/products-on-sale.tsx @@ -0,0 +1,45 @@ +/** + * External dependencies + */ +import { isExperimentalBuild } from '@woocommerce/block-settings'; +import { registerBlockVariation } from '@wordpress/blocks'; +import { __ } from '@wordpress/i18n'; +import { Icon, percent } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import { INNER_BLOCKS_TEMPLATE, QUERY_DEFAULT_ATTRIBUTES } from '../constants'; + +if ( isExperimentalBuild() ) { + registerBlockVariation( 'core/query', { + name: 'woocommerce/query-products-on-sale', + title: __( 'Products on Sale', 'woo-gutenberg-products-block' ), + isActive: ( blockAttributes ) => + blockAttributes?.__woocommerceVariationProps?.name === + 'query-products-on-sale' || + blockAttributes?.__woocommerceVariationProps?.query?.onSale === + true, + icon: { + src: ( + + ), + }, + attributes: { + ...QUERY_DEFAULT_ATTRIBUTES, + __woocommerceVariationProps: { + name: 'query-products-on-sale', + attributes: { + query: { + onSale: true, + }, + }, + }, + }, + innerBlocks: INNER_BLOCKS_TEMPLATE, + scope: [ 'block', 'inserter' ], + } ); +} diff --git a/assets/js/blocks/product-search/edit.js b/assets/js/blocks/product-search/edit.js index 8d22a4263..c881d261b 100644 --- a/assets/js/blocks/product-search/edit.js +++ b/assets/js/blocks/product-search/edit.js @@ -60,17 +60,6 @@ const Edit = ( { 'Show search field label', 'woo-gutenberg-products-block' ) } - help={ - hasLabel - ? __( - 'Label is visible.', - 'woo-gutenberg-products-block' - ) - : __( - 'Label is hidden.', - 'woo-gutenberg-products-block' - ) - } checked={ hasLabel } onChange={ () => setAttributes( { hasLabel: ! hasLabel } ) diff --git a/assets/js/blocks/product-search/editor.scss b/assets/js/blocks/product-search/editor.scss index 224f0ce39..d47eb352c 100644 --- a/assets/js/blocks/product-search/editor.scss +++ b/assets/js/blocks/product-search/editor.scss @@ -14,3 +14,9 @@ } } } + +.wc-block-components-actions { + .block-editor-warning__actions { + margin-top: 0; + } +} diff --git a/assets/js/blocks/product-search/index.js b/assets/js/blocks/product-search/index.js deleted file mode 100644 index d230edccf..000000000 --- a/assets/js/blocks/product-search/index.js +++ /dev/null @@ -1,108 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { createBlock, registerBlockType } from '@wordpress/blocks'; -import { Icon, search } from '@wordpress/icons'; -/** - * Internal dependencies - */ -import './style.scss'; -import './editor.scss'; -import Block from './block.js'; -import edit from './edit.js'; - -const attributes = { - /** - * Whether to show the field label. - */ - hasLabel: { - type: 'boolean', - default: true, - }, - - /** - * Search field label. - */ - label: { - type: 'string', - default: __( 'Search', 'woo-gutenberg-products-block' ), - }, - - /** - * Search field placeholder. - */ - placeholder: { - type: 'string', - default: __( 'Search products…', 'woo-gutenberg-products-block' ), - }, - - /** - * Store the instance ID. - */ - formId: { - type: 'string', - default: '', - }, -}; - -registerBlockType( 'woocommerce/product-search', { - title: __( 'Product Search', 'woo-gutenberg-products-block' ), - icon: { - src: ( - - ), - }, - category: 'woocommerce', - keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], - description: __( - 'A search box to allow customers to search for products by keyword.', - 'woo-gutenberg-products-block' - ), - supports: { - align: [ 'wide', 'full' ], - }, - example: { - attributes: { - hasLabel: true, - }, - }, - attributes, - transforms: { - from: [ - { - type: 'block', - blocks: [ 'core/legacy-widget' ], - // We can't transform if raw instance isn't shown in the REST API. - isMatch: ( { idBase, instance } ) => - idBase === 'woocommerce_product_search' && !! instance?.raw, - transform: ( { instance } ) => - createBlock( 'woocommerce/product-search', { - label: - instance.raw.title === '' - ? __( 'Search', 'woo-gutenberg-products-block' ) - : instance.raw.title, - } ), - }, - ], - }, - deprecated: [ - { - attributes, - save( props ) { - return ( -
    - -
    - ); - }, - }, - ], - edit, - save() { - return null; - }, -} ); diff --git a/assets/js/blocks/product-search/index.tsx b/assets/js/blocks/product-search/index.tsx new file mode 100644 index 000000000..04e5c64d1 --- /dev/null +++ b/assets/js/blocks/product-search/index.tsx @@ -0,0 +1,206 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +/** + * External dependencies + */ +import { store as blockEditorStore, Warning } from '@wordpress/block-editor'; +import { useDispatch, useSelect } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { Icon, search } from '@wordpress/icons'; +import { getSettingWithCoercion } from '@woocommerce/settings'; +import { isBoolean } from '@woocommerce/types'; +import { Button } from '@wordpress/components'; +import { + // @ts-ignore waiting for @types/wordpress__blocks update + registerBlockVariation, + registerBlockType, + createBlock, +} from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import './style.scss'; +import './editor.scss'; +import Block from './block.js'; +import Edit from './edit.js'; + +const isBlockVariationAvailable = getSettingWithCoercion( + 'isBlockVariationAvailable', + false, + isBoolean +); + +const attributes = { + /** + * Whether to show the field label. + */ + hasLabel: { + type: 'boolean', + default: true, + }, + + /** + * Search field label. + */ + label: { + type: 'string', + default: __( 'Search', 'woo-gutenberg-products-block' ), + }, + + /** + * Search field placeholder. + */ + placeholder: { + type: 'string', + default: __( 'Search products…', 'woo-gutenberg-products-block' ), + }, + + /** + * Store the instance ID. + */ + formId: { + type: 'string', + default: '', + }, +}; + +const PRODUCT_SEARCH_ATTRIBUTES = { + label: attributes.label.default, + buttonText: attributes.label.default, + placeholder: attributes.placeholder.default, + query: { + post_type: 'product', + }, +}; + +const DeprecatedBlockEdit = ( { clientId }: { clientId: string } ) => { + // @ts-ignore @wordpress/block-editor/store types not provided + const { replaceBlocks } = useDispatch( blockEditorStore ); + + const currentBlockAttributes = useSelect( + ( select ) => + select( 'core/block-editor' ).getBlockAttributes( clientId ), + [ clientId ] + ); + + const updateBlock = () => { + replaceBlocks( + clientId, + createBlock( 'core/search', { + label: + currentBlockAttributes?.label || + PRODUCT_SEARCH_ATTRIBUTES.label, + buttonText: PRODUCT_SEARCH_ATTRIBUTES.buttonText, + placeholder: + currentBlockAttributes?.placeholder || + PRODUCT_SEARCH_ATTRIBUTES.placeholder, + query: PRODUCT_SEARCH_ATTRIBUTES.query, + } ) + ); + }; + + const actions = [ + , + ]; + + return ( + + { __( + 'This version of the Product Search block is outdated. Upgrade to continue using.', + 'woo-gutenberg-products-block' + ) } + + ); +}; + +registerBlockType( 'woocommerce/product-search', { + title: __( 'Product Search', 'woo-gutenberg-products-block' ), + icon: { + src: ( + + ), + }, + category: 'woocommerce', + keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], + description: __( + 'A search box to allow customers to search for products by keyword.', + 'woo-gutenberg-products-block' + ), + supports: { + align: [ 'wide', 'full' ], + inserter: ! isBlockVariationAvailable, + }, + example: { + attributes: { + hasLabel: true, + }, + }, + attributes, + transforms: { + from: [ + { + type: 'block', + blocks: [ 'core/legacy-widget' ], + // We can't transform if raw instance isn't shown in the REST API. + isMatch: ( { idBase, instance } ) => + idBase === 'woocommerce_product_search' && !! instance?.raw, + transform: ( { instance } ) => + createBlock( 'woocommerce/product-search', { + label: + instance.raw.title || + PRODUCT_SEARCH_ATTRIBUTES.label, + } ), + }, + ], + }, + deprecated: [ + { + attributes, + save( props ) { + return ( +
    + +
    + ); + }, + }, + ], + edit: isBlockVariationAvailable ? DeprecatedBlockEdit : Edit, + save() { + return null; + }, +} ); + +if ( isBlockVariationAvailable ) { + registerBlockVariation( 'core/search', { + name: 'woocommerce/product-search', + title: __( 'Product Search', 'woo-gutenberg-products-block' ), + icon: { + src: ( + + ), + }, + // @ts-ignore waiting for @types/wordpress__blocks update + isActive: ( blockAttributes, variationAttributes ) => { + return ( + blockAttributes.query?.post_type === + variationAttributes.query.post_type + ); + }, + category: 'woocommerce', + keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], + description: __( + 'A search box to allow customers to search for products by keyword.', + 'woo-gutenberg-products-block' + ), + attributes: PRODUCT_SEARCH_ATTRIBUTES, + } ); +} diff --git a/assets/js/blocks/product-tag/block.js b/assets/js/blocks/product-tag/block.js index 5c869dc56..3c19c41fb 100644 --- a/assets/js/blocks/product-tag/block.js +++ b/assets/js/blocks/product-tag/block.js @@ -311,7 +311,7 @@ class ProductsByTagBlock extends Component { className="wc-block-products-grid wc-block-product-tag" > { __( - "This block displays products from selected tags. In order to preview this you'll first need to create a product and assign it some tags.", + 'This block displays products from selected tags. To use it you first need to create products and assign tags to them.', 'woo-gutenberg-products-block' ) } diff --git a/assets/js/blocks/products/all-products/edit.js b/assets/js/blocks/products/all-products/edit.js index ae0269294..e7ba049b5 100644 --- a/assets/js/blocks/products/all-products/edit.js +++ b/assets/js/blocks/products/all-products/edit.js @@ -149,7 +149,7 @@ class Editor extends Component { { icon: 'edit', title: __( - 'Edit inner product layout', + 'Edit the layout of each product', 'woo-gutenberg-products-block' ), onClick: () => this.togglePreview(), @@ -208,7 +208,7 @@ class Editor extends Component {
    { __( - 'Edit the blocks inside the preview below to change the content displayed for each product within the product grid.', + 'Edit the blocks inside the example below to change the content displayed for all products within the product grid.', 'woo-gutenberg-products-block' ) } diff --git a/assets/js/blocks/reviews/reviews-by-category/edit.js b/assets/js/blocks/reviews/reviews-by-category/edit.js index 316948491..29d5b1241 100644 --- a/assets/js/blocks/reviews/reviews-by-category/edit.js +++ b/assets/js/blocks/reviews/reviews-by-category/edit.js @@ -94,7 +94,7 @@ const ReviewsByCategoryEditor = ( { setAttributes( { editMode: false } ); debouncedSpeak( __( - 'Showing Reviews by Category block preview.', + 'Now displaying a preview of the reviews for the products in the selected categories.', 'woo-gutenberg-products-block' ) ); diff --git a/assets/js/blocks/reviews/reviews-by-product/index.js b/assets/js/blocks/reviews/reviews-by-product/index.js index 32b3531ff..ff6d152d4 100644 --- a/assets/js/blocks/reviews/reviews-by-product/index.js +++ b/assets/js/blocks/reviews/reviews-by-product/index.js @@ -30,7 +30,7 @@ registerBlockType( 'woocommerce/reviews-by-product', { category: 'woocommerce', keywords: [ __( 'WooCommerce', 'woo-gutenberg-products-block' ) ], description: __( - 'Show reviews of your products to build trust.', + 'Display reviews for your products.', 'woo-gutenberg-products-block' ), supports: { diff --git a/assets/js/blocks/stock-filter/block.json b/assets/js/blocks/stock-filter/block.json index 5969f42c4..7b70971d8 100644 --- a/assets/js/blocks/stock-filter/block.json +++ b/assets/js/blocks/stock-filter/block.json @@ -1,13 +1,19 @@ { "name": "woocommerce/stock-filter", "version": "1.0.0", - "title": "Filter Products by Stock", - "description": "Allow customers to filter the grid by products stock status. Works in combination with the All Products block.", + "title": "Filter by Stock", + "description": "Allow customers to filter the grid by products stock status.", "category": "woocommerce", "keywords": [ "WooCommerce" ], "supports": { "html": false, - "multiple": false + "multiple": false, + "color": { + "link": true, + "__experimentalDefaultControls": { + "text": true + } + } }, "example": { "attributes": { diff --git a/assets/js/blocks/stock-filter/block.tsx b/assets/js/blocks/stock-filter/block.tsx index c21abf605..869f0f0bf 100644 --- a/assets/js/blocks/stock-filter/block.tsx +++ b/assets/js/blocks/stock-filter/block.tsx @@ -19,12 +19,15 @@ import { } from '@wordpress/element'; import CheckboxList from '@woocommerce/base-components/checkbox-list'; import FilterSubmitButton from '@woocommerce/base-components/filter-submit-button'; +import FilterResetButton from '@woocommerce/base-components/filter-reset-button'; +import FilterTitlePlaceholder from '@woocommerce/base-components/filter-placeholder'; import Label from '@woocommerce/base-components/filter-element-label'; import isShallowEqual from '@wordpress/is-shallow-equal'; import { decodeEntities } from '@wordpress/html-entities'; import { isBoolean, objectHasProp } from '@woocommerce/types'; import { addQueryArgs, removeQueryArgs } from '@wordpress/url'; import { changeUrl, PREFIX_QUERY_ARG_FILTER_TYPE } from '@woocommerce/utils'; +import classnames from 'classnames'; /** * Internal dependencies @@ -211,15 +214,15 @@ const StockStatusFilterBlock = ( { }; const onSubmit = useCallback( - ( isChecked ) => { + ( checkedOptions ) => { if ( isEditor ) { return; } - if ( isChecked && ! filteringForPhpTemplate ) { - setProductStockStatusQuery( checked ); + if ( checkedOptions && ! filteringForPhpTemplate ) { + setProductStockStatusQuery( checkedOptions ); } - updateFilterUrl( checked ); + updateFilterUrl( checkedOptions ); }, [ isEditor, @@ -338,14 +341,15 @@ const StockStatusFilterBlock = ( { [ checked, displayedOptions ] ); - if ( displayedOptions.length === 0 ) { + if ( ! filteredCountsLoading && displayedOptions.length === 0 ) { return null; } const TagName = `h${ blockAttributes.headingLevel }` as keyof JSX.IntrinsicElements; const isLoading = - ! blockAttributes.isPreview && ! STOCK_STATUS_OPTIONS.current; + ( ! blockAttributes.isPreview && ! STOCK_STATUS_OPTIONS.current ) || + displayedOptions.length === 0; const isDisabled = ! blockAttributes.isPreview && filteredCountsLoading; const hasFilterableProducts = getSettingWithCoercion( @@ -358,14 +362,26 @@ const StockStatusFilterBlock = ( { return null; } + const heading = ( + + { blockAttributes.heading } + + ); + + const filterHeading = isLoading ? ( + { heading } + ) : ( + heading + ); + return ( <> - { ! isEditor && blockAttributes.heading && ( - - { blockAttributes.heading } - - ) } -
    + { ! isEditor && blockAttributes.heading && filterHeading } +
    - { blockAttributes.showFilterButton && ( - onSubmit( checked ) } - /> - ) }
    + { +
    + { checked.length > 0 && ! isLoading && ( + { + setChecked( [] ); + onSubmit( [] ); + } } + screenReaderLabel={ __( + 'Reset stock filter', + 'woo-gutenberg-products-block' + ) } + /> + ) } + { blockAttributes.showFilterButton && ( + onSubmit( checked ) } + /> + ) } +
    + } ); }; diff --git a/assets/js/blocks/stock-filter/edit.tsx b/assets/js/blocks/stock-filter/edit.tsx index 05bdf6dd6..7d7d9103b 100644 --- a/assets/js/blocks/stock-filter/edit.tsx +++ b/assets/js/blocks/stock-filter/edit.tsx @@ -40,20 +40,9 @@ const Edit = ( { > setAttributes( { @@ -61,41 +50,23 @@ const Edit = ( { } ) } /> -

    - { __( - 'Heading Level', - 'woo-gutenberg-products-block' - ) } -

    - - setAttributes( { headingLevel: newLevel } ) - } - /> + +

    { __( 'Size', 'woo-gutenberg-products-block' ) }

    + + setAttributes( { headingLevel: newLevel } ) + } + /> +
    ); }; diff --git a/assets/js/blocks/stock-filter/index.tsx b/assets/js/blocks/stock-filter/index.tsx index 9bb0b96af..80477ae79 100644 --- a/assets/js/blocks/stock-filter/index.tsx +++ b/assets/js/blocks/stock-filter/index.tsx @@ -18,7 +18,7 @@ import type { Attributes } from './types'; registerBlockType( metadata, { title: __( 'Filter Products by Stock', 'woo-gutenberg-products-block' ), description: __( - 'Allow customers to filter the grid by products stock status. Works in combination with the All Products block.', + 'Enable customers to filter the product grid by stock status.', 'woo-gutenberg-products-block' ), icon: { diff --git a/assets/js/blocks/stock-filter/style.scss b/assets/js/blocks/stock-filter/style.scss index 60d9609e0..2691189b9 100644 --- a/assets/js/blocks/stock-filter/style.scss +++ b/assets/js/blocks/stock-filter/style.scss @@ -1,4 +1,27 @@ +.wp-block-woocommerce-stock-filter { + h1, + h2, + h3, + h4, + h5, + h6 { + text-transform: inherit; + } + + > .wc-block-stock-filter__title { + margin-top: $gap-small; + margin-bottom: $gap-small; + } +} + .wc-block-stock-filter { + &.is-loading { + @include placeholder(); + margin-top: $gap; + box-shadow: none; + border-radius: 0; + } + margin-bottom: $gap-large; .wc-block-stock-filter-list { @@ -15,13 +38,30 @@ } } } +} + +.wc-block-stock-filter__actions { + align-items: center; + display: flex; + gap: $gap; + justify-content: flex-end; + margin-top: $gap; - .is-single, - .wc-block-dropdown-selector .wc-block-dropdown-selector__list { - opacity: 0.6; + // The specificity here is needed to overwrite the margin-top that is inherited on WC block template pages such as Shop. + button[type="submit"]:not(.wp-block-search__button).wc-block-components-filter-submit-button { + margin-left: 0; + margin-top: 0; } .wc-block-stock-filter__button { - margin-top: $gap-smaller; + margin-top: em($gap-smaller); + padding: em($gap-smaller) em($gap); + @include font-size(small); } } + +.editor-styles-wrapper .wc-block-stock-filter .wc-block-stock-filter__button { + margin-top: em($gap-smaller); + padding: em($gap-smaller) em($gap); + @include font-size(small); +} diff --git a/assets/js/blocks/stock-filter/test/__snapshots__/block.js.snap b/assets/js/blocks/stock-filter/test/__snapshots__/block.js.snap index 8f24b78b4..6463cade9 100644 --- a/assets/js/blocks/stock-filter/test/__snapshots__/block.js.snap +++ b/assets/js/blocks/stock-filter/test/__snapshots__/block.js.snap @@ -9,43 +9,103 @@ exports[`Testing stock filter renders the stock filter block 1`] = ` class="wc-block-checkbox-list wc-block-components-checkbox-list wc-block-stock-filter-list" >
  • - - + +
  • - - + +
  • - - + +
  • +
    `; @@ -58,50 +118,111 @@ exports[`Testing stock filter renders the stock filter block with the filter but class="wc-block-checkbox-list wc-block-components-checkbox-list wc-block-stock-filter-list" >
  • - - + +
  • - - + +
  • - - + +
  • + +
  • - - + +
  • - - + +
  • +
    `; diff --git a/assets/js/data/schema/README.md b/assets/js/data/schema/README.md index 435a533ce..b3c46b1ad 100644 --- a/assets/js/data/schema/README.md +++ b/assets/js/data/schema/README.md @@ -2,7 +2,6 @@ ## Table of contents -- [Table of contents](#table-of-contents) - [Actions](#actions) - [`receiveRoutes( routes, namespace = '/wc/blocks' )`](#receiveroutes-routes-namespace--wcblocks-) - [Selectors](#selectors) diff --git a/assets/js/editor-components/README.md b/assets/js/editor-components/README.md index 5ccaad420..4fd4c3e2c 100644 --- a/assets/js/editor-components/README.md +++ b/assets/js/editor-components/README.md @@ -4,7 +4,7 @@ These are shared components used in WooCommerce blocks for the editor (Gutenberg Many of our blocks need rich, smart components to provide an interface for selecting or configuring blocks with WooCommerce data. Often there are multiple blocks that need such components. Components in this collection are used in multiple blocks, and may include logic for working with Woo data specifically (e.g. products, shipping methods, product categories). -See [Storybook & Components](docs/contributors/storybook.md) doc for more information. +See [Storybook & Components](../../../docs/contributors/contributing/storybook-and-components.md) doc for more information. diff --git a/assets/js/editor-components/compatibility-notices/cart-checkout-compatibility-notice.tsx b/assets/js/editor-components/compatibility-notices/cart-checkout-compatibility-notice.tsx deleted file mode 100644 index 9c71e98fb..000000000 --- a/assets/js/editor-components/compatibility-notices/cart-checkout-compatibility-notice.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/** - * External dependencies - */ -import { Guide } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; -import { createInterpolateElement } from '@wordpress/element'; -import { isWpVersion } from '@woocommerce/settings'; -import type { ReactElement } from 'react'; - -/** - * Internal dependencies - */ -import { useCompatibilityNotice } from './use-compatibility-notice'; -import WooImage from './woo-image'; - -interface CartCheckoutCompatibilityNoticeProps { - blockName: 'cart' | 'checkout'; -} - -export function CartCheckoutCompatibilityNotice( { - blockName, -}: CartCheckoutCompatibilityNoticeProps ): ReactElement | null { - const [ isVisible, dismissNotice ] = useCompatibilityNotice( blockName ); - - if ( isWpVersion( '5.4', '<=' ) || ! isVisible ) { - return null; - } - - return ( - dismissNotice() } - finishButtonText={ __( 'Got it!', 'woo-gutenberg-products-block' ) } - pages={ [ - { - image: , - content: ( - <> -

    - { __( - 'Compatibility notice', - 'woo-gutenberg-products-block' - ) } -

    -

    - { createInterpolateElement( - __( - 'This block may not be compatible with all checkout extensions and integrations.', - 'woo-gutenberg-products-block' - ), - { - em: , - } - ) } -

    -

    - { createInterpolateElement( - __( - 'We recommend reviewing our expanding list of compatible extensions prior to using this block on a live store.', - 'woo-gutenberg-products-block' - ), - { - a: ( - // eslint-disable-next-line jsx-a11y/anchor-has-content - - ), - } - ) } -

    - - ), - }, - ] } - /> - ); -} diff --git a/assets/js/editor-components/compatibility-notices/index.tsx b/assets/js/editor-components/compatibility-notices/index.tsx deleted file mode 100644 index c1f6e1c6d..000000000 --- a/assets/js/editor-components/compatibility-notices/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './cart-checkout-compatibility-notice'; diff --git a/assets/js/editor-components/compatibility-notices/style.scss b/assets/js/editor-components/compatibility-notices/style.scss deleted file mode 100644 index b4d975488..000000000 --- a/assets/js/editor-components/compatibility-notices/style.scss +++ /dev/null @@ -1,31 +0,0 @@ -.wc-block-welcome-guide { - width: 312px; - - &.components-modal__frame.components-guide { - height: auto; - } - - &__image { - background: #00a0d2; - margin: 0 0 $gap; - } - - &__heading { - font-size: 24px; - line-height: 1.4; - margin: $gap 0; - padding: 0 $gap-large; - } - - &__text { - font-size: 13px; - line-height: 1.4; - margin: 0 0 $gap-large; - padding: 0 $gap-large; - } - - &__inserter-icon { - margin: 0 4px; - vertical-align: text-top; - } -} diff --git a/assets/js/editor-components/compatibility-notices/woo-image.js b/assets/js/editor-components/compatibility-notices/woo-image.js deleted file mode 100644 index f9e7edcda..000000000 --- a/assets/js/editor-components/compatibility-notices/woo-image.js +++ /dev/null @@ -1,132 +0,0 @@ -const WooImage = ( props ) => ( -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -); - -export default WooImage; diff --git a/assets/js/editor-components/default-notice/editor.scss b/assets/js/editor-components/default-notice/editor.scss new file mode 100644 index 000000000..ebc290361 --- /dev/null +++ b/assets/js/editor-components/default-notice/editor.scss @@ -0,0 +1,18 @@ +.wc-default-page-notice.is-dismissible { + margin: 0; + padding-right: 16px; + .components-notice__dismiss { + min-width: 24px; + } + .components-notice__content { + margin: 4px 0; + } + svg { + width: 16px; + height: 16px; + } +} + +.wc-blocks-legacy-page-notice { + margin: 0; +} diff --git a/assets/js/editor-components/default-notice/index.tsx b/assets/js/editor-components/default-notice/index.tsx new file mode 100644 index 000000000..66f4dad9a --- /dev/null +++ b/assets/js/editor-components/default-notice/index.tsx @@ -0,0 +1,191 @@ +/** + * External dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; +import { store as editorStore } from '@wordpress/editor'; +import triggerFetch from '@wordpress/api-fetch'; +import { store as coreStore } from '@wordpress/core-data'; +import { Notice, Button } from '@wordpress/components'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { CHECKOUT_PAGE_ID, CART_PAGE_ID } from '@woocommerce/block-settings'; +import { + useCallback, + useState, + createInterpolateElement, +} from '@wordpress/element'; +import { getAdminLink } from '@woocommerce/settings'; +/** + * Internal dependencies + */ +import './editor.scss'; + +export function DefaultNotice( { block }: { block: string } ) { + // To avoid having the same logic twice, we're going to handle both pages here. + const ORIGINAL_PAGE_ID = + block === 'checkout' ? CHECKOUT_PAGE_ID : CART_PAGE_ID; + const settingName = + block === 'checkout' + ? 'woocommerce_checkout_page_id' + : 'woocommerce_cart_page_id'; + + const noticeContent = + block === 'checkout' + ? __( + 'If you would like to use this block as your default checkout, update your page settings', + 'woo-gutenberg-products-block' + ) + : __( + 'If you would like to use this block as your default cart, update your page settings', + 'woo-gutenberg-products-block' + ); + + // Everything below works the same for Cart/Checkout + const { saveEntityRecord } = useDispatch( coreStore ); + const { editPost, savePost } = useDispatch( editorStore ); + const { slug, isLoadingPage, postPublished, currentPostId } = useSelect( + ( select ) => { + const { getEntityRecord, isResolving } = select( coreStore ); + const { isCurrentPostPublished, getCurrentPostId } = + select( editorStore ); + return { + slug: + getEntityRecord( 'postType', 'page', ORIGINAL_PAGE_ID ) + ?.slug || block, + isLoadingPage: isResolving( 'getEntityRecord', [ + 'postType', + 'page', + ORIGINAL_PAGE_ID, + ] ), + postPublished: isCurrentPostPublished(), + currentPostId: getCurrentPostId(), + }; + }, + [] + ); + const [ settingStatus, setStatus ] = useState( 'pristine' ); + const updatePage = useCallback( () => { + setStatus( 'updating' ); + Promise.resolve() + .then( () => + triggerFetch( { + path: `/wc/v3/settings/advanced/${ settingName }`, + method: 'GET', + } ) + ) + .catch( ( error ) => { + if ( error.code === 'rest_setting_setting_invalid' ) { + setStatus( 'error' ); + } + } ) + .then( () => { + if ( ! postPublished ) { + editPost( { status: 'publish' } ); + return savePost(); + } + } ) + .then( () => + // Make this page ID the default cart/checkout. + triggerFetch( { + path: `/wc/v3/settings/advanced/${ settingName }`, + method: 'POST', + data: { + value: currentPostId.toString(), + }, + } ) + ) + // Append `-2` to the original link so we can use it here. + .then( () => { + if ( ORIGINAL_PAGE_ID !== 0 ) { + return saveEntityRecord( 'postType', 'page', { + id: ORIGINAL_PAGE_ID, + slug: `${ slug }-2`, + } ); + } + } ) + // Use the original link for this page. + .then( () => editPost( { slug } ) ) + // Save page. + .then( () => savePost() ) + .then( () => setStatus( 'updated' ) ); + }, [ + postPublished, + editPost, + savePost, + settingName, + currentPostId, + ORIGINAL_PAGE_ID, + saveEntityRecord, + slug, + ] ); + if ( currentPostId === ORIGINAL_PAGE_ID || settingStatus === 'dismissed' ) { + return null; + } + return ( + setStatus( 'dismissed' ) } + spokenMessage={ + settingStatus === 'updated' + ? __( + 'Page settings updated', + 'woo-gutenberg-products-block' + ) + : noticeContent + } + > + { settingStatus === 'updated' ? ( + __( 'Page settings updated', 'woo-gutenberg-products-block' ) + ) : ( + <> +

    { noticeContent }

    + + + ) } +
    + ); +} + +export function LegacyNotice( { block }: { block: string } ) { + return ( + + { createInterpolateElement( + sprintf( + /* translators: %s is the block name. It will be cart or checkout. */ + __( + 'If you would like to use this block as your default %s you must update your
    page settings in WooCommerce.', + 'woo-gutenberg-products-block' + ), + block + ), + { + a: ( + // eslint-disable-next-line jsx-a11y/anchor-has-content + + ), + } + ) } + + ); +} diff --git a/assets/js/editor-components/error-placeholder/error-message.tsx b/assets/js/editor-components/error-placeholder/error-message.tsx index 2f0c113a1..7f7d111e5 100644 --- a/assets/js/editor-components/error-placeholder/error-message.tsx +++ b/assets/js/editor-components/error-placeholder/error-message.tsx @@ -19,7 +19,7 @@ export interface ErrorMessageProps { const getErrorMessage = ( { message, type }: ErrorObject ) => { if ( ! message ) { return __( - 'An unknown error occurred which prevented the block from being updated.', + 'An error has prevented the block from being updated.', 'woo-gutenberg-products-block' ); } diff --git a/assets/js/editor-components/feedback-prompt/index.js b/assets/js/editor-components/feedback-prompt/index.js index 1ced9034a..3d3de5009 100644 --- a/assets/js/editor-components/feedback-prompt/index.js +++ b/assets/js/editor-components/feedback-prompt/index.js @@ -4,6 +4,7 @@ import { __ } from '@wordpress/i18n'; import PropTypes from 'prop-types'; import { Icon, commentContent, external } from '@wordpress/icons'; +import { useEffect, useState } from '@wordpress/element'; /** * Internal dependencies @@ -21,26 +22,37 @@ const FeedbackPrompt = ( { text, url = 'https://ideas.woocommerce.com/forums/133476-woocommerce?category_id=384565', } ) => { + // By returning false we ensure that this component is not entered into the InspectorControls + // (which is a slot fill), children array on first render, on the second render when the state + // gets updated this component does get put into the InspectorControls children array but as the + // last item, ensuring it shows last in the sidebar. + const [ isVisible, setIsVisible ] = useState( false ); + useEffect( () => { + setIsVisible( true ); + }, [] ); + return ( - + isVisible && ( +
    + +

    + { __( 'Feedback?', 'woo-gutenberg-products-block' ) } +

    +

    { text }

    + + { __( + 'Give us your feedback.', + 'woo-gutenberg-products-block' + ) } + + +
    + ) ); }; diff --git a/assets/js/editor-components/grid-content-control/index.js b/assets/js/editor-components/grid-content-control/index.js index 9f7d83e4e..ab90b83e6 100644 --- a/assets/js/editor-components/grid-content-control/index.js +++ b/assets/js/editor-components/grid-content-control/index.js @@ -21,17 +21,6 @@ const GridContentControl = ( { onChange, settings } ) => { <> onChange( { ...settings, image: ! imageIsVisible } ) @@ -39,49 +28,16 @@ const GridContentControl = ( { onChange, settings } ) => { /> onChange( { ...settings, title: ! title } ) } /> onChange( { ...settings, price: ! price } ) } /> onChange( { ...settings, rating: ! rating } ) } /> @@ -90,17 +46,6 @@ const GridContentControl = ( { onChange, settings } ) => { 'Add to Cart button', 'woo-gutenberg-products-block' ) } - help={ - button - ? __( - 'Add to Cart button is visible.', - 'woo-gutenberg-products-block' - ) - : __( - 'Add to Cart button is hidden.', - 'woo-gutenberg-products-block' - ) - } checked={ button } onChange={ () => onChange( { ...settings, button: ! button } ) } /> diff --git a/assets/js/editor-components/grid-layout-control/index.js b/assets/js/editor-components/grid-layout-control/index.js index ff269f75c..87c6820d3 100644 --- a/assets/js/editor-components/grid-layout-control/index.js +++ b/assets/js/editor-components/grid-layout-control/index.js @@ -57,13 +57,13 @@ const GridLayoutControl = ( { /> { + const [ isVisible, dismissNotice ] = useCompatibilityNotice( block ); + + const noticeText = createInterpolateElement( + __( + 'The Cart & Checkout Blocks are a beta feature to optimize for faster checkout. To make sure this feature is right for your store, review the list of compatible extensions.', + 'woo-gutenberg-products-block' + ), + { + a: ( + // Suppress the warning as this will be interpolated into the string with content. + // eslint-disable-next-line jsx-a11y/anchor-has-content + + ), + } + ); + + return ( + + { noticeText } + + ); +}; diff --git a/assets/js/editor-components/compatibility-notices/use-compatibility-notice.ts b/assets/js/editor-components/sidebar-compatibility-notice/use-compatibility-notice.ts similarity index 94% rename from assets/js/editor-components/compatibility-notices/use-compatibility-notice.ts rename to assets/js/editor-components/sidebar-compatibility-notice/use-compatibility-notice.ts index 0e3a13d7c..86aba93bb 100644 --- a/assets/js/editor-components/compatibility-notices/use-compatibility-notice.ts +++ b/assets/js/editor-components/sidebar-compatibility-notice/use-compatibility-notice.ts @@ -10,7 +10,7 @@ export const useCompatibilityNotice = ( blockName: string ): [ boolean, () => void ] => { const [ dismissedNotices, setDismissedNotices ] = useLocalStorageState( - `wc-blocks_dismissed_compatibility_notices`, + `wc-blocks_dismissed_sidebar_compatibility_notices`, initialDismissedNotices ); const [ isVisible, setIsVisible ] = useState( false ); diff --git a/assets/js/shared/context/product-data-context.js b/assets/js/shared/context/product-data-context.js index ef94a8eea..3d91f5f56 100644 --- a/assets/js/shared/context/product-data-context.js +++ b/assets/js/shared/context/product-data-context.js @@ -63,6 +63,7 @@ const defaultProductData = { const ProductDataContext = createContext( { product: defaultProductData, hasContext: false, + isLoading: false, } ); export const useProductDataContext = () => useContext( ProductDataContext ); @@ -70,10 +71,11 @@ export const useProductDataContext = () => useContext( ProductDataContext ); export const ProductDataContextProvider = ( { product = null, children, - isLoading = false, + isLoading, } ) => { const contextValue = { product: product || defaultProductData, + isLoading, hasContext: true, }; diff --git a/assets/js/shared/hocs/with-product-data-context.js b/assets/js/shared/hocs/with-product-data-context.js index 9de448bfe..95bba5be2 100644 --- a/assets/js/shared/hocs/with-product-data-context.js +++ b/assets/js/shared/hocs/with-product-data-context.js @@ -1,12 +1,11 @@ /** * External dependencies */ -import apiFetch from '@wordpress/api-fetch'; +import { useStoreProducts } from '@woocommerce/base-context/hooks'; import { ProductDataContextProvider, useProductDataContext, } from '@woocommerce/shared-context'; -import { useState, useEffect } from '@wordpress/element'; /** * Loads the product from the API and adds to the context provider. @@ -14,41 +13,32 @@ import { useState, useEffect } from '@wordpress/element'; * @param {Object} props Component props. */ const OriginalComponentWithContext = ( props ) => { - const { productId, OriginalComponent } = props; - const [ product, setProduct ] = useState( null ); - const [ isLoading, setIsLoading ] = useState( true ); + const { productId, OriginalComponent, postId, product } = props; - useEffect( () => { - if ( !! props.product ) { - setProduct( props.product ); - setIsLoading( false ); - } - }, [ props.product ] ); + const id = props?.isDescendentOfQueryLoop ? postId : productId; - useEffect( () => { - if ( productId > 0 ) { - setIsLoading( true ); - apiFetch( { - path: `/wc/store/v1/products/${ productId }`, - } ) - .then( ( receivedProduct ) => { - setProduct( receivedProduct ); - } ) - .catch( async () => { - setProduct( null ); - } ) - .finally( () => { - setIsLoading( false ); - } ); - } - }, [ productId ] ); + const { products, productsLoading } = useStoreProducts( { + include: id, + } ); + + const productFromAPI = { + product: id > 0 && products.length > 0 ? products[ 0 ] : null, + isLoading: productsLoading, + }; - if ( ! isLoading && ! product ) { - return null; + if ( product ) { + return ( + + + + ); } return ( - + ); diff --git a/assets/js/types/type-defs/blocks.ts b/assets/js/types/type-defs/blocks.ts index e7e7f13d6..aa6e6c0d8 100644 --- a/assets/js/types/type-defs/blocks.ts +++ b/assets/js/types/type-defs/blocks.ts @@ -1,8 +1,11 @@ /** * External dependencies */ +import type { BlockEditProps, BlockInstance } from '@wordpress/blocks'; import { LazyExoticComponent } from 'react'; +export type EditorBlock< T > = BlockInstance< T > & BlockEditProps< T >; + export type RegisteredBlockComponent = | LazyExoticComponent< React.ComponentType< unknown > > | ( () => JSX.Element | null ) diff --git a/bin/hook-docs/data/actions.json b/bin/hook-docs/data/actions.json index 6ec1005eb..b6d0904fd 100644 --- a/bin/hook-docs/data/actions.json +++ b/bin/hook-docs/data/actions.json @@ -1,805 +1,743 @@ { - "$schema": "https://raw.githubusercontent.com/johnbillion/wp-hooks-generator/0.7.0/schema.json", - "hooks": [ - { - "name": "woocommerce_add_to_cart", - "file": "StoreApi/Utilities/CartController.php", - "type": "action", - "doc": { - "description": "Fires when an item is added to the cart.", - "long_description": "This hook fires when an item is added to the cart. This is triggered from the Store API in this context, but WooCommerce core add to cart events trigger the same hook.", - "tags": [ - { - "name": "internal", - "content": "Matches action name in WooCommerce core." - }, - { - "name": "param", - "content": "ID of the item in the cart.", - "types": [ - "string" - ], - "variable": "$cart_id" - }, - { - "name": "param", - "content": "ID of the product added to the cart.", - "types": [ - "integer" - ], - "variable": "$product_id" - }, - { - "name": "param", - "content": "Quantity of the item added to the cart.", - "types": [ - "integer" - ], - "variable": "$request_quantity" - }, - { - "name": "param", - "content": "Variation ID of the product added to the cart.", - "types": [ - "integer" - ], - "variable": "$variation_id" - }, - { - "name": "param", - "content": "Array of variation data.", - "types": [ - "array" - ], - "variable": "$variation" - }, - { - "name": "param", - "content": "Array of other cart item data.", - "types": [ - "array" - ], - "variable": "$cart_item_data" - } - ], - "long_description_html": "

    This hook fires when an item is added to the cart. This is triggered from the Store API in this context, but WooCommerce core add to cart events trigger the same hook.

    " - }, - "args": 6 - }, - { - "name": "woocommerce_after_main_content", - "file": "BlockTypes/ClassicTemplate.php", - "type": "action", - "doc": { - "description": "Hook: woocommerce_after_main_content", - "long_description": "Called after rendering the main content for a product.", - "tags": [ - { - "name": "see", - "content": "Outputs closing DIV for the content (priority 10)", - "refers": "woocommerce_output_content_wrapper_end()" - } - ], - "long_description_html": "

    Called after rendering the main content for a product.

    " - }, - "args": 0 - }, - { - "name": "woocommerce_after_main_content", - "file": "BlockTypes/ClassicTemplate.php", - "type": "action", - "doc": { - "description": "Hook: woocommerce_after_main_content", - "long_description": "Called after rendering the main content for a product.", - "tags": [ - { - "name": "see", - "content": "Outputs closing DIV for the content (priority 10)", - "refers": "woocommerce_output_content_wrapper_end()" - } - ], - "long_description_html": "

    Called after rendering the main content for a product.

    " - }, - "args": 0 - }, - { - "name": "woocommerce_after_shop_loop", - "file": "BlockTypes/ClassicTemplate.php", - "type": "action", - "doc": { - "description": "Hook: woocommerce_after_shop_loop.", - "long_description": "", - "tags": [ - { - "name": "see", - "content": "Renders pagination (priority 10)", - "refers": "woocommerce_pagination()" - } - ], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_applied_coupon", - "file": "StoreApi/Utilities/CartController.php", - "type": "action", - "doc": { - "description": "Fires after a coupon has been applied to the cart.", - "long_description": "", - "tags": [ - { - "name": "internal", - "content": "Matches action name in WooCommerce core." - }, - { - "name": "param", - "content": "The coupon code that was applied.", - "types": [ - "string" - ], - "variable": "$coupon_code" - } - ], - "long_description_html": "" - }, - "args": 1 - }, - { - "name": "woocommerce_archive_description", - "file": "BlockTypes/ClassicTemplate.php", - "type": "action", - "doc": { - "description": "Hook: woocommerce_archive_description.", - "long_description": "", - "tags": [ - { - "name": "see", - "content": "Renders the taxonomy archive description (priority 10)", - "refers": "woocommerce_taxonomy_archive_description()" - }, - { - "name": "see", - "content": "Renders the product archive description (priority 10)", - "refers": "woocommerce_product_archive_description()" - } - ], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_before_main_content", - "file": "BlockTypes/ClassicTemplate.php", - "type": "action", - "doc": { - "description": "Hook: woocommerce_before_main_content", - "long_description": "Called before rendering the main content for a product.", - "tags": [ - { - "name": "see", - "content": "Outputs opening DIV for the content (priority 10)", - "refers": "woocommerce_output_content_wrapper()" - }, - { - "name": "see", - "content": "Outputs breadcrumb trail to the current product (priority 20)", - "refers": "woocommerce_breadcrumb()" - }, - { - "name": "see", - "content": "Outputs schema markup (priority 30)", - "refers": "WC_Structured_Data::generate_website_data()" - } - ], - "long_description_html": "

    Called before rendering the main content for a product.

    " - }, - "args": 0 - }, - { - "name": "woocommerce_before_main_content", - "file": "BlockTypes/ClassicTemplate.php", - "type": "action", - "doc": { - "description": "Hook: woocommerce_before_main_content", - "long_description": "Called before rendering the main content for a product.", - "tags": [ - { - "name": "see", - "content": "Outputs opening DIV for the content (priority 10)", - "refers": "woocommerce_output_content_wrapper()" - }, - { - "name": "see", - "content": "Outputs breadcrumb trail to the current product (priority 20)", - "refers": "woocommerce_breadcrumb()" - }, - { - "name": "see", - "content": "Outputs schema markup (priority 30)", - "refers": "WC_Structured_Data::generate_website_data()" - } - ], - "long_description_html": "

    Called before rendering the main content for a product.

    " - }, - "args": 0 - }, - { - "name": "woocommerce_before_shop_loop", - "file": "BlockTypes/ClassicTemplate.php", - "type": "action", - "doc": { - "description": "Hook: woocommerce_before_shop_loop.", - "long_description": "", - "tags": [ - { - "name": "see", - "content": "Render error notices (priority 10)", - "refers": "woocommerce_output_all_notices()" - }, - { - "name": "see", - "content": "Show number of results found (priority 20)", - "refers": "woocommerce_result_count()" - }, - { - "name": "see", - "content": "Show form to control sort order (priority 30)", - "refers": "woocommerce_catalog_ordering()" - } - ], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_blocks_cart_enqueue_data", - "file": "BlockTypes/Cart.php", - "type": "action", - "doc": { - "description": "Fires after cart block data is registered.", - "long_description": "", - "tags": [], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_blocks_cart_enqueue_data", - "file": "BlockTypes/MiniCart.php", - "type": "action", - "doc": { - "description": "Fires after cart block data is registered.", - "long_description": "", - "tags": [], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_blocks_checkout_enqueue_data", - "file": "BlockTypes/Checkout.php", - "type": "action", - "doc": { - "description": "Fires after checkout block data is registered.", - "long_description": "", - "tags": [], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_blocks_enqueue_cart_block_scripts_after", - "file": "BlockTypes/Cart.php", - "type": "action", - "doc": { - "description": "Fires after cart block scripts are enqueued.", - "long_description": "", - "tags": [], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_blocks_enqueue_cart_block_scripts_before", - "file": "BlockTypes/Cart.php", - "type": "action", - "doc": { - "description": "Fires before cart block scripts are enqueued.", - "long_description": "", - "tags": [], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_blocks_enqueue_checkout_block_scripts_after", - "file": "BlockTypes/Checkout.php", - "type": "action", - "doc": { - "description": "Fires after checkout block scripts are enqueued.", - "long_description": "", - "tags": [], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_blocks_enqueue_checkout_block_scripts_before", - "file": "BlockTypes/Checkout.php", - "type": "action", - "doc": { - "description": "Fires before checkout block scripts are enqueued.", - "long_description": "", - "tags": [], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_blocks_{$this->registry_identifier}_registration", - "file": "Integrations/IntegrationRegistry.php", - "type": "action", - "doc": { - "description": "Fires when the IntegrationRegistry is initialized.", - "long_description": "Runs before integrations are initialized allowing new integration to be registered for use. This should be used as the primary hook for integrations to include their scripts, styles, and other code extending the blocks.", - "tags": [ - { - "name": "param", - "content": "Instance of the IntegrationRegistry class which exposes the IntegrationRegistry::register() method.", - "types": [ - "\\Automattic\\WooCommerce\\Blocks\\Integrations\\IntegrationRegistry" - ], - "variable": "$this" - } - ], - "long_description_html": "

    Runs before integrations are initialized allowing new integration to be registered for use. This should be used as the primary hook for integrations to include their scripts, styles, and other code extending the blocks.

    " - }, - "args": 1 - }, - { - "name": "woocommerce_check_cart_items", - "file": "StoreApi/Utilities/CartController.php", - "type": "action", - "doc": { - "description": "Fires when cart items are being validated.", - "long_description": "Allow 3rd parties to validate cart items. This is a legacy hook from Woo core. This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture notices and convert to wp errors instead.", - "tags": [ - { - "name": "deprecated", - "content": "" - }, - { - "name": "internal", - "content": "Matches action name in WooCommerce core." - } - ], - "long_description_html": "

    Allow 3rd parties to validate cart items. This is a legacy hook from Woo core. This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture notices and convert to wp errors instead.

    " - }, - "args": 0 - }, - { - "name": "woocommerce_created_customer", - "file": "StoreApi/Routes/V1/Checkout.php", - "type": "action", - "doc": { - "description": "Fires after a customer account has been registered.", - "long_description": "This hook fires after customer accounts are created and passes the customer data.", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "New customer (user) ID.", - "types": [ - "integer" - ], - "variable": "$customer_id" - }, - { - "name": "param", - "content": "Array of customer (user) data.", - "types": [ - "array" - ], - "variable": "$new_customer_data" - }, - { - "name": "param", - "content": "The generated password for the account.", - "types": [ - "string" - ], - "variable": "$password_generated" - } - ], - "long_description_html": "

    This hook fires after customer accounts are created and passes the customer data.

    " - }, - "args": 3 - }, - { - "name": "woocommerce_no_products_found", - "file": "BlockTypes/ClassicTemplate.php", - "type": "action", - "doc": { - "description": "Hook: woocommerce_no_products_found.", - "long_description": "", - "tags": [ - { - "name": "see", - "content": "Default no products found content (priority 10)", - "refers": "wc_no_products_found()" - } - ], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_register_post", - "file": "StoreApi/Routes/V1/Checkout.php", - "type": "action", - "doc": { - "description": "Fires before a customer account is registered.", - "long_description": "This hook fires before customer accounts are created and passes the form data (username, email) and an array of errors.\n This could be used to add extra validation logic and append errors to the array.", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "Customer username.", - "types": [ - "string" - ], - "variable": "$username" - }, - { - "name": "param", - "content": "Customer email address.", - "types": [ - "string" - ], - "variable": "$user_email" - }, - { - "name": "param", - "content": "Error object.", - "types": [ - "\\WP_Error" - ], - "variable": "$errors" - } - ], - "long_description_html": "

    This hook fires before customer accounts are created and passes the form data (username, email) and an array of errors.

    This could be used to add extra validation logic and append errors to the array.

    " - }, - "args": 3 - }, - { - "name": "woocommerce_rest_checkout_process_payment_with_context", - "file": "StoreApi/Routes/V1/Checkout.php", - "type": "action_reference", - "doc": { - "description": "Process payment with context.", - "long_description": "", - "tags": [ - { - "name": "hook", - "content": "woocommerce_rest_checkout_process_payment_with_context" - }, - { - "name": "throws", - "content": "If there is an error taking payment, an \\Exception object can be thrown with an error message.", - "types": [ - "\\Exception" - ] - }, - { - "name": "param", - "content": "Holds context for the payment, including order ID and payment method.", - "types": [ - "\\Automattic\\WooCommerce\\StoreApi\\Payments\\PaymentContext" - ], - "variable": "$context" - }, - { - "name": "param", - "content": "Result object for the transaction.", - "types": [ - "\\Automattic\\WooCommerce\\StoreApi\\Payments\\PaymentResult" - ], - "variable": "$payment_result" - } - ], - "long_description_html": "" - }, - "args": 1 - }, - { - "name": "woocommerce_shop_loop", - "file": "BlockTypes/ClassicTemplate.php", - "type": "action", - "doc": { - "description": "Hook: woocommerce_shop_loop.", - "long_description": "", - "tags": [], - "long_description_html": "" - }, - "args": 0 - }, - { - "name": "woocommerce_store_api_cart_errors", - "file": "StoreApi/Utilities/CartController.php", - "type": "action", - "doc": { - "description": "Fires an action to validate the cart.", - "long_description": "Functions hooking into this should add custom errors using the provided WP_Error instance.", - "tags": [ - { - "name": "example", - "content": "docs/examples/validate-cart.md" - }, - { - "name": "param", - "content": "WP_Error object.", - "types": [ - "\\WP_Error" - ], - "variable": "$errors" - }, - { - "name": "param", - "content": "Cart object.", - "types": [ - "\\WC_Cart" - ], - "variable": "$cart" - } - ], - "long_description_html": "

    Functions hooking into this should add custom errors using the provided WP_Error instance.

    " - }, - "args": 2 - }, - { - "name": "woocommerce_store_api_cart_update_customer_from_request", - "file": "StoreApi/Routes/V1/CartUpdateCustomer.php", - "type": "action", - "doc": { - "description": "Fires when the Checkout Block/Store API updates a customer from the API request data.", - "long_description": "", - "tags": [ - { - "name": "param", - "content": "Customer object.", - "types": [ - "\\WC_Customer" - ], - "variable": "$customer" - }, - { - "name": "param", - "content": "Full details about the request.", - "types": [ - "\\WP_REST_Request" - ], - "variable": "$request" - } - ], - "long_description_html": "" - }, - "args": 2 - }, - { - "name": "woocommerce_store_api_cart_update_order_from_request", - "file": "StoreApi/Routes/V1/AbstractCartRoute.php", - "type": "action", - "doc": { - "description": "Fires when the order is synced with cart data from a cart route.", - "long_description": "", - "tags": [ - { - "name": "param", - "content": "Order object.", - "types": [ - "\\WC_Order" - ], - "variable": "$draft_order" - }, - { - "name": "param", - "content": "Customer object.", - "types": [ - "\\WC_Customer" - ], - "variable": "$customer" - }, - { - "name": "param", - "content": "Full details about the request.", - "types": [ - "\\WP_REST_Request" - ], - "variable": "$request" - } - ], - "long_description_html": "" - }, - "args": 2 - }, - { - "name": "woocommerce_store_api_checkout_order_processed", - "file": "StoreApi/Routes/V1/Checkout.php", - "type": "action", - "doc": { - "description": "Fires before an order is processed by the Checkout Block/Store API.", - "long_description": "This hook informs extensions that $order has completed processing and is ready for payment.\n This is similar to existing core hook woocommerce_checkout_order_processed. We're using a new action: - To keep the interface focused (only pass $order, not passing request data). - This also explicitly indicates these orders are from checkout block/StoreAPI.", - "tags": [ - { - "name": "see", - "content": "", - "refers": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3238" - }, - { - "name": "example", - "content": "docs/examples/checkout-order-processed.md" - }, - { - "name": "param", - "content": "Order object.", - "types": [ - "\\WC_Order" - ], - "variable": "$order" - } - ], - "long_description_html": "

    This hook informs extensions that $order has completed processing and is ready for payment.

    This is similar to existing core hook woocommerce_checkout_order_processed. We're using a new action:

    • To keep the interface focused (only pass $order, not passing request data).
    • This also explicitly indicates these orders are from checkout block/StoreAPI.
    " - }, - "args": 1 - }, - { - "name": "woocommerce_store_api_checkout_update_customer_from_request", - "file": "StoreApi/Routes/V1/Checkout.php", - "type": "action", - "doc": { - "description": "Fires when the Checkout Block/Store API updates a customer from the API request data.", - "long_description": "", - "tags": [ - { - "name": "param", - "content": "Customer object.", - "types": [ - "\\WC_Customer" - ], - "variable": "$customer" - }, - { - "name": "param", - "content": "Full details about the request.", - "types": [ - "\\WP_REST_Request" - ], - "variable": "$request" - } - ], - "long_description_html": "" - }, - "args": 2 - }, - { - "name": "woocommerce_store_api_checkout_update_order_from_request", - "file": "StoreApi/Routes/V1/Checkout.php", - "type": "action", - "doc": { - "description": "Fires when the Checkout Block/Store API updates an order's from the API request data.", - "long_description": "This hook gives extensions the chance to update orders based on the data in the request. This can be used in conjunction with the ExtendSchema class to post custom data and then process it.", - "tags": [ - { - "name": "param", - "content": "Order object.", - "types": [ - "\\WC_Order" - ], - "variable": "$order" - }, - { - "name": "param", - "content": "Full details about the request.", - "types": [ - "\\WP_REST_Request" - ], - "variable": "$request" - } - ], - "long_description_html": "

    This hook gives extensions the chance to update orders based on the data in the request. This can be used in conjunction with the ExtendSchema class to post custom data and then process it.

    " - }, - "args": 2 - }, - { - "name": "woocommerce_store_api_checkout_update_order_meta", - "file": "StoreApi/Routes/V1/Checkout.php", - "type": "action", - "doc": { - "description": "Fires when the Checkout Block/Store API updates an order's meta data.", - "long_description": "This hook gives extensions the chance to add or update meta data on the $order. Throwing an exception from a callback attached to this action will make the Checkout Block render in a warning state, effectively preventing checkout.\n This is similar to existing core hook woocommerce_checkout_update_order_meta. We're using a new action: - To keep the interface focused (only pass $order, not passing request data). - This also explicitly indicates these orders are from checkout block/StoreAPI.", - "tags": [ - { - "name": "see", - "content": "", - "refers": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3686" - }, - { - "name": "param", - "content": "Order object.", - "types": [ - "\\WC_Order" - ], - "variable": "$order" - } - ], - "long_description_html": "

    This hook gives extensions the chance to add or update meta data on the $order. Throwing an exception from a callback attached to this action will make the Checkout Block render in a warning state, effectively preventing checkout.

    This is similar to existing core hook woocommerce_checkout_update_order_meta. We're using a new action:

    • To keep the interface focused (only pass $order, not passing request data).
    • This also explicitly indicates these orders are from checkout block/StoreAPI.
    " - }, - "args": 1 - }, - { - "name": "woocommerce_store_api_validate_add_to_cart", - "file": "StoreApi/Utilities/CartController.php", - "type": "action", - "doc": { - "description": "Fires during validation when adding an item to the cart via the Store API.", - "long_description": "Fire action to validate add to cart. Functions hooking into this should throw an \\Exception to prevent add to cart from happening.", - "tags": [ - { - "name": "param", - "content": "Product object being added to the cart.", - "types": [ - "\\WC_Product" - ], - "variable": "$product" - }, - { - "name": "param", - "content": "Add to cart request params including id, quantity, and variation attributes.", - "types": [ - "array" - ], - "variable": "$request" - } - ], - "long_description_html": "

    Fire action to validate add to cart. Functions hooking into this should throw an \\Exception to prevent add to cart from happening.

    " - }, - "args": 2 - }, - { - "name": "woocommerce_store_api_validate_cart_item", - "file": "StoreApi/Utilities/CartController.php", - "type": "action", - "doc": { - "description": "Fire action to validate add to cart. Functions hooking into this should throw an \\Exception to prevent add to cart from occurring.", - "long_description": "", - "tags": [ - { - "name": "param", - "content": "Product object being added to the cart.", - "types": [ - "\\WC_Product" - ], - "variable": "$product" - }, - { - "name": "param", - "content": "Cart item array.", - "types": [ - "array" - ], - "variable": "$cart_item" - } - ], - "long_description_html": "" - }, - "args": 2 - } - ] -} \ No newline at end of file + "$schema": "https://raw.githubusercontent.com/wp-hooks/generator/0.9.0/schema.json", + "hooks": [ + { + "name": "woocommerce_add_to_cart", + "file": "StoreApi/Utilities/CartController.php", + "type": "action", + "doc": { + "description": "Fires when an item is added to the cart.", + "long_description": "This hook fires when an item is added to the cart. This is triggered from the Store API in this context, but WooCommerce core add to cart events trigger the same hook.", + "tags": [ + { + "name": "internal", + "content": "Matches action name in WooCommerce core." + }, + { + "name": "param", + "content": "ID of the item in the cart.", + "types": [ "string" ], + "variable": "$cart_id" + }, + { + "name": "param", + "content": "ID of the product added to the cart.", + "types": [ "integer" ], + "variable": "$product_id" + }, + { + "name": "param", + "content": "Quantity of the item added to the cart.", + "types": [ "integer" ], + "variable": "$request_quantity" + }, + { + "name": "param", + "content": "Variation ID of the product added to the cart.", + "types": [ "integer" ], + "variable": "$variation_id" + }, + { + "name": "param", + "content": "Array of variation data.", + "types": [ "array" ], + "variable": "$variation" + }, + { + "name": "param", + "content": "Array of other cart item data.", + "types": [ "array" ], + "variable": "$cart_item_data" + } + ], + "long_description_html": "

    This hook fires when an item is added to the cart. This is triggered from the Store API in this context, but WooCommerce core add to cart events trigger the same hook.

    " + }, + "args": 6 + }, + { + "name": "woocommerce_after_main_content", + "file": "BlockTypes/ClassicTemplate.php", + "type": "action", + "doc": { + "description": "Hook: woocommerce_after_main_content", + "long_description": "Called after rendering the main content for a product.", + "tags": [ + { + "name": "see", + "content": "Outputs closing DIV for the content (priority 10)", + "refers": "woocommerce_output_content_wrapper_end()" + } + ], + "long_description_html": "

    Called after rendering the main content for a product.

    " + }, + "args": 0 + }, + { + "name": "woocommerce_after_main_content", + "file": "BlockTypes/ClassicTemplate.php", + "type": "action", + "doc": { + "description": "Hook: woocommerce_after_main_content", + "long_description": "Called after rendering the main content for a product.", + "tags": [ + { + "name": "see", + "content": "Outputs closing DIV for the content (priority 10)", + "refers": "woocommerce_output_content_wrapper_end()" + } + ], + "long_description_html": "

    Called after rendering the main content for a product.

    " + }, + "args": 0 + }, + { + "name": "woocommerce_after_shop_loop", + "file": "BlockTypes/ClassicTemplate.php", + "type": "action", + "doc": { + "description": "Hook: woocommerce_after_shop_loop.", + "long_description": "", + "tags": [ + { + "name": "see", + "content": "Renders pagination (priority 10)", + "refers": "woocommerce_pagination()" + } + ], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_applied_coupon", + "file": "StoreApi/Utilities/CartController.php", + "type": "action", + "doc": { + "description": "Fires after a coupon has been applied to the cart.", + "long_description": "", + "tags": [ + { + "name": "internal", + "content": "Matches action name in WooCommerce core." + }, + { + "name": "param", + "content": "The coupon code that was applied.", + "types": [ "string" ], + "variable": "$coupon_code" + } + ], + "long_description_html": "" + }, + "args": 1 + }, + { + "name": "woocommerce_archive_description", + "file": "BlockTypes/ClassicTemplate.php", + "type": "action", + "doc": { + "description": "Hook: woocommerce_archive_description.", + "long_description": "", + "tags": [ + { + "name": "see", + "content": "Renders the taxonomy archive description (priority 10)", + "refers": "woocommerce_taxonomy_archive_description()" + }, + { + "name": "see", + "content": "Renders the product archive description (priority 10)", + "refers": "woocommerce_product_archive_description()" + } + ], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_before_main_content", + "file": "BlockTypes/ClassicTemplate.php", + "type": "action", + "doc": { + "description": "Hook: woocommerce_before_main_content", + "long_description": "Called before rendering the main content for a product.", + "tags": [ + { + "name": "see", + "content": "Outputs opening DIV for the content (priority 10)", + "refers": "woocommerce_output_content_wrapper()" + }, + { + "name": "see", + "content": "Outputs breadcrumb trail to the current product (priority 20)", + "refers": "woocommerce_breadcrumb()" + }, + { + "name": "see", + "content": "Outputs schema markup (priority 30)", + "refers": "WC_Structured_Data::generate_website_data()" + } + ], + "long_description_html": "

    Called before rendering the main content for a product.

    " + }, + "args": 0 + }, + { + "name": "woocommerce_before_main_content", + "file": "BlockTypes/ClassicTemplate.php", + "type": "action", + "doc": { + "description": "Hook: woocommerce_before_main_content", + "long_description": "Called before rendering the main content for a product.", + "tags": [ + { + "name": "see", + "content": "Outputs opening DIV for the content (priority 10)", + "refers": "woocommerce_output_content_wrapper()" + }, + { + "name": "see", + "content": "Outputs breadcrumb trail to the current product (priority 20)", + "refers": "woocommerce_breadcrumb()" + }, + { + "name": "see", + "content": "Outputs schema markup (priority 30)", + "refers": "WC_Structured_Data::generate_website_data()" + } + ], + "long_description_html": "

    Called before rendering the main content for a product.

    " + }, + "args": 0 + }, + { + "name": "woocommerce_before_shop_loop", + "file": "BlockTypes/ClassicTemplate.php", + "type": "action", + "doc": { + "description": "Hook: woocommerce_before_shop_loop.", + "long_description": "", + "tags": [ + { + "name": "see", + "content": "Render error notices (priority 10)", + "refers": "woocommerce_output_all_notices()" + }, + { + "name": "see", + "content": "Show number of results found (priority 20)", + "refers": "woocommerce_result_count()" + }, + { + "name": "see", + "content": "Show form to control sort order (priority 30)", + "refers": "woocommerce_catalog_ordering()" + } + ], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_blocks_cart_enqueue_data", + "file": "BlockTypes/Cart.php", + "type": "action", + "doc": { + "description": "Fires after cart block data is registered.", + "long_description": "", + "tags": [], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_blocks_cart_enqueue_data", + "file": "BlockTypes/MiniCart.php", + "type": "action", + "doc": { + "description": "Fires after cart block data is registered.", + "long_description": "", + "tags": [], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_blocks_checkout_enqueue_data", + "file": "BlockTypes/Checkout.php", + "type": "action", + "doc": { + "description": "Fires after checkout block data is registered.", + "long_description": "", + "tags": [], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_blocks_enqueue_cart_block_scripts_after", + "file": "BlockTypes/Cart.php", + "type": "action", + "doc": { + "description": "Fires after cart block scripts are enqueued.", + "long_description": "", + "tags": [], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_blocks_enqueue_cart_block_scripts_before", + "file": "BlockTypes/Cart.php", + "type": "action", + "doc": { + "description": "Fires before cart block scripts are enqueued.", + "long_description": "", + "tags": [], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_blocks_enqueue_checkout_block_scripts_after", + "file": "BlockTypes/Checkout.php", + "type": "action", + "doc": { + "description": "Fires after checkout block scripts are enqueued.", + "long_description": "", + "tags": [], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_blocks_enqueue_checkout_block_scripts_before", + "file": "BlockTypes/Checkout.php", + "type": "action", + "doc": { + "description": "Fires before checkout block scripts are enqueued.", + "long_description": "", + "tags": [], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_blocks_{$this->registry_identifier}_registration", + "file": "Integrations/IntegrationRegistry.php", + "type": "action", + "doc": { + "description": "Fires when the IntegrationRegistry is initialized.", + "long_description": "Runs before integrations are initialized allowing new integration to be registered for use. This should be used as the primary hook for integrations to include their scripts, styles, and other code extending the blocks.", + "tags": [ + { + "name": "param", + "content": "Instance of the IntegrationRegistry class which exposes the IntegrationRegistry::register() method.", + "types": [ + "\\Automattic\\WooCommerce\\Blocks\\Integrations\\IntegrationRegistry" + ], + "variable": "$this" + } + ], + "long_description_html": "

    Runs before integrations are initialized allowing new integration to be registered for use. This should be used as the primary hook for integrations to include their scripts, styles, and other code extending the blocks.

    " + }, + "args": 1 + }, + { + "name": "woocommerce_check_cart_items", + "file": "StoreApi/Utilities/CartController.php", + "type": "action", + "doc": { + "description": "Fires when cart items are being validated.", + "long_description": "Allow 3rd parties to validate cart items. This is a legacy hook from Woo core. This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture notices and convert to wp errors instead.", + "tags": [ + { + "name": "deprecated", + "content": "" + }, + { + "name": "internal", + "content": "Matches action name in WooCommerce core." + } + ], + "long_description_html": "

    Allow 3rd parties to validate cart items. This is a legacy hook from Woo core. This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture notices and convert to wp errors instead.

    " + }, + "args": 0 + }, + { + "name": "woocommerce_created_customer", + "file": "StoreApi/Routes/V1/Checkout.php", + "type": "action", + "doc": { + "description": "Fires after a customer account has been registered.", + "long_description": "This hook fires after customer accounts are created and passes the customer data.", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "New customer (user) ID.", + "types": [ "integer" ], + "variable": "$customer_id" + }, + { + "name": "param", + "content": "Array of customer (user) data.", + "types": [ "array" ], + "variable": "$new_customer_data" + }, + { + "name": "param", + "content": "The generated password for the account.", + "types": [ "string" ], + "variable": "$password_generated" + } + ], + "long_description_html": "

    This hook fires after customer accounts are created and passes the customer data.

    " + }, + "args": 3 + }, + { + "name": "woocommerce_no_products_found", + "file": "BlockTypes/ClassicTemplate.php", + "type": "action", + "doc": { + "description": "Hook: woocommerce_no_products_found.", + "long_description": "", + "tags": [ + { + "name": "see", + "content": "Default no products found content (priority 10)", + "refers": "wc_no_products_found()" + } + ], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_register_post", + "file": "StoreApi/Routes/V1/Checkout.php", + "type": "action", + "doc": { + "description": "Fires before a customer account is registered.", + "long_description": "This hook fires before customer accounts are created and passes the form data (username, email) and an array of errors.\n This could be used to add extra validation logic and append errors to the array.", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "Customer username.", + "types": [ "string" ], + "variable": "$username" + }, + { + "name": "param", + "content": "Customer email address.", + "types": [ "string" ], + "variable": "$user_email" + }, + { + "name": "param", + "content": "Error object.", + "types": [ "\\WP_Error" ], + "variable": "$errors" + } + ], + "long_description_html": "

    This hook fires before customer accounts are created and passes the form data (username, email) and an array of errors.

    This could be used to add extra validation logic and append errors to the array.

    " + }, + "args": 3 + }, + { + "name": "woocommerce_rest_checkout_process_payment_with_context", + "file": "StoreApi/Routes/V1/Checkout.php", + "type": "action_reference", + "doc": { + "description": "Process payment with context.", + "long_description": "", + "tags": [ + { + "name": "hook", + "content": "woocommerce_rest_checkout_process_payment_with_context" + }, + { + "name": "throws", + "content": "If there is an error taking payment, an \\Exception object can be thrown with an error message.", + "types": [ "\\Exception" ] + }, + { + "name": "param", + "content": "Holds context for the payment, including order ID and payment method.", + "types": [ + "\\Automattic\\WooCommerce\\StoreApi\\Payments\\PaymentContext" + ], + "variable": "$context" + }, + { + "name": "param", + "content": "Result object for the transaction.", + "types": [ + "\\Automattic\\WooCommerce\\StoreApi\\Payments\\PaymentResult" + ], + "variable": "$payment_result" + } + ], + "long_description_html": "" + }, + "args": 1 + }, + { + "name": "woocommerce_shop_loop", + "file": "BlockTypes/ClassicTemplate.php", + "type": "action", + "doc": { + "description": "Hook: woocommerce_shop_loop.", + "long_description": "", + "tags": [], + "long_description_html": "" + }, + "args": 0 + }, + { + "name": "woocommerce_store_api_cart_errors", + "file": "StoreApi/Utilities/CartController.php", + "type": "action", + "doc": { + "description": "Fires an action to validate the cart.", + "long_description": "Functions hooking into this should add custom errors using the provided WP_Error instance.", + "tags": [ + { + "name": "example", + "content": "docs/examples/validate-cart.md" + }, + { + "name": "param", + "content": "WP_Error object.", + "types": [ "\\WP_Error" ], + "variable": "$errors" + }, + { + "name": "param", + "content": "Cart object.", + "types": [ "\\WC_Cart" ], + "variable": "$cart" + } + ], + "long_description_html": "

    Functions hooking into this should add custom errors using the provided WP_Error instance.

    " + }, + "args": 2 + }, + { + "name": "woocommerce_store_api_cart_update_customer_from_request", + "file": "StoreApi/Routes/V1/CartUpdateCustomer.php", + "type": "action", + "doc": { + "description": "Fires when the Checkout Block/Store API updates a customer from the API request data.", + "long_description": "", + "tags": [ + { + "name": "param", + "content": "Customer object.", + "types": [ "\\WC_Customer" ], + "variable": "$customer" + }, + { + "name": "param", + "content": "Full details about the request.", + "types": [ "\\WP_REST_Request" ], + "variable": "$request" + } + ], + "long_description_html": "" + }, + "args": 2 + }, + { + "name": "woocommerce_store_api_cart_update_order_from_request", + "file": "StoreApi/Routes/V1/AbstractCartRoute.php", + "type": "action", + "doc": { + "description": "Fires when the order is synced with cart data from a cart route.", + "long_description": "", + "tags": [ + { + "name": "param", + "content": "Order object.", + "types": [ "\\WC_Order" ], + "variable": "$draft_order" + }, + { + "name": "param", + "content": "Customer object.", + "types": [ "\\WC_Customer" ], + "variable": "$customer" + }, + { + "name": "param", + "content": "Full details about the request.", + "types": [ "\\WP_REST_Request" ], + "variable": "$request" + } + ], + "long_description_html": "" + }, + "args": 2 + }, + { + "name": "woocommerce_store_api_checkout_order_processed", + "file": "StoreApi/Routes/V1/Checkout.php", + "type": "action", + "doc": { + "description": "Fires before an order is processed by the Checkout Block/Store API.", + "long_description": "This hook informs extensions that $order has completed processing and is ready for payment.\n This is similar to existing core hook woocommerce_checkout_order_processed. We're using a new action: - To keep the interface focused (only pass $order, not passing request data). - This also explicitly indicates these orders are from checkout block/StoreAPI.", + "tags": [ + { + "name": "see", + "content": "", + "refers": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3238" + }, + { + "name": "example", + "content": "docs/examples/checkout-order-processed.md" + }, + { + "name": "param", + "content": "Order object.", + "types": [ "\\WC_Order" ], + "variable": "$order" + } + ], + "long_description_html": "

    This hook informs extensions that $order has completed processing and is ready for payment.

    This is similar to existing core hook woocommerce_checkout_order_processed. We're using a new action:

    • To keep the interface focused (only pass $order, not passing request data).
    • This also explicitly indicates these orders are from checkout block/StoreAPI.
    " + }, + "args": 1 + }, + { + "name": "woocommerce_store_api_checkout_update_customer_from_request", + "file": "StoreApi/Routes/V1/Checkout.php", + "type": "action", + "doc": { + "description": "Fires when the Checkout Block/Store API updates a customer from the API request data.", + "long_description": "", + "tags": [ + { + "name": "param", + "content": "Customer object.", + "types": [ "\\WC_Customer" ], + "variable": "$customer" + }, + { + "name": "param", + "content": "Full details about the request.", + "types": [ "\\WP_REST_Request" ], + "variable": "$request" + } + ], + "long_description_html": "" + }, + "args": 2 + }, + { + "name": "woocommerce_store_api_checkout_update_order_from_request", + "file": "StoreApi/Routes/V1/Checkout.php", + "type": "action", + "doc": { + "description": "Fires when the Checkout Block/Store API updates an order's from the API request data.", + "long_description": "This hook gives extensions the chance to update orders based on the data in the request. This can be used in conjunction with the ExtendSchema class to post custom data and then process it.", + "tags": [ + { + "name": "param", + "content": "Order object.", + "types": [ "\\WC_Order" ], + "variable": "$order" + }, + { + "name": "param", + "content": "Full details about the request.", + "types": [ "\\WP_REST_Request" ], + "variable": "$request" + } + ], + "long_description_html": "

    This hook gives extensions the chance to update orders based on the data in the request. This can be used in conjunction with the ExtendSchema class to post custom data and then process it.

    " + }, + "args": 2 + }, + { + "name": "woocommerce_store_api_checkout_update_order_meta", + "file": "StoreApi/Routes/V1/Checkout.php", + "type": "action", + "doc": { + "description": "Fires when the Checkout Block/Store API updates an order's meta data.", + "long_description": "This hook gives extensions the chance to add or update meta data on the $order. Throwing an exception from a callback attached to this action will make the Checkout Block render in a warning state, effectively preventing checkout.\n This is similar to existing core hook woocommerce_checkout_update_order_meta. We're using a new action: - To keep the interface focused (only pass $order, not passing request data). - This also explicitly indicates these orders are from checkout block/StoreAPI.", + "tags": [ + { + "name": "see", + "content": "", + "refers": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3686" + }, + { + "name": "param", + "content": "Order object.", + "types": [ "\\WC_Order" ], + "variable": "$order" + } + ], + "long_description_html": "

    This hook gives extensions the chance to add or update meta data on the $order. Throwing an exception from a callback attached to this action will make the Checkout Block render in a warning state, effectively preventing checkout.

    This is similar to existing core hook woocommerce_checkout_update_order_meta. We're using a new action:

    • To keep the interface focused (only pass $order, not passing request data).
    • This also explicitly indicates these orders are from checkout block/StoreAPI.
    " + }, + "args": 1 + }, + { + "name": "woocommerce_store_api_validate_add_to_cart", + "file": "StoreApi/Utilities/CartController.php", + "type": "action", + "doc": { + "description": "Fires during validation when adding an item to the cart via the Store API.", + "long_description": "Fire action to validate add to cart. Functions hooking into this should throw an \\Exception to prevent add to cart from happening.", + "tags": [ + { + "name": "param", + "content": "Product object being added to the cart.", + "types": [ "\\WC_Product" ], + "variable": "$product" + }, + { + "name": "param", + "content": "Add to cart request params including id, quantity, and variation attributes.", + "types": [ "array" ], + "variable": "$request" + } + ], + "long_description_html": "

    Fire action to validate add to cart. Functions hooking into this should throw an \\Exception to prevent add to cart from happening.

    " + }, + "args": 2 + }, + { + "name": "woocommerce_store_api_validate_cart_item", + "file": "StoreApi/Utilities/CartController.php", + "type": "action", + "doc": { + "description": "Fire action to validate add to cart. Functions hooking into this should throw an \\Exception to prevent add to cart from occurring.", + "long_description": "", + "tags": [ + { + "name": "param", + "content": "Product object being added to the cart.", + "types": [ "\\WC_Product" ], + "variable": "$product" + }, + { + "name": "param", + "content": "Cart item array.", + "types": [ "array" ], + "variable": "$cart_item" + } + ], + "long_description_html": "" + }, + "args": 2 + } + ] +} diff --git a/bin/hook-docs/data/filters.json b/bin/hook-docs/data/filters.json index 5b7991c02..786a644fd 100644 --- a/bin/hook-docs/data/filters.json +++ b/bin/hook-docs/data/filters.json @@ -1,1011 +1,842 @@ { - "$schema": "https://raw.githubusercontent.com/johnbillion/wp-hooks-generator/0.7.0/schema.json", - "hooks": [ - { - "name": "__experimental_woocommerce_blocks_add_data_attributes_to_block", - "file": "BlockTypesController.php", - "type": "filter", - "doc": { - "description": "Filters the list of allowed Block Names", - "long_description": "This hook defines which block names should have block name and attribute data- attributes appended on render.", - "tags": [ - { - "name": "param", - "content": "List of namespaces.", - "types": [ - "array" - ], - "variable": "$allowed_namespaces" - } - ], - "long_description_html": "

    This hook defines which block names should have block name and attribute data- attributes appended on render.

    " - }, - "args": 1 - }, - { - "name": "__experimental_woocommerce_blocks_add_data_attributes_to_namespace", - "file": "BlockTypesController.php", - "type": "filter", - "doc": { - "description": "Filters the list of allowed block namespaces.", - "long_description": "This hook defines which block namespaces should have block name and attribute `data-` attributes appended on render.", - "tags": [ - { - "name": "param", - "content": "List of namespaces.", - "types": [ - "array" - ], - "variable": "$allowed_namespaces" - } - ], - "long_description_html": "

    This hook defines which block namespaces should have block name and attribute data- attributes appended on render.

    " - }, - "args": 1 - }, - { - "name": "__experimental_woocommerce_blocks_payment_gateway_features_list", - "file": "Payments/Integrations/PayPal.php", - "type": "filter", - "doc": { - "description": "Filter to control what features are available for each payment gateway.", - "long_description": "", - "tags": [ - { - "name": "example", - "content": "docs/examples/payment-gateways-features-list.md" - }, - { - "name": "param", - "content": "List of supported features.", - "types": [ - "array" - ], - "variable": "$features" - }, - { - "name": "param", - "content": "Gateway name.", - "types": [ - "string" - ], - "variable": "$name" - }, - { - "name": "return", - "content": "Updated list of supported features.", - "types": [ - "array" - ] - } - ], - "long_description_html": "" - }, - "args": 2 - }, - { - "name": "woocommerce_add_cart_item", - "file": "StoreApi/Utilities/CartController.php", - "type": "filter", - "doc": { - "description": "Filters the item being added to the cart.", - "long_description": "", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "Array of cart item data being added to the cart.", - "types": [ - "array" - ], - "variable": "$cart_item_data" - }, - { - "name": "param", - "content": "Id of the item in the cart.", - "types": [ - "string" - ], - "variable": "$cart_id" - }, - { - "name": "return", - "content": "Updated cart item data.", - "types": [ - "array" - ] - } - ], - "long_description_html": "" - }, - "args": 2 - }, - { - "name": "woocommerce_add_cart_item_data", - "file": "StoreApi/Utilities/CartController.php", - "type": "filter", - "doc": { - "description": "Filter cart item data for add to cart requests.", - "long_description": "", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "Array of other cart item data.", - "types": [ - "array" - ], - "variable": "$cart_item_data" - }, - { - "name": "param", - "content": "ID of the product added to the cart.", - "types": [ - "integer" - ], - "variable": "$product_id" - }, - { - "name": "param", - "content": "Variation ID of the product added to the cart.", - "types": [ - "integer" - ], - "variable": "$variation_id" - }, - { - "name": "param", - "content": "Quantity of the item added to the cart.", - "types": [ - "integer" - ], - "variable": "$quantity" - }, - { - "name": "return", - "content": "", - "types": [ - "array" - ] - } - ], - "long_description_html": "" - }, - "args": 4 - }, - { - "name": "woocommerce_add_to_cart_sold_individually_quantity", - "file": "StoreApi/Utilities/CartController.php", - "type": "filter", - "doc": { - "description": "Filter sold individually quantity for add to cart requests.", - "long_description": "", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "Defaults to 1.", - "types": [ - "integer" - ], - "variable": "$sold_individually_quantity" - }, - { - "name": "param", - "content": "Quantity of the item added to the cart.", - "types": [ - "integer" - ], - "variable": "$quantity" - }, - { - "name": "param", - "content": "ID of the product added to the cart.", - "types": [ - "integer" - ], - "variable": "$product_id" - }, - { - "name": "param", - "content": "Variation ID of the product added to the cart.", - "types": [ - "integer" - ], - "variable": "$variation_id" - }, - { - "name": "param", - "content": "Array of other cart item data.", - "types": [ - "array" - ], - "variable": "$cart_item_data" - }, - { - "name": "return", - "content": "", - "types": [ - "integer" - ] - } - ], - "long_description_html": "" - }, - "args": 5 - }, - { - "name": "woocommerce_add_to_cart_validation", - "file": "StoreApi/Utilities/CartController.php", - "type": "filter", - "doc": { - "description": "Filters if an item being added to the cart passed validation checks.", - "long_description": "Allow 3rd parties to validate if an item can be added to the cart. This is a legacy hook from Woo core. This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture notices and convert to exceptions instead.", - "tags": [ - { - "name": "deprecated", - "content": "" - }, - { - "name": "param", - "content": "True if the item passed validation.", - "types": [ - "boolean" - ], - "variable": "$passed_validation" - }, - { - "name": "param", - "content": "Product ID being validated.", - "types": [ - "integer" - ], - "variable": "$product_id" - }, - { - "name": "param", - "content": "Quantity added to the cart.", - "types": [ - "integer" - ], - "variable": "$quantity" - }, - { - "name": "param", - "content": "Variation ID being added to the cart.", - "types": [ - "integer" - ], - "variable": "$variation_id" - }, - { - "name": "param", - "content": "Variation data.", - "types": [ - "array" - ], - "variable": "$variation" - }, - { - "name": "return", - "content": "", - "types": [ - "boolean" - ] - } - ], - "long_description_html": "

    Allow 3rd parties to validate if an item can be added to the cart. This is a legacy hook from Woo core. This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture notices and convert to exceptions instead.

    " - }, - "args": 5 - }, - { - "name": "woocommerce_adjust_non_base_location_prices", - "file": "StoreApi/Utilities/ProductQuery.php", - "type": "filter", - "doc": { - "description": "Filters if taxes should be removed from locations outside the store base location.", - "long_description": "The woocommerce_adjust_non_base_location_prices filter can stop base taxes being taken off when dealing with out of base locations. e.g. If a product costs 10 including tax, all users will pay 10 regardless of location and taxes.", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "True by default.", - "types": [ - "boolean" - ], - "variable": "$adjust_non_base_location_prices" - }, - { - "name": "return", - "content": "", - "types": [ - "boolean" - ] - } - ], - "long_description_html": "

    The woocommerce_adjust_non_base_location_prices filter can stop base taxes being taken off when dealing with out of base locations. e.g. If a product costs 10 including tax, all users will pay 10 regardless of location and taxes.

    " - }, - "args": 1 - }, - { - "name": "woocommerce_admin_disabled", - "file": "InboxNotifications.php", - "type": "filter", - "doc": { - "description": "", - "long_description": "", - "tags": [], - "long_description_html": "" - }, - "args": 1 - }, - { - "name": "woocommerce_apply_individual_use_coupon", - "file": "StoreApi/Utilities/CartController.php", - "type": "filter", - "doc": { - "description": "Filter coupons to remove when applying an individual use coupon.", - "long_description": "", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "Array of coupons to remove from the cart.", - "types": [ - "array" - ], - "variable": "$coupons" - }, - { - "name": "param", - "content": "Coupon object applied to the cart.", - "types": [ - "\\WC_Coupon" - ], - "variable": "$coupon" - }, - { - "name": "param", - "content": "Array of applied coupons already applied to the cart.", - "types": [ - "array" - ], - "variable": "$applied_coupons" - }, - { - "name": "return", - "content": "", - "types": [ - "array" - ] - } - ], - "long_description_html": "" - }, - "args": 3 - }, - { - "name": "woocommerce_apply_with_individual_use_coupon", - "file": "StoreApi/Utilities/CartController.php", - "type": "filter", - "doc": { - "description": "Filters if a coupon can be applied alongside other individual use coupons.", - "long_description": "", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "Defaults to false.", - "types": [ - "boolean" - ], - "variable": "$apply_with_individual_use_coupon" - }, - { - "name": "param", - "content": "Coupon object applied to the cart.", - "types": [ - "\\WC_Coupon" - ], - "variable": "$coupon" - }, - { - "name": "param", - "content": "Individual use coupon already applied to the cart.", - "types": [ - "\\WC_Coupon" - ], - "variable": "$individual_use_coupon" - }, - { - "name": "param", - "content": "Array of applied coupons already applied to the cart.", - "types": [ - "array" - ], - "variable": "$applied_coupons" - }, - { - "name": "return", - "content": "", - "types": [ - "boolean" - ] - } - ], - "long_description_html": "" - }, - "args": 4 - }, - { - "name": "woocommerce_blocks_product_grid_is_cacheable", - "file": "BlockTypes/AbstractProductGrid.php", - "type": "filter", - "doc": { - "description": "Filters whether or not the product grid is cacheable.", - "long_description": "", - "tags": [ - { - "name": "param", - "content": "The list of script dependencies.", - "types": [ - "boolean" - ], - "variable": "$is_cacheable" - }, - { - "name": "param", - "content": "Query args for the products query passed to BlocksWpQuery.", - "types": [ - "array" - ], - "variable": "$query_args" - }, - { - "name": "return", - "content": "True to enable cache, false to disable cache.", - "types": [ - "array" - ] - } - ], - "long_description_html": "" - }, - "args": 2 - }, - { - "name": "woocommerce_blocks_product_grid_item_html", - "file": "BlockTypes/AbstractProductGrid.php", - "type": "filter", - "doc": { - "description": "Filters the HTML for products in the grid.", - "long_description": "", - "tags": [ - { - "name": "param", - "content": "Product grid item HTML.", - "types": [ - "string" - ], - "variable": "$html" - }, - { - "name": "param", - "content": "Product data passed to the template.", - "types": [ - "array" - ], - "variable": "$data" - }, - { - "name": "param", - "content": "Product object.", - "types": [ - "\\WC_Product" - ], - "variable": "$product" - }, - { - "name": "return", - "content": "Updated product grid item HTML.", - "types": [ - "string" - ] - } - ], - "long_description_html": "" - }, - "args": 3 - }, - { - "name": "woocommerce_blocks_register_script_dependencies", - "file": "Assets/Api.php", - "type": "filter", - "doc": { - "description": "Filters the list of script dependencies.", - "long_description": "", - "tags": [ - { - "name": "param", - "content": "The list of script dependencies.", - "types": [ - "array" - ], - "variable": "$dependencies" - }, - { - "name": "param", - "content": "The script's handle.", - "types": [ - "string" - ], - "variable": "$handle" - }, - { - "name": "return", - "content": "", - "types": [ - "array" - ] - } - ], - "long_description_html": "" - }, - "args": 2 - }, - { - "name": "woocommerce_cart_contents_changed", - "file": "StoreApi/Utilities/CartController.php", - "type": "filter", - "doc": { - "description": "Filters the entire cart contents when the cart changes.", - "long_description": "", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "Array of all cart items.", - "types": [ - "array" - ], - "variable": "$cart_contents" - }, - { - "name": "return", - "content": "Updated array of all cart items.", - "types": [ - "array" - ] - } - ], - "long_description_html": "" - }, - "args": 1 - }, - { - "name": "woocommerce_ga_disable_tracking", - "file": "Domain/Services/GoogleAnalytics.php", - "type": "filter", - "doc": { - "description": "Filter to disable Google Analytics tracking.", - "long_description": "", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in GA extension." - }, - { - "name": "param", - "content": "If true, tracking will be disabled.", - "types": [ - "boolean" - ], - "variable": "$disable_tracking" - } - ], - "long_description_html": "" - }, - "args": 1 - }, - { - "name": "woocommerce_get_item_data", - "file": "StoreApi/Schemas/V1/CartItemSchema.php", - "type": "filter", - "doc": { - "description": "Filters cart item data.", - "long_description": "Filters the variation option name for custom option slugs.", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "Cart item data. Empty by default.", - "types": [ - "array" - ], - "variable": "$item_data" - }, - { - "name": "param", - "content": "Cart item array.", - "types": [ - "array" - ], - "variable": "$cart_item" - }, - { - "name": "return", - "content": "", - "types": [ - "array" - ] - } - ], - "long_description_html": "

    Filters the variation option name for custom option slugs.

    " - }, - "args": 2 - }, - { - "name": "woocommerce_new_customer_data", - "file": "StoreApi/Routes/V1/Checkout.php", - "type": "filter", - "doc": { - "description": "Filters customer data before a customer account is registered.", - "long_description": "This hook filters customer data. It allows user data to be changed, for example, username, password, email, first name, last name, and role.", - "tags": [ - { - "name": "param", - "content": "An array of customer (user) data.", - "types": [ - "array" - ], - "variable": "$customer_data" - }, - { - "name": "return", - "content": "", - "types": [ - "array" - ] - } - ], - "long_description_html": "

    This hook filters customer data. It allows user data to be changed, for example, username, password, email, first name, last name, and role.

    " - }, - "args": 1 - }, - { - "name": "woocommerce_registration_errors", - "file": "StoreApi/Routes/V1/Checkout.php", - "type": "filter", - "doc": { - "description": "Filters registration errors before a customer account is registered.", - "long_description": "This hook filters registration errors. This can be used to manipulate the array of errors before they are displayed.", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "Error object.", - "types": [ - "\\WP_Error" - ], - "variable": "$errors" - }, - { - "name": "param", - "content": "Customer username.", - "types": [ - "string" - ], - "variable": "$username" - }, - { - "name": "param", - "content": "Customer email address.", - "types": [ - "string" - ], - "variable": "$user_email" - }, - { - "name": "return", - "content": "", - "types": [ - "\\WP_Error" - ] - } - ], - "long_description_html": "

    This hook filters registration errors. This can be used to manipulate the array of errors before they are displayed.

    " - }, - "args": 3 - }, - { - "name": "woocommerce_shared_settings", - "file": "Assets/AssetDataRegistry.php", - "type": "filter", - "doc": { - "description": "Filters the array of shared settings.", - "long_description": "Low level hook for registration of new data late in the cycle. This is deprecated. Instead, use the data api:\n ```php Automattic\\WooCommerce\\Blocks\\Package::container()->get( Automattic\\WooCommerce\\Blocks\\Assets\\AssetDataRegistry::class )->add( $key, $value ) ```", - "tags": [ - { - "name": "deprecated", - "content": "" - }, - { - "name": "param", - "content": "Settings data.", - "types": [ - "array" - ], - "variable": "$data" - }, - { - "name": "return", - "content": "", - "types": [ - "array" - ] - } - ], - "long_description_html": "

    Low level hook for registration of new data late in the cycle. This is deprecated. Instead, use the data api:

    Automattic\\WooCommerce\\Blocks\\Package::container()->get( Automattic\\WooCommerce\\Blocks\\Assets\\AssetDataRegistry::class )->add( $key, $value )
    " - }, - "args": 1 - }, - { - "name": "woocommerce_shipping_package_name", - "file": "StoreApi/Utilities/CartController.php", - "type": "filter", - "doc": { - "description": "Filters the shipping package name.", - "long_description": "", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "Shipping package name.", - "types": [ - "string" - ], - "variable": "$shipping_package_name" - }, - { - "name": "param", - "content": "Shipping package ID.", - "types": [ - "string" - ], - "variable": "$package_id" - }, - { - "name": "param", - "content": "Shipping package from WooCommerce.", - "types": [ - "array" - ], - "variable": "$package" - }, - { - "name": "return", - "content": "Shipping package name.", - "types": [ - "string" - ] - } - ], - "long_description_html": "" - }, - "args": 3 - }, - { - "name": "woocommerce_show_page_title", - "file": "BlockTypes/ClassicTemplate.php", - "type": "filter", - "doc": { - "description": "We need to load the scripts here because when using block templates wp_head() gets run after the block template. As a result we are trying to enqueue required scripts before we have even registered them.", - "long_description": "", - "tags": [ - { - "name": "see", - "content": "", - "refers": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues/5328#issuecomment-989013447" - } - ], - "long_description_html": "" - }, - "args": 1 - }, - { - "name": "woocommerce_store_api_disable_nonce_check", - "file": "StoreApi/Routes/V1/AbstractCartRoute.php", - "type": "filter", - "doc": { - "description": "Filters the Store API nonce check.", - "long_description": "This can be used to disable the nonce check when testing API endpoints via a REST API client.", - "tags": [ - { - "name": "param", - "content": "If true, nonce checks will be disabled.", - "types": [ - "boolean" - ], - "variable": "$disable_nonce_check" - }, - { - "name": "return", - "content": "", - "types": [ - "boolean" - ] - } - ], - "long_description_html": "

    This can be used to disable the nonce check when testing API endpoints via a REST API client.

    " - }, - "args": 1 - }, - { - "name": "woocommerce_store_api_product_quantity_limit", - "file": "StoreApi/Utilities/QuantityLimits.php", - "type": "filter", - "doc": { - "description": "Filters the quantity limit for a product being added to the cart via the Store API.", - "long_description": "Filters the variation option name for custom option slugs.", - "tags": [ - { - "name": "param", - "content": "Quantity limit which defaults to 9999 unless sold individually.", - "types": [ - "integer" - ], - "variable": "$quantity_limit" - }, - { - "name": "param", - "content": "Product instance.", - "types": [ - "\\WC_Product" - ], - "variable": "$product" - }, - { - "name": "return", - "content": "", - "types": [ - "integer" - ] - } - ], - "long_description_html": "

    Filters the variation option name for custom option slugs.

    " - }, - "args": 2 - }, - { - "name": "woocommerce_store_api_product_quantity_{$value_type}", - "file": "StoreApi/Utilities/QuantityLimits.php", - "type": "filter", - "doc": { - "description": "Filters the quantity minimum for a cart item in Store API. This allows extensions to control the minimum qty of items already within the cart.", - "long_description": "The suffix of the hook will vary depending on the value being filtered. For example, minimum, maximum, multiple_of, editable.", - "tags": [ - { - "name": "param", - "content": "The value being filtered.", - "types": [ - "mixed" - ], - "variable": "$value" - }, - { - "name": "param", - "content": "The product object.", - "types": [ - "\\WC_Product" - ], - "variable": "$product" - }, - { - "name": "param", - "content": "The cart item if the product exists in the cart, or null.", - "types": [ - "array", - "null" - ], - "variable": "$cart_item" - }, - { - "name": "return", - "content": "", - "types": [ - "mixed" - ] - } - ], - "long_description_html": "

    The suffix of the hook will vary depending on the value being filtered. For example, minimum, maximum, multiple_of, editable.

    " - }, - "args": 3 - }, - { - "name": "woocommerce_variation_option_name", - "file": "StoreApi/Schemas/V1/CartItemSchema.php", - "type": "filter", - "doc": { - "description": "Filters the variation option name.", - "long_description": "Filters the variation option name for custom option slugs.", - "tags": [ - { - "name": "internal", - "content": "Matches filter name in WooCommerce core." - }, - { - "name": "param", - "content": "The name to display.", - "types": [ - "string" - ], - "variable": "$value" - }, - { - "name": "param", - "content": "Unused because this is not a variation taxonomy.", - "types": [ - "null" - ], - "variable": "$unused" - }, - { - "name": "param", - "content": "Taxonomy or product attribute name.", - "types": [ - "string" - ], - "variable": "$taxonomy" - }, - { - "name": "param", - "content": "Product data.", - "types": [ - "\\WC_Product" - ], - "variable": "$product" - }, - { - "name": "return", - "content": "", - "types": [ - "string" - ] - } - ], - "long_description_html": "

    Filters the variation option name for custom option slugs.

    " - }, - "args": 4 - } - ] -} \ No newline at end of file + "$schema": "https://raw.githubusercontent.com/wp-hooks/generator/0.9.0/schema.json", + "hooks": [ + { + "name": "__experimental_woocommerce_blocks_add_data_attributes_to_block", + "file": "BlockTypesController.php", + "type": "filter", + "doc": { + "description": "Filters the list of allowed Block Names", + "long_description": "This hook defines which block names should have block name and attribute data- attributes appended on render.", + "tags": [ + { + "name": "param", + "content": "List of namespaces.", + "types": [ "array" ], + "variable": "$allowed_namespaces" + } + ], + "long_description_html": "

    This hook defines which block names should have block name and attribute data- attributes appended on render.

    " + }, + "args": 1 + }, + { + "name": "__experimental_woocommerce_blocks_add_data_attributes_to_namespace", + "file": "BlockTypesController.php", + "type": "filter", + "doc": { + "description": "Filters the list of allowed block namespaces.", + "long_description": "This hook defines which block namespaces should have block name and attribute `data-` attributes appended on render.", + "tags": [ + { + "name": "param", + "content": "List of namespaces.", + "types": [ "array" ], + "variable": "$allowed_namespaces" + } + ], + "long_description_html": "

    This hook defines which block namespaces should have block name and attribute data- attributes appended on render.

    " + }, + "args": 1 + }, + { + "name": "__experimental_woocommerce_blocks_payment_gateway_features_list", + "file": "Payments/Integrations/PayPal.php", + "type": "filter", + "doc": { + "description": "Filter to control what features are available for each payment gateway.", + "long_description": "", + "tags": [ + { + "name": "example", + "content": "docs/examples/payment-gateways-features-list.md" + }, + { + "name": "param", + "content": "List of supported features.", + "types": [ "array" ], + "variable": "$features" + }, + { + "name": "param", + "content": "Gateway name.", + "types": [ "string" ], + "variable": "$name" + }, + { + "name": "return", + "content": "Updated list of supported features.", + "types": [ "array" ] + } + ], + "long_description_html": "" + }, + "args": 2 + }, + { + "name": "woocommerce_add_cart_item", + "file": "StoreApi/Utilities/CartController.php", + "type": "filter", + "doc": { + "description": "Filters the item being added to the cart.", + "long_description": "", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "Array of cart item data being added to the cart.", + "types": [ "array" ], + "variable": "$cart_item_data" + }, + { + "name": "param", + "content": "Id of the item in the cart.", + "types": [ "string" ], + "variable": "$cart_id" + }, + { + "name": "return", + "content": "Updated cart item data.", + "types": [ "array" ] + } + ], + "long_description_html": "" + }, + "args": 2 + }, + { + "name": "woocommerce_add_cart_item_data", + "file": "StoreApi/Utilities/CartController.php", + "type": "filter", + "doc": { + "description": "Filter cart item data for add to cart requests.", + "long_description": "", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "Array of other cart item data.", + "types": [ "array" ], + "variable": "$cart_item_data" + }, + { + "name": "param", + "content": "ID of the product added to the cart.", + "types": [ "integer" ], + "variable": "$product_id" + }, + { + "name": "param", + "content": "Variation ID of the product added to the cart.", + "types": [ "integer" ], + "variable": "$variation_id" + }, + { + "name": "param", + "content": "Quantity of the item added to the cart.", + "types": [ "integer" ], + "variable": "$quantity" + }, + { + "name": "return", + "content": "", + "types": [ "array" ] + } + ], + "long_description_html": "" + }, + "args": 4 + }, + { + "name": "woocommerce_add_to_cart_sold_individually_quantity", + "file": "StoreApi/Utilities/CartController.php", + "type": "filter", + "doc": { + "description": "Filter sold individually quantity for add to cart requests.", + "long_description": "", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "Defaults to 1.", + "types": [ "integer" ], + "variable": "$sold_individually_quantity" + }, + { + "name": "param", + "content": "Quantity of the item added to the cart.", + "types": [ "integer" ], + "variable": "$quantity" + }, + { + "name": "param", + "content": "ID of the product added to the cart.", + "types": [ "integer" ], + "variable": "$product_id" + }, + { + "name": "param", + "content": "Variation ID of the product added to the cart.", + "types": [ "integer" ], + "variable": "$variation_id" + }, + { + "name": "param", + "content": "Array of other cart item data.", + "types": [ "array" ], + "variable": "$cart_item_data" + }, + { + "name": "return", + "content": "", + "types": [ "integer" ] + } + ], + "long_description_html": "" + }, + "args": 5 + }, + { + "name": "woocommerce_add_to_cart_validation", + "file": "StoreApi/Utilities/CartController.php", + "type": "filter", + "doc": { + "description": "Filters if an item being added to the cart passed validation checks.", + "long_description": "Allow 3rd parties to validate if an item can be added to the cart. This is a legacy hook from Woo core. This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture notices and convert to exceptions instead.", + "tags": [ + { + "name": "deprecated", + "content": "" + }, + { + "name": "param", + "content": "True if the item passed validation.", + "types": [ "boolean" ], + "variable": "$passed_validation" + }, + { + "name": "param", + "content": "Product ID being validated.", + "types": [ "integer" ], + "variable": "$product_id" + }, + { + "name": "param", + "content": "Quantity added to the cart.", + "types": [ "integer" ], + "variable": "$quantity" + }, + { + "name": "param", + "content": "Variation ID being added to the cart.", + "types": [ "integer" ], + "variable": "$variation_id" + }, + { + "name": "param", + "content": "Variation data.", + "types": [ "array" ], + "variable": "$variation" + }, + { + "name": "return", + "content": "", + "types": [ "boolean" ] + } + ], + "long_description_html": "

    Allow 3rd parties to validate if an item can be added to the cart. This is a legacy hook from Woo core. This filter will be deprecated because it encourages usage of wc_add_notice. For the API we need to capture notices and convert to exceptions instead.

    " + }, + "args": 5 + }, + { + "name": "woocommerce_adjust_non_base_location_prices", + "file": "StoreApi/Utilities/ProductQuery.php", + "type": "filter", + "doc": { + "description": "Filters if taxes should be removed from locations outside the store base location.", + "long_description": "The woocommerce_adjust_non_base_location_prices filter can stop base taxes being taken off when dealing with out of base locations. e.g. If a product costs 10 including tax, all users will pay 10 regardless of location and taxes.", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "True by default.", + "types": [ "boolean" ], + "variable": "$adjust_non_base_location_prices" + }, + { + "name": "return", + "content": "", + "types": [ "boolean" ] + } + ], + "long_description_html": "

    The woocommerce_adjust_non_base_location_prices filter can stop base taxes being taken off when dealing with out of base locations. e.g. If a product costs 10 including tax, all users will pay 10 regardless of location and taxes.

    " + }, + "args": 1 + }, + { + "name": "woocommerce_apply_individual_use_coupon", + "file": "StoreApi/Utilities/CartController.php", + "type": "filter", + "doc": { + "description": "Filter coupons to remove when applying an individual use coupon.", + "long_description": "", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "Array of coupons to remove from the cart.", + "types": [ "array" ], + "variable": "$coupons" + }, + { + "name": "param", + "content": "Coupon object applied to the cart.", + "types": [ "\\WC_Coupon" ], + "variable": "$coupon" + }, + { + "name": "param", + "content": "Array of applied coupons already applied to the cart.", + "types": [ "array" ], + "variable": "$applied_coupons" + }, + { + "name": "return", + "content": "", + "types": [ "array" ] + } + ], + "long_description_html": "" + }, + "args": 3 + }, + { + "name": "woocommerce_apply_with_individual_use_coupon", + "file": "StoreApi/Utilities/CartController.php", + "type": "filter", + "doc": { + "description": "Filters if a coupon can be applied alongside other individual use coupons.", + "long_description": "", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "Defaults to false.", + "types": [ "boolean" ], + "variable": "$apply_with_individual_use_coupon" + }, + { + "name": "param", + "content": "Coupon object applied to the cart.", + "types": [ "\\WC_Coupon" ], + "variable": "$coupon" + }, + { + "name": "param", + "content": "Individual use coupon already applied to the cart.", + "types": [ "\\WC_Coupon" ], + "variable": "$individual_use_coupon" + }, + { + "name": "param", + "content": "Array of applied coupons already applied to the cart.", + "types": [ "array" ], + "variable": "$applied_coupons" + }, + { + "name": "return", + "content": "", + "types": [ "boolean" ] + } + ], + "long_description_html": "" + }, + "args": 4 + }, + { + "name": "woocommerce_blocks_product_grid_is_cacheable", + "file": "BlockTypes/AbstractProductGrid.php", + "type": "filter", + "doc": { + "description": "Filters whether or not the product grid is cacheable.", + "long_description": "", + "tags": [ + { + "name": "param", + "content": "The list of script dependencies.", + "types": [ "boolean" ], + "variable": "$is_cacheable" + }, + { + "name": "param", + "content": "Query args for the products query passed to BlocksWpQuery.", + "types": [ "array" ], + "variable": "$query_args" + }, + { + "name": "return", + "content": "True to enable cache, false to disable cache.", + "types": [ "array" ] + } + ], + "long_description_html": "" + }, + "args": 2 + }, + { + "name": "woocommerce_blocks_product_grid_item_html", + "file": "BlockTypes/AbstractProductGrid.php", + "type": "filter", + "doc": { + "description": "Filters the HTML for products in the grid.", + "long_description": "", + "tags": [ + { + "name": "param", + "content": "Product grid item HTML.", + "types": [ "string" ], + "variable": "$html" + }, + { + "name": "param", + "content": "Product data passed to the template.", + "types": [ "array" ], + "variable": "$data" + }, + { + "name": "param", + "content": "Product object.", + "types": [ "\\WC_Product" ], + "variable": "$product" + }, + { + "name": "return", + "content": "Updated product grid item HTML.", + "types": [ "string" ] + } + ], + "long_description_html": "" + }, + "args": 3 + }, + { + "name": "woocommerce_blocks_register_script_dependencies", + "file": "Assets/Api.php", + "type": "filter", + "doc": { + "description": "Filters the list of script dependencies.", + "long_description": "", + "tags": [ + { + "name": "param", + "content": "The list of script dependencies.", + "types": [ "array" ], + "variable": "$dependencies" + }, + { + "name": "param", + "content": "The script's handle.", + "types": [ "string" ], + "variable": "$handle" + }, + { + "name": "return", + "content": "", + "types": [ "array" ] + } + ], + "long_description_html": "" + }, + "args": 2 + }, + { + "name": "woocommerce_cart_contents_changed", + "file": "StoreApi/Utilities/CartController.php", + "type": "filter", + "doc": { + "description": "Filters the entire cart contents when the cart changes.", + "long_description": "", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "Array of all cart items.", + "types": [ "array" ], + "variable": "$cart_contents" + }, + { + "name": "return", + "content": "Updated array of all cart items.", + "types": [ "array" ] + } + ], + "long_description_html": "" + }, + "args": 1 + }, + { + "name": "woocommerce_ga_disable_tracking", + "file": "Domain/Services/GoogleAnalytics.php", + "type": "filter", + "doc": { + "description": "Filter to disable Google Analytics tracking.", + "long_description": "", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in GA extension." + }, + { + "name": "param", + "content": "If true, tracking will be disabled.", + "types": [ "boolean" ], + "variable": "$disable_tracking" + } + ], + "long_description_html": "" + }, + "args": 1 + }, + { + "name": "woocommerce_get_item_data", + "file": "StoreApi/Schemas/V1/CartItemSchema.php", + "type": "filter", + "doc": { + "description": "Filters cart item data.", + "long_description": "Filters the variation option name for custom option slugs.", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "Cart item data. Empty by default.", + "types": [ "array" ], + "variable": "$item_data" + }, + { + "name": "param", + "content": "Cart item array.", + "types": [ "array" ], + "variable": "$cart_item" + }, + { + "name": "return", + "content": "", + "types": [ "array" ] + } + ], + "long_description_html": "

    Filters the variation option name for custom option slugs.

    " + }, + "args": 2 + }, + { + "name": "woocommerce_new_customer_data", + "file": "StoreApi/Routes/V1/Checkout.php", + "type": "filter", + "doc": { + "description": "Filters customer data before a customer account is registered.", + "long_description": "This hook filters customer data. It allows user data to be changed, for example, username, password, email, first name, last name, and role.", + "tags": [ + { + "name": "param", + "content": "An array of customer (user) data.", + "types": [ "array" ], + "variable": "$customer_data" + }, + { + "name": "return", + "content": "", + "types": [ "array" ] + } + ], + "long_description_html": "

    This hook filters customer data. It allows user data to be changed, for example, username, password, email, first name, last name, and role.

    " + }, + "args": 1 + }, + { + "name": "woocommerce_registration_errors", + "file": "StoreApi/Routes/V1/Checkout.php", + "type": "filter", + "doc": { + "description": "Filters registration errors before a customer account is registered.", + "long_description": "This hook filters registration errors. This can be used to manipulate the array of errors before they are displayed.", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "Error object.", + "types": [ "\\WP_Error" ], + "variable": "$errors" + }, + { + "name": "param", + "content": "Customer username.", + "types": [ "string" ], + "variable": "$username" + }, + { + "name": "param", + "content": "Customer email address.", + "types": [ "string" ], + "variable": "$user_email" + }, + { + "name": "return", + "content": "", + "types": [ "\\WP_Error" ] + } + ], + "long_description_html": "

    This hook filters registration errors. This can be used to manipulate the array of errors before they are displayed.

    " + }, + "args": 3 + }, + { + "name": "woocommerce_shared_settings", + "file": "Assets/AssetDataRegistry.php", + "type": "filter", + "doc": { + "description": "Filters the array of shared settings.", + "long_description": "Low level hook for registration of new data late in the cycle. This is deprecated. Instead, use the data api:\n ```php Automattic\\WooCommerce\\Blocks\\Package::container()->get( Automattic\\WooCommerce\\Blocks\\Assets\\AssetDataRegistry::class )->add( $key, $value ) ```", + "tags": [ + { + "name": "deprecated", + "content": "" + }, + { + "name": "param", + "content": "Settings data.", + "types": [ "array" ], + "variable": "$data" + }, + { + "name": "return", + "content": "", + "types": [ "array" ] + } + ], + "long_description_html": "

    Low level hook for registration of new data late in the cycle. This is deprecated. Instead, use the data api:

    Automattic\\WooCommerce\\Blocks\\Package::container()->get( Automattic\\WooCommerce\\Blocks\\Assets\\AssetDataRegistry::class )->add( $key, $value )
    " + }, + "args": 1 + }, + { + "name": "woocommerce_shipping_package_name", + "file": "StoreApi/Utilities/CartController.php", + "type": "filter", + "doc": { + "description": "Filters the shipping package name.", + "long_description": "", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "Shipping package name.", + "types": [ "string" ], + "variable": "$shipping_package_name" + }, + { + "name": "param", + "content": "Shipping package ID.", + "types": [ "string" ], + "variable": "$package_id" + }, + { + "name": "param", + "content": "Shipping package from WooCommerce.", + "types": [ "array" ], + "variable": "$package" + }, + { + "name": "return", + "content": "Shipping package name.", + "types": [ "string" ] + } + ], + "long_description_html": "" + }, + "args": 3 + }, + { + "name": "woocommerce_show_page_title", + "file": "BlockTypes/ClassicTemplate.php", + "type": "filter", + "doc": { + "description": "We need to load the scripts here because when using block templates wp_head() gets run after the block template. As a result we are trying to enqueue required scripts before we have even registered them.", + "long_description": "", + "tags": [ + { + "name": "see", + "content": "", + "refers": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues/5328#issuecomment-989013447" + } + ], + "long_description_html": "" + }, + "args": 1 + }, + { + "name": "woocommerce_store_api_disable_nonce_check", + "file": "StoreApi/Routes/V1/AbstractCartRoute.php", + "type": "filter", + "doc": { + "description": "Filters the Store API nonce check.", + "long_description": "This can be used to disable the nonce check when testing API endpoints via a REST API client.", + "tags": [ + { + "name": "param", + "content": "If true, nonce checks will be disabled.", + "types": [ "boolean" ], + "variable": "$disable_nonce_check" + }, + { + "name": "return", + "content": "", + "types": [ "boolean" ] + } + ], + "long_description_html": "

    This can be used to disable the nonce check when testing API endpoints via a REST API client.

    " + }, + "args": 1 + }, + { + "name": "woocommerce_store_api_product_quantity_limit", + "file": "StoreApi/Utilities/QuantityLimits.php", + "type": "filter", + "doc": { + "description": "Filters the quantity limit for a product being added to the cart via the Store API.", + "long_description": "Filters the variation option name for custom option slugs.", + "tags": [ + { + "name": "param", + "content": "Quantity limit which defaults to 9999 unless sold individually.", + "types": [ "integer" ], + "variable": "$quantity_limit" + }, + { + "name": "param", + "content": "Product instance.", + "types": [ "\\WC_Product" ], + "variable": "$product" + }, + { + "name": "return", + "content": "", + "types": [ "integer" ] + } + ], + "long_description_html": "

    Filters the variation option name for custom option slugs.

    " + }, + "args": 2 + }, + { + "name": "woocommerce_store_api_product_quantity_{$value_type}", + "file": "StoreApi/Utilities/QuantityLimits.php", + "type": "filter", + "doc": { + "description": "Filters the quantity minimum for a cart item in Store API. This allows extensions to control the minimum qty of items already within the cart.", + "long_description": "The suffix of the hook will vary depending on the value being filtered. For example, minimum, maximum, multiple_of, editable.", + "tags": [ + { + "name": "param", + "content": "The value being filtered.", + "types": [ "mixed" ], + "variable": "$value" + }, + { + "name": "param", + "content": "The product object.", + "types": [ "\\WC_Product" ], + "variable": "$product" + }, + { + "name": "param", + "content": "The cart item if the product exists in the cart, or null.", + "types": [ "array", "null" ], + "variable": "$cart_item" + }, + { + "name": "return", + "content": "", + "types": [ "mixed" ] + } + ], + "long_description_html": "

    The suffix of the hook will vary depending on the value being filtered. For example, minimum, maximum, multiple_of, editable.

    " + }, + "args": 3 + }, + { + "name": "woocommerce_variation_option_name", + "file": "StoreApi/Schemas/V1/CartItemSchema.php", + "type": "filter", + "doc": { + "description": "Filters the variation option name.", + "long_description": "Filters the variation option name for custom option slugs.", + "tags": [ + { + "name": "internal", + "content": "Matches filter name in WooCommerce core." + }, + { + "name": "param", + "content": "The name to display.", + "types": [ "string" ], + "variable": "$value" + }, + { + "name": "param", + "content": "Unused because this is not a variation taxonomy.", + "types": [ "null" ], + "variable": "$unused" + }, + { + "name": "param", + "content": "Taxonomy or product attribute name.", + "types": [ "string" ], + "variable": "$taxonomy" + }, + { + "name": "param", + "content": "Product data.", + "types": [ "\\WC_Product" ], + "variable": "$product" + }, + { + "name": "return", + "content": "", + "types": [ "string" ] + } + ], + "long_description_html": "

    Filters the variation option name for custom option slugs.

    " + }, + "args": 4 + } + ] +} diff --git a/bin/hook-docs/format-hook-doc/files.js b/bin/hook-docs/format-hook-doc/files.js index e7282f630..8a4825c25 100644 --- a/bin/hook-docs/format-hook-doc/files.js +++ b/bin/hook-docs/format-hook-doc/files.js @@ -2,7 +2,7 @@ const files = ( sources ) => { return sources && sources.length ? { ul: sources.map( ( file ) => { - return `[${ file }](../../src/${ file })`; + return `[${ file }](../../../../src/${ file })`; } ), } : null; diff --git a/bin/webpack-configs.js b/bin/webpack-configs.js index 9f16254af..4c91754bf 100644 --- a/bin/webpack-configs.js +++ b/bin/webpack-configs.js @@ -261,7 +261,7 @@ const getMainConfig = ( options = {} ) => { new CopyWebpackPlugin( { patterns: [ { - from: './assets/js/blocks/**/block.json', + from: './assets/js/**/block.json', to( { absoluteFilename } ) { /** * Getting the block name from the JSON metadata is less error prone diff --git a/bin/webpack-entries.js b/bin/webpack-entries.js index 714dc0646..4e717d948 100644 --- a/bin/webpack-entries.js +++ b/bin/webpack-entries.js @@ -57,6 +57,9 @@ const blocks = { 'legacy-template': { customDir: 'classic-template', }, + 'product-query': { + isExperimental: true, + }, }; // Returns the entries for each block given a relative path (ie: `index.js`, diff --git a/bin/webpack-helpers.js b/bin/webpack-helpers.js index b1fd4697b..0448fed65 100644 --- a/bin/webpack-helpers.js +++ b/bin/webpack-helpers.js @@ -16,6 +16,7 @@ const wcDepMap = { '@woocommerce/blocks-registry': [ 'wc', 'wcBlocksRegistry' ], '@woocommerce/settings': [ 'wc', 'wcSettings' ], '@woocommerce/block-data': [ 'wc', 'wcBlocksData' ], + '@woocommerce/data': [ 'wc', 'data' ], '@woocommerce/shared-context': [ 'wc', 'wcBlocksSharedContext' ], '@woocommerce/shared-hocs': [ 'wc', 'wcBlocksSharedHocs' ], '@woocommerce/price-format': [ 'wc', 'priceFormat' ], @@ -27,6 +28,7 @@ const wcHandleMap = { '@woocommerce/settings': 'wc-settings', '@woocommerce/block-settings': 'wc-settings', '@woocommerce/block-data': 'wc-blocks-data-store', + '@woocommerce/data': 'wc-store-data', '@woocommerce/shared-context': 'wc-blocks-shared-context', '@woocommerce/shared-hocs': 'wc-blocks-shared-hocs', '@woocommerce/price-format': 'wc-price-format', diff --git a/composer.lock b/composer.lock index 1a0acfea8..52c349887 100644 --- a/composer.lock +++ b/composer.lock @@ -8,23 +8,23 @@ "packages": [ { "name": "automattic/jetpack-autoloader", - "version": "v2.11.6", + "version": "v2.11.7", "source": { "type": "git", "url": "https://github.com/Automattic/jetpack-autoloader.git", - "reference": "a22f41ff845b8bd4591a933b282270f57dd5bc1d" + "reference": "65170ab358aa5a8efd9de96666a46b74dc74513d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/a22f41ff845b8bd4591a933b282270f57dd5bc1d", - "reference": "a22f41ff845b8bd4591a933b282270f57dd5bc1d", + "url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/65170ab358aa5a8efd9de96666a46b74dc74513d", + "reference": "65170ab358aa5a8efd9de96666a46b74dc74513d", "shasum": "" }, "require": { "composer-plugin-api": "^1.1 || ^2.0" }, "require-dev": { - "automattic/jetpack-changelogger": "^3.1", + "automattic/jetpack-changelogger": "^3.2", "yoast/phpunit-polyfills": "1.0.3" }, "type": "composer-plugin", @@ -53,9 +53,9 @@ ], "description": "Creates a custom autoloader for a plugin or theme.", "support": { - "source": "https://github.com/Automattic/jetpack-autoloader/tree/v2.11.6" + "source": "https://github.com/Automattic/jetpack-autoloader/tree/v2.11.7" }, - "time": "2022-06-21T07:32:07+00:00" + "time": "2022-07-26T13:41:25+00:00" }, { "name": "composer/installers", @@ -2715,16 +2715,16 @@ }, { "name": "wp-phpunit/wp-phpunit", - "version": "6.0.1", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/wp-phpunit/wp-phpunit.git", - "reference": "d4082280dd59add7c42d0a67400f8eb26cd790de" + "reference": "88c786f68c6abe1061f9e40f5e8b299e41a50287" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-phpunit/wp-phpunit/zipball/d4082280dd59add7c42d0a67400f8eb26cd790de", - "reference": "d4082280dd59add7c42d0a67400f8eb26cd790de", + "url": "https://api.github.com/repos/wp-phpunit/wp-phpunit/zipball/88c786f68c6abe1061f9e40f5e8b299e41a50287", + "reference": "88c786f68c6abe1061f9e40f5e8b299e41a50287", "shasum": "" }, "type": "library", @@ -2759,7 +2759,7 @@ "issues": "https://github.com/wp-phpunit/issues", "source": "https://github.com/wp-phpunit/wp-phpunit" }, - "time": "2022-07-12T22:10:08+00:00" + "time": "2022-08-30T21:14:52+00:00" }, { "name": "yoast/phpunit-polyfills", diff --git a/docs/README.md b/docs/README.md index c9d8cdfc9..bc9899303 100644 --- a/docs/README.md +++ b/docs/README.md @@ -146,7 +146,7 @@ The following tutorials from [developer.woocommerce.com](https://developer.wooco [We're hiring!](https://woocommerce.com/careers/) Come work with us! -🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/readme.md) +🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/README.md) diff --git a/docs/contributors/README.md b/docs/contributors/README.md index 2991aa4bb..a2836e09b 100644 --- a/docs/contributors/README.md +++ b/docs/contributors/README.md @@ -2,15 +2,15 @@ This folder contains documentation for developers and contributors looking to get started with WooCommerce Block Development. -| Document | Description | -| ---------------------------------------------------- | ---------------------------------------------------------------------------------------- | -| [Getting Started](getting-started.md) | This doc covers tooling and creating builds during development. | -| [Coding Guidelines](coding-guidelines.md) | This doc covers development best practices. | -| [JavaScript Testing](javascript-testing.md) | This doc explains how to run automated JavaScript tests. | -| [Developing Components (& Storybook)](components.md) | This doc outlines where our reusable components live, and how to test them in Storybook. | -| [Block Script Assets](block-assets.md) | This doc explains how Block Script Assets are loaded and used. | -| [JS build system](js-build-system.md) | This doc explains how JavaScript files are built. | -| [CSS build system](css-build-system.md) | This doc explains how CSS is built. | +| Document | Description | +|------------------------------------------------------------| ---------------------------------------------------------------------------------------- | +| [Getting Started](contributing/getting-started.md) | This doc covers tooling and creating builds during development. | +| [Coding Guidelines](contributing/coding-guidelines.md) | This doc covers development best practices. | +| [JavaScript Testing](contributing/javascript-testing.md) | This doc explains how to run automated JavaScript tests. | +| [Developing Components (& Storybook)](components.md) | This doc outlines where our reusable components live, and how to test them in Storybook. | +| [Block Script Assets](contributing/block-assets.md) | This doc explains how Block Script Assets are loaded and used. | +| [JS build system](contributing/javascript-build-system.md) | This doc explains how JavaScript files are built. | +| [CSS build system](contributing/css-build-system.md) | This doc explains how CSS is built. | diff --git a/docs/contributors/components.md b/docs/contributors/components.md index a24e19770..71081ad36 100644 --- a/docs/contributors/components.md +++ b/docs/contributors/components.md @@ -2,17 +2,15 @@ This repo includes [Storybook](https://storybook.js.org) tooling so we can test and develop components in isolation. -The storybook is automatically built and published to [GitHub pages](https://woocommerce.github.io/woocommerce-gutenberg-products-block/) on every push to the main branch. See [travis.yml](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/.travis.yml) for details. - - +The storybook is automatically built and published to [GitHub pages](https://woocommerce.github.io/woocommerce-blocks/) on every push to the main branch. ## Where are our components? We have components in a few folders, for different contexts. -- [`assets/js/base/components`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/assets/js/base/components) -- [`assets/js/editor-components`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/assets/js/editor-components) -- [`assets/js/icons`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/assets/js/icons) +- [`assets/js/base/components`](../../assets/js/base/components) +- [`assets/js/editor-components`](../../assets/js/editor-components) +- [`assets/js/icons`](../../assets/js/icons) **`assets/js/base/components`** are used in front-end code, as well as editor & admin. These components help us build consistent interfaces across the front end (shopper) experience and elsewhere. @@ -27,7 +25,7 @@ They allow us to build a consistent and powerful UI for merchants for authoring **`assets/js/icons`** is a suite of icons and SVG images that we use in our interfaces. -For more info about individual components, refer to [Storybook](https://woocommerce.github.io/woocommerce-gutenberg-products-block/) or individual readme files. +For more info about individual components, refer to [Storybook](https://woocommerce.github.io/woocommerce-blocks/) or individual readme files. ## How to run Storybook locally and test components diff --git a/docs/contributors/contributing/folder-structure.md b/docs/contributors/contributing/folder-structure.md index e3adfe01a..a54bb5cfd 100644 --- a/docs/contributors/contributing/folder-structure.md +++ b/docs/contributors/contributing/folder-structure.md @@ -2,6 +2,7 @@ The following snippet explains how the WooCommerce Blocks repository is structured omitting irrelevant or obvious items with further explanations: +```text │ ├── LICENSE ├── README.md @@ -184,6 +185,7 @@ The following snippet explains how the WooCommerce Blocks repository is structur ├── tests/utils │ Utilities for the test cases. │ +``` ## Credits diff --git a/docs/contributors/contributing/getting-started.md b/docs/contributors/contributing/getting-started.md index be57c1c43..16dbfc6f0 100644 --- a/docs/contributors/contributing/getting-started.md +++ b/docs/contributors/contributing/getting-started.md @@ -2,19 +2,19 @@ ## Table of contents -- [Cloning the Git Repository](#cloning-the-git-repository) -- [Configuring your WordPress site](#configuring-your-wordpress-site) -- [Installing dependencies](#installing-dependencies) -- [Building the plugin files](#building-the-plugin-files) - - [Legacy builds](#legacy-builds) -- [Create a plugin package in ZIP format](#create-a-plugin-package-in-zip-format) -- [Linting](#linting) -- [Running the Blocks plugin](#running-the-blocks-plugin) -- [Developer Tools (Visual Studio Code)](#developer-tools-visual-studio-code) - - [EditorConfig](#editorconfig) - - [ESLint](#eslint) - - [Prettier](#prettier) -- [Testing](#testing) +- [Cloning the Git Repository](#cloning-the-git-repository) +- [Configuring your WordPress site](#configuring-your-wordpress-site) +- [Installing dependencies](#installing-dependencies) +- [Building the plugin files](#building-the-plugin-files) + - [Legacy builds](#legacy-builds) +- [Create a plugin package in ZIP format](#create-a-plugin-package-in-zip-format) +- [Linting](#linting) +- [Running the Blocks plugin](#running-the-blocks-plugin) +- [Developer Tools (Visual Studio Code)](#developer-tools-visual-studio-code) + - [EditorConfig](#editorconfig) + - [ESLint](#eslint) + - [Prettier](#prettier) +- [Testing](#testing) Before you can begin contributing to the Blocks plugin there are several steps and tools required to setup your local development environment. @@ -52,7 +52,7 @@ To install dependencies, you will need the following tools installed on your mac - [`npm` and `node.js`](https://nodejs.org) - [`composer`](https://getcomposer.org) -See [`package.json` `engines`](../../package.json) for details of required versions. +See [`package.json` `engines`](../../../package.json) for details of required versions. Once you have `node` and `composer` setup, install the dependencies from the command line: @@ -79,7 +79,7 @@ This plugin supports two type of builds: The legacy builds are loaded in a site environment where the WordPress version doesn't meet minimum requirements for a component used in a set build. -You can read more about legacy builds in the [this doc](./assets/js/legacy/README.md). +You can read more about legacy builds in the [this doc](../../../assets/js/legacy/README.md). ## Create a plugin package in ZIP format @@ -96,9 +96,9 @@ Run `$ npm run lint` to check code against our linting rules. This script runs 3 sub-commands: `lint:php`, `lint:css`, `lint:js`. Use these to run linters across the codebase (linters check for valid syntax). -- `lint:php` runs phpcs via composer, which uses the [phpcs.xml](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/phpcs.xml) rule set. -- `lint:css` runs stylelint over all the scss code in `assets/css`, using the rules in [.stylelintrc.json.](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/.stylelintrc.json) -- `lint:js` runs eslint over all the JavaScript, using the rules in [.eslintrc.js.](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/.eslintrc.js) +- `lint:php` runs phpcs via composer, which uses the [phpcs.xml](../../../phpcs.xml) rule set. +- `lint:css` runs stylelint over all the scss code in `assets/css`, using the rules in [.stylelintrc.json.](../../../.stylelintrc.json) +- `lint:js` runs eslint over all the JavaScript, using the rules in [.eslintrc.js.](../../../.eslintrc.js) Note; linters are also ran before commits via Git. If there are any violations, you will not be able to commit your changes until they are fixed, unless you add the `--no-verify` flag to your commit command. @@ -148,7 +148,7 @@ You’ll find a handful of scripts in `package.json` that performs the automated - JS tests: `npm run test` - Run `npm run wp-env` command to setup the development environment in Docker. -To find out more about how to run automated JavaScript tests, check out the documentation on [JavaScript Testing](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/docs/contributors/javascript-testing.md). +To find out more about how to run automated JavaScript tests, check out the documentation on [JavaScript Testing](../../contributors/contributing/javascript-testing.md). diff --git a/docs/contributors/contributing/storybook-and-components.md b/docs/contributors/contributing/storybook-and-components.md index ba2721027..6bb83184c 100644 --- a/docs/contributors/contributing/storybook-and-components.md +++ b/docs/contributors/contributing/storybook-and-components.md @@ -6,15 +6,15 @@ - [How to run Storybook locally and test components](#how-to-run-storybook-locally-and-test-components) - [How to add a story for a component](#how-to-add-a-story-for-a-component) -This repo includes [Storybook](https://storybook.js.org) tooling so we can test and develop components in isolation. The storybook is automatically built and published to [GitHub pages](https://woocommerce.github.io/woocommerce-gutenberg-products-block/) on every push to the main branch. See [travis.yml](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/.travis.yml) for details. +This repo includes [Storybook](https://storybook.js.org) tooling so we can test and develop components in isolation. The storybook is automatically built and published to [GitHub pages](https://woocommerce.github.io/woocommerce-blocks/) on every push to the main branch. ## Where are our components? We have components in a few folders, for different contexts. -- [`assets/js/base/components`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/assets/js/base/components) -- [`assets/js/editor-components`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/assets/js/editor-components) -- [`assets/js/icons`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/assets/js/icons) +- [`assets/js/base/components`](../../../assets/js/base/components) +- [`assets/js/editor-components`](../../../assets/js/editor-components) +- [`assets/js/icons`](../../../assets/js/icons) **`assets/js/base/components`** are used in front-end code, as well as editor & admin. These components help us build consistent interfaces across the front end (shopper) experience and elsewhere. @@ -29,7 +29,7 @@ They allow us to build a consistent and powerful UI for merchants for authoring **`assets/js/icons`** is a suite of icons and SVG images that we use in our interfaces. -For more info about individual components, refer to [Storybook](https://woocommerce.github.io/woocommerce-gutenberg-products-block/) or individual readme files. +For more info about individual components, refer to [Storybook](https://woocommerce.github.io/woocommerce-blocks/) or individual readme files. ## How to run Storybook locally and test components diff --git a/docs/designers/theming/README.md b/docs/designers/theming/README.md index a24fec9e9..7cdd93e6f 100644 --- a/docs/designers/theming/README.md +++ b/docs/designers/theming/README.md @@ -6,7 +6,7 @@ This page includes all documentation regarding WooCommerce Blocks and themes. ### Block and component class names -WooCommerce Blocks follows BEM for class names, as [stated in our coding guidelines](../contributors/coding-guidelines.md). All classes start with one of these two prefixes: +WooCommerce Blocks follows BEM for class names, as [stated in our coding guidelines](../../contributors/contributing/coding-guidelines.md). All classes start with one of these two prefixes: - `.wc-block-`: class names specific to a single block. - `.wc-block-components-`: class names specific to a component. The component might be reused by different blocks. diff --git a/docs/designers/theming/all-products-and-filters.md b/docs/designers/theming/all-products-and-filters.md index c13f5efe6..222cbe403 100644 --- a/docs/designers/theming/all-products-and-filters.md +++ b/docs/designers/theming/all-products-and-filters.md @@ -2,7 +2,7 @@ ## Price slider accent color -The Filter Products by Price block includes a price slider which uses an accent color to show the selected range. +The Filter by Price block includes a price slider which uses an accent color to show the selected range. ![Price filter screenshot](https://user-images.githubusercontent.com/3616980/96570001-2053f900-12ca-11eb-8a75-8a54f243bda3.png) diff --git a/docs/internal-developers/automations/README.md b/docs/internal-developers/automations/README.md new file mode 100644 index 000000000..6c5b0cff4 --- /dev/null +++ b/docs/internal-developers/automations/README.md @@ -0,0 +1,19 @@ +# Automatations + +This directory contains documentation for all the automations configured in this repository. + +| Document | Description | +| -------------------------------------- | ------------------------------------- | +| [Dependabot](dependabot.md) | This doc explains how Dependabot works. | + + + + +--- + +[We're hiring!](https://woocommerce.com/careers/) Come work with us! + +🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/internal-developers/block-client-apis/README.md) + + + diff --git a/docs/internal-developers/automations/dependabot.md b/docs/internal-developers/automations/dependabot.md new file mode 100644 index 000000000..4bf761399 --- /dev/null +++ b/docs/internal-developers/automations/dependabot.md @@ -0,0 +1,10 @@ + +# Dependabot + +This repository uses [`Dependabot`](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates) to help with keeping all the package dependencies (NPM, Composer, GitHub Actions) up to date. Without this in place, it's very easy to let the package versions we're using go stale and end up with a backlog of chores for updating those in the future. It is essential to keep dependencies updated to avoid security problems and lower overall upgrade costs. +The process is automated: Dependabot creates a branch and a PR with a package bump in package.json. A new package-lock.json is created. Automated tests are executed. Also, Dependabot will create a maximum of 10 PRs for each ecosystem (NPM, Composer, GitHub Actions). + +It is the responsibility of the porter to review these PRs weekly and merge/reject them. + +Dependabot's configuration is located at [`.github/dependabot.yml` path](https://github.com/woocommerce/woocommerce-blocks/blob/trunk/.github/dependabot.yml). + diff --git a/docs/internal-developers/block-client-apis/README.md b/docs/internal-developers/block-client-apis/README.md index e7f2d9a1a..dda5813c9 100644 --- a/docs/internal-developers/block-client-apis/README.md +++ b/docs/internal-developers/block-client-apis/README.md @@ -2,13 +2,13 @@ This folder contains documentation for API interfaces for Blocks. In _most cases_, these docs describe APIs and interfaces that are _internal_ only, and thus are provided to assist with developing the blocks in this repository. Documentation will tend to focus on high level overviews. -For more details about extensibility points in the blocks, you can reference the [extensibility docs](../extensibility/README.md). +For more details about extensibility points in the blocks, you can reference the [extensibility docs](../../third-party-developers/extensibility/README.md). -| Document | Description | -| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -| [Checkout API interface](checkout/checkout-api.md) | This doc goes into some detail about some of the API specifics for the checkout block architecture. | -| [Checkout Flow and Events](../../third-party-developers/extensibility/checkout-flow-and-events.md) | All about the checkout flow in the checkout block and the various emitted events that can be subscribed to. | -| [Notices](notices.md) | Explains how the notices system works and which methods are available to add an remove them. | +| Document | Description | +| ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- | +| [Checkout API interface](checkout/checkout-api.md) | This doc goes into some detail about some of the API specifics for the checkout block architecture. | +| [Checkout Flow and Events](../../internal-developers/block-client-apis/checkout/checkout-flow-and-events.md) | All about the checkout flow in the checkout block and the various emitted events that can be subscribed to. | +| [Notices](notices.md) | Explains how the notices system works and which methods are available to add an remove them. | diff --git a/docs/internal-developers/block-client-apis/checkout/checkout-api.md b/docs/internal-developers/block-client-apis/checkout/checkout-api.md index 3a91eab66..ff4e9996b 100644 --- a/docs/internal-developers/block-client-apis/checkout/checkout-api.md +++ b/docs/internal-developers/block-client-apis/checkout/checkout-api.md @@ -2,22 +2,22 @@ ## Table of contents -- [Contexts](#contexts) - - [Notices Context](#notices-context) - - [Customer Data Context](#customer-data-context) - - [Shipping Method Data context](#shipping-method-data-context) - - [Payment Method Data Context](#payment-method-data-context) - - [Checkout Context](#checkout-context) -- [Hooks](#hooks) - - [`usePaymentMethodInterface`](#usepaymentmethodinterface) +- [Contexts](#contexts) + - [Notices Context](#notices-context) + - [Customer Data Context](#customer-data-context) + - [Shipping Method Data context](#shipping-method-data-context) + - [Payment Method Data Context](#payment-method-data-context) + - [Checkout Context](#checkout-context) +- [Hooks](#hooks) + - [`usePaymentMethodInterface`](#usepaymentmethodinterface) -This document gives an overview of some of the major architectural components/APIs for the checkout block. If you haven't already, you may also want to read about the [Checkout Flow and Events](../../extensibility/checkout-flow-and-events.md). +This document gives an overview of some of the major architectural components/APIs for the checkout block. If you haven't already, you may also want to read about the [Checkout Flow and Events](../../../internal-developers/block-client-apis/checkout/checkout-flow-and-events.md). ## Contexts Much of the data and api interface for components in the Checkout Block are constructed and exposed via [usage of `React.Context`](https://reactjs.org/docs/context.html). In some cases the context maintains the "tree" state within the context itself (via `useReducer`) and in others it interacts with a global `wp.data` store (for data that communicates with the server). -You can find type definitions (`typedef`) for contexts in [this file](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/assets/js/types/type-defs/contexts.js). +You can find type definitions (`typedef`) for contexts in [this file](../../../../assets/js/types/type-defs/contexts.js). ### Notices Context @@ -108,7 +108,7 @@ These docs currently don't go into detail for all the hooks as that is fairly st ### `usePaymentMethodInterface` -This hook is used to expose all the interfaces for the registered payment method components to utilize. Essentially the result from this hook is fed in as props on the registered payment components when they are setup by checkout. You can use the typedef ([`PaymentMethodInterface`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/assets/js/type-defs/payment-method-interface.ts)) to see what is fed to payment methods as props from this hook. +This hook is used to expose all the interfaces for the registered payment method components to utilize. Essentially the result from this hook is fed in as props on the registered payment components when they are setup by checkout. You can use the typedef ([`PaymentMethodInterface`](../../../../assets/js/types/type-defs/payment-method-interface.ts)) to see what is fed to payment methods as props from this hook. _Why don't payment methods just implement this hook_? diff --git a/docs/internal-developers/block-client-apis/checkout/checkout-flow-and-events.md b/docs/internal-developers/block-client-apis/checkout/checkout-flow-and-events.md index 90c1cd653..1b66f393b 100644 --- a/docs/internal-developers/block-client-apis/checkout/checkout-flow-and-events.md +++ b/docs/internal-developers/block-client-apis/checkout/checkout-flow-and-events.md @@ -2,24 +2,24 @@ ## Table of Contents -- [General Concepts](#general-concepts) - - [Tracking flow through status](#tracking-flow-through-status) - - [`CheckoutProvider` Exposed Statuses](#checkoutprovider-exposed-statuses) - - [Special States:](#special-states) - - [`ShippingProvider` Exposed Statuses](#shippingprovider-exposed-statuses) - - [`PaymentMethodDataProvider` Exposed Statuses](#paymentmethoddataprovider-exposed-statuses) - - [Emitting Events](#emitting-events) - - [`onCheckoutValidationBeforeProcessing`](#oncheckoutvalidationbeforeprocessing) - - [`onPaymentProcessing`](#onpaymentprocessing) - - [Success](#success) - - [Fail](#fail) - - [Error](#error) - - [`onCheckoutAfterProcessingWithSuccess`](#oncheckoutafterprocessingwithsuccess) - - [`onCheckoutAfterProcessingWithError`](#oncheckoutafterprocessingwitherror) - - [`onShippingRateSuccess`](#onshippingratesuccess) - - [`onShippingRateFail`](#onshippingratefail) - - [`onShippingRateSelectSuccess`](#onshippingrateselectsuccess) - - [`onShippingRateSelectFail`](#onshippingrateselectfail) +- [General Concepts](#general-concepts) + - [Tracking flow through status](#tracking-flow-through-status) + - [`CheckoutProvider` Exposed Statuses](#checkoutprovider-exposed-statuses) + - [Special States:](#special-states) + - [`ShippingProvider` Exposed Statuses](#shippingprovider-exposed-statuses) + - [`PaymentMethodDataProvider` Exposed Statuses](#paymentmethoddataprovider-exposed-statuses) + - [Emitting Events](#emitting-events) + - [`onCheckoutValidationBeforeProcessing`](#oncheckoutvalidationbeforeprocessing) + - [`onPaymentProcessing`](#onpaymentprocessing) + - [Success](#success) + - [Fail](#fail) + - [Error](#error) + - [`onCheckoutAfterProcessingWithSuccess`](#oncheckoutafterprocessingwithsuccess) + - [`onCheckoutAfterProcessingWithError`](#oncheckoutafterprocessingwitherror) + - [`onShippingRateSuccess`](#onshippingratesuccess) + - [`onShippingRateFail`](#onshippingratefail) + - [`onShippingRateSelectSuccess`](#onshippingrateselectsuccess) + - [`onShippingRateSelectFail`](#onshippingrateselectfail) This document gives an overview of the flow for the checkout in the WooCommerce checkout block, and some general architectural overviews. @@ -99,7 +99,7 @@ The status is exposed on the `currentErrorStatus` object provided by the `useShi ### `PaymentMethodDataProvider` Exposed Statuses -This context provider exposes everything related to payment method data and registered payment methods. The statuses exposed via this provider help inform the current state of _client side_ processing for payment methods and are updated via the payment method data event emitters. _Client side_ means the state of processing any payments by registered and active payment methods when the checkout form is submitted via those payment methods registered client side components. It's still possible that payment methods might have additional server side processing when the order is being processed but that is not reflected by these statuses (more in the [payment method integration doc](./payment-method-integration.md)). +This context provider exposes everything related to payment method data and registered payment methods. The statuses exposed via this provider help inform the current state of _client side_ processing for payment methods and are updated via the payment method data event emitters. _Client side_ means the state of processing any payments by registered and active payment methods when the checkout form is submitted via those payment methods registered client side components. It's still possible that payment methods might have additional server side processing when the order is being processed but that is not reflected by these statuses (more in the [payment method integration doc](../../../third-party-developers/extensibility/checkout-payment-methods/payment-method-integration.md)). The possible _internal_ statuses that may be set are: @@ -266,7 +266,7 @@ const successResponse = { type: 'success' }; When a success response is returned, the payment method context status will be changed to `SUCCESS`. In addition, including any of the additional properties will result in extra actions: - `paymentMethodData`: The contents of this object will be included as the value for `payment_data` when checkout sends a request to the checkout endpoint for processing the order. This is useful if a payment method does additional server side processing. -- `billingData`: This allows payment methods to update any billing data information in the checkout (typically used by Express payment methods) so it's included in the checkout processing request to the server. This data should be in the [shape outlined here](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/assets/js/type-defs/billing.js). +- `billingData`: This allows payment methods to update any billing data information in the checkout (typically used by Express payment methods) so it's included in the checkout processing request to the server. This data should be in the [shape outlined here](../../../../assets/js/types/type-defs/billing.js). - `shippingData`: This allows payment methods to update any shipping data information for the order (typically used by Express payment methods) so it's included in the checkout processing request to the server. This data should be in the [shape outlined here](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/assets/js/type-defs/cart.js#L20-L32). If `billingData` or `shippingData` properties aren't in the response object, then the state for the data is left alone. diff --git a/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md b/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md index 7612c4bf8..29c2b4364 100644 --- a/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md +++ b/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md @@ -2,19 +2,19 @@ ## Table of contents -- [Blocks behind flags](#blocks-behind-flags) - - [Feature plugin flag](#feature-plugin-flag) - - [Experimental flag](#experimental-flag) -- [Features behind flags](#features-behind-flags) - - [Feature plugin flag](#feature-plugin-flag-1) - - [Experimental plugin flag](#experimental-plugin-flag) -- [Processes and commands that use a flag](#processes-and-commands-that-use-a-flag) -- [Usages of `__experimental` prefix](#usages-of-__experimental-prefix) - - [PHP filters and actions](#php-filters-and-actions) - - [JS methods](#js-methods) - - [Slots](#slots) - - [Misc](#misc) -- [Usages of `experimental` prefix](#usages-of-experimental-prefix) +- [Blocks behind flags](#blocks-behind-flags) + - [Feature plugin flag](#feature-plugin-flag) + - [Experimental flag](#experimental-flag) +- [Features behind flags](#features-behind-flags) + - [Feature plugin flag](#feature-plugin-flag-1) + - [Experimental plugin flag](#experimental-plugin-flag) +- [Processes and commands that use a flag](#processes-and-commands-that-use-a-flag) +- [Usages of `__experimental` prefix](#usages-of-__experimental-prefix) + - [PHP filters and actions](#php-filters-and-actions) + - [JS methods](#js-methods) + - [Slots](#slots) + - [Misc](#misc) +- [Usages of `experimental` prefix](#usages-of-experimental-prefix) We have feature gating system setup in our plugin that defines what is accessible to the public and what is not, it has three phases: @@ -33,32 +33,8 @@ The majority of our feature flagging is blocks, this is a list of them: ### Feature plugin flag -- Cart block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/f76c7e46ce63d88059d8ce8b05d9409b78988e5f/assets/js/blocks/cart-checkout/cart/index.js#L51) | [PHP flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/4a1ee97eb97011458174e93e44a9b7ad2f10ca36/src/BlockTypesController.php#L177)). -- Checkout block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/89b5d3032aa9d8b7368ba4edd3da222d076fbcaa/assets/js/blocks/cart-checkout/checkout/index.js#L86) | [PHP flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/4a1ee97eb97011458174e93e44a9b7ad2f10ca36/src/BlockTypesController.php#L176)). -- Checkout Actions block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/78e2de7a3ddfd3a554273fd6c2ff68478e9692ad/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-actions-block/index.tsx#14)). -- Checkout Billing Address block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/78e2de7a3ddfd3a554273fd6c2ff68478e9692ad/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-billing-address-block/index.tsx#14)). -- Checkout Contact Information block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/78e2de7a3ddfd3a554273fd6c2ff68478e9692ad/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-contact-information-block/index.tsx#14)). -- Checkout Express Payment block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/1cf7823eab9ccc974312fb806af7d8b77da8969e/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-express-payment-block/index.tsx#12)). -- Checkout Fields block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/78e2de7a3ddfd3a554273fd6c2ff68478e9692ad/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-fields-block/index.tsx#13)). -- Checkout Order Note block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/1cf7823eab9ccc974312fb806af7d8b77da8969e/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-order-note-block/index.tsx#13)). -- Checkout Order Summary block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/78e2de7a3ddfd3a554273fd6c2ff68478e9692ad/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-order-summary-block/index.tsx#14)). -- Checkout Payment block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/78e2de7a3ddfd3a554273fd6c2ff68478e9692ad/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-payment-block/index.tsx#14)). -- Checkout Shipping Address block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/78e2de7a3ddfd3a554273fd6c2ff68478e9692ad/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-shipping-address-block/index.tsx#14)). -- Checkout Shipping Methods block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/78e2de7a3ddfd3a554273fd6c2ff68478e9692ad/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-shipping-methods-block/index.tsx#14)). -- Checkout Terms block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/89b5d3032aa9d8b7368ba4edd3da222d076fbcaa/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-terms-block/index.tsx#13)). -- Checkout Totals block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/78e2de7a3ddfd3a554273fd6c2ff68478e9692ad/assets/js/blocks/cart-checkout/checkout-i2/inner-blocks/checkout-totals-block/index.tsx#L13)). - ### Experimental flag -- Cart block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/index.js#L44) | [PHP flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/961c0c476d4228a218859c658c42f9b6eebfdec4/src/BlockTypesController.php#L182)). -- Cart Express Checkout block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/cart-express-payment-block/index.tsx#L13)). -- Cart Items block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/cart-items-block/index.tsx#L13)). -- Cart Line Items block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/cart-line-items-block/index.tsx#L13)). -- Cart Order Summary block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/cart-order-summary-block/index.tsx#L14)). -- Cart Totals block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/cart-totals-block/index.tsx#L13)). -- Empty Cart block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/empty-cart-block/index.tsx#L13)). -- Filled Cart block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/filled-cart-block/index.tsx#L13)). -- Cart Proceed to checkout block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/proceed-to-checkout-block/index.tsx#L14)). - Single Product block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/9b76ea7a1680e68cc20bfee01078e43ccfc996bd/assets/js/blocks/single-product/index.js#L43) | [PHP flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/4a1ee97eb97011458174e93e44a9b7ad2f10ca36/src/BlockTypesController.php#L181) | [webpack flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/341be1f56071fbd4b5ff975e8788d65a09512df2/bin/webpack-entries.js#L57-L59)). - ⚛️ Add to cart ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/add-to-cart/index.js#L29-L32)). - ⚛️ Product category list ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/category-list/index.js#L29-L32)). @@ -72,16 +48,9 @@ We also have individual features or code blocks behind a feature flag, this is a ### Feature plugin flag -- Payment API ([PHP flag 1](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/07387889ec3a03769eb490821ee608d4e741e942/src/Domain/Bootstrap.php#L92-L94) | [PHP flag 2](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/07387889ec3a03769eb490821ee608d4e741e942/src/Domain/Bootstrap.php#L245-L254)). - ⚛️ Product Price new controls ([JS flag 1](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/price/attributes.js#L13-L44) | [JS flag 2-1](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8d2f0ad8ade2c7217769b431f93de76d6cfacf6e/assets/js/atomic/blocks/product-elements/price/block.js#L116) | [JS flag 2-2](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8d2f0ad8ade2c7217769b431f93de76d6cfacf6e/assets/js/atomic/blocks/product-elements/price/block.js#L114) | [JS flag 2-3](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8d2f0ad8ade2c7217769b431f93de76d6cfacf6e/assets/js/atomic/blocks/product-elements/price/block.js#L91) | [JS flag 2-4](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8d2f0ad8ade2c7217769b431f93de76d6cfacf6e/assets/js/atomic/blocks/product-elements/price/block.js#L95) | [JS flag 2-5](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8d2f0ad8ade2c7217769b431f93de76d6cfacf6e/assets/js/atomic/blocks/product-elements/price/block.js#L106) | [JS flag 3-1](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/price/edit.js#L59-L108) | [JS flag 3-2](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/price/edit.js#L114-L131)). - ⚛️ Product Title new controls ([JS flag 1](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/title/attributes.js#L21-L40) | [JS flag 2-1](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/title/block.js#L70-L72) | [JS flag 2-2](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/title/block.js#L94-L95) | [JS flag 2-3](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/title/block.js#L104) | [JS flag 3-1](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/title/edit.js#L47-L54) | [JS flag 3-2](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/title/edit.js#L77-L107) | [JS flag 3-3](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/title/edit.js#L116-L129)). - Utility function to pass styles to a block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/9ebddbc5d21eb3cc67fedddbccbd86453313eb64/assets/js/atomic/utils/block-styling.js#L6-L12)). -- Feature to create an account from the Checkout block ([PHP flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/4cedb65367be0d1c4c1f9dd9c016e3b1325cf92e/src/Domain/Services/CreateAccount.php#L40)). -- Checkout package ([PHP Flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/6da64165025e7a2afc1782e4b278d72536e7b754/src/AssetsController.php#L62-L64)) which contains: - - SlotFills used in Cart and Checkout. - - Checkout Filters. - - Inner Blocks registry for Cart & Checkout i2. - - Components exposed to 3PD. ### Experimental plugin flag @@ -108,8 +77,8 @@ We also have individual features or code blocks behind a feature flag, this is a ### JS methods -- `__experimentalDeRegisterPaymentMethod` function used to deregister a payment method, only used in tests ([experimental function](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b07883b8b76feeb439d655b255507b24fc59e091/assets/js/blocks-registry/payment-methods/registry.ts#L114)). -- `__experimentalDeRegisterExpressPaymentMethod` function used to deregister an express payment method, only used in tests ([experimental function](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b07883b8b76feeb439d655b255507b24fc59e091/assets/js/blocks-registry/payment-methods/registry.ts#L120)). +- `__experimentalDeRegisterPaymentMethod` function used to deregister a payment method, only used in tests ([experimental function](https://github.com/woocommerce/woocommerce-blocks/blob/f27456dd00fa0b21b29a935943defb18351edf48/assets/js/blocks-registry/payment-methods/registry.ts#L110-L114)). +- `__experimentalDeRegisterExpressPaymentMethod` function used to deregister an express payment method, only used in tests ([experimental function](https://github.com/woocommerce/woocommerce-blocks/blob/f27456dd00fa0b21b29a935943defb18351edf48/assets/js/blocks-registry/payment-methods/registry.ts#L116-L120)). - `__experimentalRegisterCheckoutFilters` and `__experimentalApplyCheckoutFilter` methods included with `@woocommerce/blocks-checkout` package. They allow registering and applying a filter to certain parts of the Cart and Checkout blocks ([experimental method 1](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/3e59ec9842464f783f6e087947e717fa0b0a7b1b/packages/checkout/registry/index.js#L2) | [experimental method 2](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/3e59ec9842464f783f6e087947e717fa0b0a7b1b/packages/checkout/registry/index.js#L17)). ### Slots diff --git a/docs/internal-developers/testing/releases/260.md b/docs/internal-developers/testing/releases/260.md index b3bc55c65..e5feb8a19 100644 --- a/docs/internal-developers/testing/releases/260.md +++ b/docs/internal-developers/testing/releases/260.md @@ -5,7 +5,7 @@ ## Cart and Checkout Blocks -[See testing notes here](https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/docs/testing/cart-checkout) +[See testing notes here](../cart-checkout/) ## All Products diff --git a/docs/internal-developers/testing/releases/270.md b/docs/internal-developers/testing/releases/270.md index 227778a23..65f11fc50 100644 --- a/docs/internal-developers/testing/releases/270.md +++ b/docs/internal-developers/testing/releases/270.md @@ -11,7 +11,7 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. ![Checkout heading styles](https://user-images.githubusercontent.com/3616980/84032118-1e327300-a997-11ea-8c06-363ac2bd78b3.png) - In Checkout, the item quantity badges are visible with dark backgrounds (with Storefront, you can change the background color in Appearance > Customize > Background) (#2619). \ ![Item quantity badges](https://user-images.githubusercontent.com/3616980/84031988-ed523e00-a996-11ea-8545-339111e31f5f.png) - - Try adding the code snippet from the [Cart and Checkout theming](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/docs/theming/cart-and-checkout.md#item-quantity-badge) docs (you can do it via a child theme or directly in the browser devtools) and verify the item quantity badge styles update accordingly. + - Try adding the code snippet from the [Cart and Checkout theming](../../../designers/theming/cart-and-checkout.md#item-quantity-badge) docs (you can do it via a child theme or directly in the browser devtools) and verify the item quantity badge styles update accordingly. - In general, verify there were no regressions introduced after 2.6.0. - The Cart block title should be `Your cart (X items)` (#2615). \ ![Cart block title](https://user-images.githubusercontent.com/3616980/84032294-66ea2c00-a997-11ea-8d6d-929668cb702b.png) @@ -30,10 +30,10 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. ![Select in Hello theme](https://user-images.githubusercontent.com/3616980/84032650-f4c61700-a997-11ea-969d-6427d1e221bb.png) - Twenty Twenty: - Add the All Products block and the Hand-picked Products block in a page and verify (#2573): - That with the All Products block you can add the On Sale badge and it's correctly aligned in the editor and the frontend (before, it was always shown on top of the image). \ - ![All Products in Twenty Twenty](https://user-images.githubusercontent.com/3616980/83013870-fef22800-a01d-11ea-8ea8-21229285d10a.png) + ![All Products in Twenty Twenty](https://user-images.githubusercontent.com/3616980/83013870-fef22800-a01d-11ea-8ea8-21229285d10a.png) - The Hand-picked Products block discounted prices are not underlined. \ ![Hand-picked Products in Twenty Twenty](https://user-images.githubusercontent.com/3616980/83013599-8e4b0b80-a01d-11ea-88ab-a1537110c4e2.png) -- Go to the Checkout block and verify font sizes look correct (they are inherited from the theme) (#2533). +- Go to the Checkout block and verify font sizes look correct (they are inherited from the theme) (#2533). ## Cart and Checkout error flow (#2655) @@ -94,7 +94,7 @@ You'll need to be logged in with a user that has saved payment methods. - Add the All Products block and a PHP-based product grids block (Hand-picked Products, for example) and verify: - Both of them have the same styles for prices. - Both of them scale up the small image. _Hand-picked Products on top, All Products below:_ \ ![Product grid blocks by default](https://user-images.githubusercontent.com/3616980/83166453-3d1b4480-a10f-11ea-813f-2515b26dedac.png) -- Add the [code snippets](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/docs/theming/product-grid-270.md#product-grid-blocks-style-update-in-270) from the theming docs to undo the changes and verify: - Hand-picked Products block doesn't scale up the image anymore. - All Products block shows discounted prices in two lines. +- Add the [code snippets](../../../designers/theming/product-grid-270.md#product-grid-blocks-style-update-in-270) from the theming docs to undo the changes and verify: - Hand-picked Products block doesn't scale up the image anymore. - All Products block shows discounted prices in two lines. _Hand-picked Products on top, All Products below:_ \ ![Product grid blocks with the code snippets applied](https://user-images.githubusercontent.com/3616980/83164436-828a4280-a10c-11ea-81c1-b9a62cdf52b5.png) diff --git a/docs/internal-developers/testing/releases/790.md b/docs/internal-developers/testing/releases/790.md index fa3182f28..fe958ea06 100644 --- a/docs/internal-developers/testing/releases/790.md +++ b/docs/internal-developers/testing/releases/790.md @@ -18,8 +18,8 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. ### Fix images hidden by default in Product grid blocks. ([6599](https://github.com/woocommerce/woocommerce-blocks/pull/6599)) -| Before | After | -| ------ | ----- | +| Before | After | +| --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | ![imatge](https://user-images.githubusercontent.com/3616980/174588765-7e570a5b-d428-4604-b2af-6534e388b550.png) | ![imatge](https://user-images.githubusercontent.com/3616980/174588822-9cdb7813-05d1-4f97-ae55-1d4392c9f65a.png) | 1. With WC core 6.5.1 and WC Blocks disabled, add a Handpicked Products block to a post or page. @@ -31,14 +31,13 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. 7. Verify images are visible by default. 8. Verify you can still toggle the images. -### Fix: Scrolling issue of the Filled Mini Cart Contents block. ([6565](https://github.com/woocommerce/woocommerce-blocks/pull/6565)) +### Fix: Scrolling issue of the Filled Mini Cart view block. ([6565](https://github.com/woocommerce/woocommerce-blocks/pull/6565)) -| Before | After | -| ------ | ----- | -| ![Before](https://user-images.githubusercontent.com/5423135/173493967-1009d322-351e-451c-a10c-c6456ec08f52.png) | ![After](https://user-images.githubusercontent.com/5423135/173533745-41cda7ed-a068-4d5d-b948-7e2038f3d21c.png) | +| Before | After | +| ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| ![Before](https://user-images.githubusercontent.com/5423135/173493967-1009d322-351e-451c-a10c-c6456ec08f52.png) | ![After](https://user-images.githubusercontent.com/5423135/173533745-41cda7ed-a068-4d5d-b948-7e2038f3d21c.png) | | image | image | - 1. With a block theme like 2022. Edit the Mini Cart template part. 2. Add some blocks to the Mini Cart Items section to make the content overflow. 3. See the footer inside the viewport, and the Mini Cart Items block is now scrollable to view the underneath content. @@ -48,13 +47,11 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. ### Added descriptions to the FSE WooCommerce Templates in the Editor UI. ([6345](https://github.com/woocommerce/woocommerce-blocks/pull/6345)) +| Before | After | +| ------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| ![bifor_fixed](https://user-images.githubusercontent.com/905781/165815026-408dccff-ea16-4766-8a65-9696866e6f92.jpg) | ![after_-_fixed](https://user-images.githubusercontent.com/905781/165815040-723bb981-5cc2-4787-a38d-d9dee3e12757.jpg) | -|Before|After| -|-|-| -|![bifor_fixed](https://user-images.githubusercontent.com/905781/165815026-408dccff-ea16-4766-8a65-9696866e6f92.jpg)|![after_-_fixed](https://user-images.githubusercontent.com/905781/165815040-723bb981-5cc2-4787-a38d-d9dee3e12757.jpg)| - - -#### Testing template descriptions** +#### Testing template descriptions\*\* 1. Activate a **block** theme, like Twenty Twenty Two 2. Open the **Appearance > Editor (Beta)** @@ -63,14 +60,12 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. 5. Open a template (like Mini cart) 6. make sure you can edit and save the content. - -#### Testing the search template** +#### Testing the search template\*\* 1. Activate a **block** theme, like Twenty Twenty Two 2. Make sure there's at least 1 product added 3. Run a product search: `?s={keyword}&post_type=product` and make sure the products are being displayed correctly in a grid (using the search template, instead of the default one). - ## Feature plugin only ### Prevent warnings appearing when using some plugins for managing shipping packages. ([6470](https://github.com/woocommerce/woocommerce-blocks/pull/6470)) @@ -81,7 +76,7 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. 4. Add multiple items to your cart. 5. Go to the Checkout/Cart Block. 6. Ensure you see no errors. - + --- @@ -90,4 +85,3 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. 🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/internal-developers/testing/releases/790.md) - diff --git a/docs/internal-developers/testing/releases/820.md b/docs/internal-developers/testing/releases/820.md index 5df2aa206..4f0bf0674 100644 --- a/docs/internal-developers/testing/releases/820.md +++ b/docs/internal-developers/testing/releases/820.md @@ -19,9 +19,9 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. 2. Navigate to **Appearance > Editor (Beta)** and add a Mini Cart block somewhere in your site. 3. Select the Mini Cart block in the editor and confirm the icon in the inserter and toolbar reflect the changes. -| Before | After | -| ------ | ----- | -| ![CleanShot 2022-07-28 at 14 57 58](https://user-images.githubusercontent.com/481776/181622493-d618649c-e9ee-4649-9e10-a2aed6737fc5.png) | ![CleanShot 2022-07-28 at 15 31 41](https://user-images.githubusercontent.com/481776/181622516-4bade22f-944a-488e-aacc-6094afa97efe.png) | +| Before | After | +| ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| ![CleanShot 2022-07-28 at 14 57 58](https://user-images.githubusercontent.com/481776/181622493-d618649c-e9ee-4649-9e10-a2aed6737fc5.png) | ![CleanShot 2022-07-28 at 15 31 41](https://user-images.githubusercontent.com/481776/181622516-4bade22f-944a-488e-aacc-6094afa97efe.png) | ### Fix: Replace DropdownSelector with FormTokenField from Gutenberg ([6647](https://github.com/woocommerce/woocommerce-blocks/pull/6647)) @@ -39,9 +39,9 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. 5. Hover over one of the terms and click the `View` link of one of the attributes. 6. Check that the page is rendered with a header, a footer, and using a product grid. -| Before | After | -| ------ | ----- | -| Screenshot 2022-07-27 at 16 38 51 | ![Screenshot 2022-07-27 at 16 38 41](https://user-images.githubusercontent.com/186112/181275933-3b712c54-1c6f-4578-8a25-659052cde175.png)| +| Before | After | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| Screenshot 2022-07-27 at 16 38 51 | ![Screenshot 2022-07-27 at 16 38 41](https://user-images.githubusercontent.com/186112/181275933-3b712c54-1c6f-4578-8a25-659052cde175.png) | ### All Products block: Migrate to block.json ([6754](https://github.com/woocommerce/woocommerce-blocks/pull/6754)) @@ -97,10 +97,9 @@ Test that there are no regressions compared with the previous `Product Best Sell 3. Make sure all matching products appear on the list. 4. Make sure all items on the list preserve their original case. - -| Before | After | -| ------ | ----- | -| 172268138-7445fbf1-ad25-4716-8b5a-ee4b463af54b | ![Screenshot 2022-06-11 at 21 16 42](https://user-images.githubusercontent.com/1847066/173202019-aa3659e5-0dd4-454b-95bd-f2ead03ee40d.png) | +| Before | After | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| 172268138-7445fbf1-ad25-4716-8b5a-ee4b463af54b | ![Screenshot 2022-06-11 at 21 16 42](https://user-images.githubusercontent.com/1847066/173202019-aa3659e5-0dd4-454b-95bd-f2ead03ee40d.png) | ## Feature plugin @@ -131,8 +130,8 @@ Test that there are no regressions compared with the previous `Product Best Sell 5. Go the checkout page and look at the shipping options, ensure there is a title for each one. 6. Disable the plugin and reload the Checkout Block, ensure the shipping section still looks OK. -| Before | After | -| ------ | ----- | +| Before | After | +| ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | | | image | ### Fix missing translations in inspector ([6737](https://github.com/woocommerce/woocommerce-blocks/pull/6737)) @@ -149,7 +148,6 @@ Test that there are no regressions compared with the previous `Product Best Sell [We're hiring!](https://woocommerce.com/careers/) Come work with us! -🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/internal-developers/testing/releases/810.md) +🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/internal-developers/testing/releases/820.md) - diff --git a/docs/internal-developers/testing/releases/821.md b/docs/internal-developers/testing/releases/821.md index bd77494dd..3fbc57eee 100644 --- a/docs/internal-developers/testing/releases/821.md +++ b/docs/internal-developers/testing/releases/821.md @@ -7,12 +7,12 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. ### Ensure onChange is set for radio buttons in `SavedPaymentMethodOptions` ([6825](https://github.com/woocommerce/woocommerce-blocks/pull/6825)) 1. Install Stripe, set it up so you can use it at Checkout. -2. Add items to your cart and go to checkout. Add a credit/debit card via stripe and choose `Save payment information to my account for future purchases.` -3. Check out. Repeat step 2 once more with a different card number. **Ensure the new card you use ends in four different numbers than the first one!** You can see test cards here: -4. Add items to your cart and go to checkout a third time. This time ensure you can switch between saved cards. - image -5. Check out successfully, and then go to the back end of your site. Go to the orders you made (WooCommerce -> Orders) and for each order check the payment method used (you'll need to follow this through to Stripe), and ensure the card number used matches the one you chose in the Checkout block. (Click the link on the order page) - image +2. Add items to your cart and go to checkout. Add a credit/debit card via stripe and choose `Save payment information to my account for future purchases.` +3. Check out. Repeat step 2 once more with a different card number. **Ensure the new card you use ends in four different numbers than the first one!** You can see test cards here: +4. Add items to your cart and go to checkout a third time. This time ensure you can switch between saved cards. + image +5. Check out successfully, and then go to the back end of your site. Go to the orders you made (WooCommerce -> Orders) and for each order check the payment method used (you'll need to follow this through to Stripe), and ensure the card number used matches the one you chose in the Checkout block. (Click the link on the order page) + image @@ -20,7 +20,6 @@ Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github. [We're hiring!](https://woocommerce.com/careers/) Come work with us! -🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/internal-developers/testing/releases/810.md) +🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/internal-developers/testing/releases/821.md) - diff --git a/docs/internal-developers/testing/releases/830.md b/docs/internal-developers/testing/releases/830.md new file mode 100644 index 000000000..fe469c83d --- /dev/null +++ b/docs/internal-developers/testing/releases/830.md @@ -0,0 +1,124 @@ +# Testing notes and ZIP for release 8.3.0 + +Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github.com/woocommerce/woocommerce-blocks/files/9350354/woocommerce-gutenberg-products-block.zip) + +## Feature plugin and package inclusion in WooCommerce + +### Enable the Cart and Checkout blocks when WooCommerce Blocks is bundled in WooCommerce Core. ([6805](https://github.com/woocommerce/woocommerce-blocks/pull/6805)) + +**Cart Block**: + +1. In the Cart Block in the editor, ensure the shipping calculator is enabled. +2. Enable coupons on your site (WooCommerce -> Settings -> General -> Enable the use of coupon codes) and add one. +3. Add two shipping methods for different locations, e.g. two for USA and two for UK. +4. Do not add items to your cart. +5. Go to the Cart Block and ensure the empty cart is displayed. +6. Add items to your cart and revisit the Cart Block. +7. Enter your address in the shipping calculator, ensure the correct shipping prices are displayed based on your location. +8. Enter a coupon and ensure it works, and the price is modified accordingly. +9. Modify the quantities of items in your cart, ensure it works and the prices update properly. +10. If you have express payments enabled and working, try checking out from the Cart Block using GPay or Apple pay. +11. If you don't, hit proceed to checkout and ensure it works correctly. + +**Checkout Block**: + +1. Go to WooCommerce -> Settings -> Accounts & Privacy and enable ` Allow customers to create an account during checkout` and `Allow customers to log into an existing account during checkout`. +2. Go to Checkout Block editor, select contact information block and enable `Allow shoppers to sign up for a user account during checkout`. +3. Enable the Stripe payment method, COD, and cheque. +4. Log out of the site then add items to your cart and go to the Checkout Block. +5. Check the `create account` box when entering your details. +6. Remove the coupon added in the Cart testing steps, and try re-adding it. +7. Change shipping methods and ensure the prices update. +8. Change address, ensure shipping prices update when the country changes. +9. Leave some fields empty on the address form, ensure you get an error. +10. Re-fill them and enter an invalid ZIP code. (Set country to UK and enter 234345 as the Postcode). Ensure you see an error at the top of the block. +11. Correct the error (A valid one is `SW19 1AA` if in UK). +12. Check out and ensure it works and the order is logged correctly. +13. Ensure you received emails relating to your order (if using Local WP you can go to your site -> tools -> mailhog to check this). + +### Refactor Product Categories block to use block.json. ([6875](https://github.com/woocommerce/woocommerce-blocks/pull/6875)) + +**WooCommerce Blocks**: + +1. Add Product Categories List block as a widget (Appearance → Widgets) +2. Open block settings +3. Test block controls, save, and review if it still renders correctly in the frontend + +**WPCOM**: + +1. Add Product Categories List block as a widget (Appearance → Widgets) +2. Open block settings +3. Open Advanced and click on "Add new rule" under Visibility + +### Add feedback box to the Cart & Checkout Inner Blocks in the inspector. ([6881](https://github.com/woocommerce/woocommerce-blocks/pull/6881)) + +1. Go to the Cart and Checkout editor pages +2. Select the Block and each of its inner blocks. You should notice the feedback box in the inspector. + +![image](https://user-images.githubusercontent.com/14235870/183031149-73a4bb4b-975a-4c9e-a82f-9241a61beb8a.png) + +### Add notice to Cart and Checkout blocks' inspector controls which links to the list of compatible plugins. ([6869](https://github.com/woocommerce/woocommerce-blocks/pull/6869)) + +1. Go to the editor, insert the Checkout block. +2. Select it, verify you see the notice. Click through each and every inner block and ensure the notice displays for it. +3. Dismiss the notice, click back through the inner blocks and ensure the notice is gone. Reload the page, ensure the notice is still gone. +4. Go to the editor, insert the Cart block. +5. Select it, verify you see the notice. Click through each and every inner block and ensure the notice displays for it. +6. Dismiss the notice, click back through the inner blocks and ensure the notice is gone. Reload the page, ensure the notice is still gone. +7. Clear local storage again. +8. Go back to the Cart and Checkout blocks and ensure the notice is back. +9. Create a new page. Add the Checkout Block. Select it and verify the sidebar contains the default warning: +image. +Verify the wording says **checkout**. +10. Add the Cart Block, ensure the same notice appears but ensure it says **cart**. + +### Add the ability to register patterns by adding them under the "patterns" folder and add the new "WooCommerce Filters" pattern. ([6861](https://github.com/woocommerce/woocommerce-blocks/pull/6861)) + +1. Create a new page with the `All Products` block. +2. Open the block inserter, go to the patterns tab, and select the WooCommerce category from the dropdown +3. Make sure you see a pattern under that category named: `WooCommerce Filters` +4. Click on it to insert it on the page. +5. Check that all 4 filter blocks (by attribute, price, stock, and active filters) are added. +6. Complete the filter by attribute by selecting one of them. +7. Save the page and make sure all the filters are rendered on the front-end. + +### Override the description to prevent infinite loop. ([6849](https://github.com/woocommerce/woocommerce-blocks/pull/6849)) + +1. Make sure you are using a block theme (ie: Twenty Twenty Two). +2. Go to Appearance > Editor > Templates. +3. Click on Add New and select Single Item: Product. +4. Select any product from the list (ie: Hoodie). +5. In the template, add the Hand-picked Products block and select the same product. +6. Visit that product page in the frontend and notice the correct product is selected. + +### Update billing address when shipping address gets change in shipping calculator at Cart block. ([6823](https://github.com/woocommerce/woocommerce-blocks/pull/6823)) + +1. Add a product to the cart and go to the Cart block. +2. Add a new address with a valid zip code in the Shipping calculator, different from what you already used. +3. Click on the Update button and wait for the update. +4. Proceed to Checkout. +5. In the Checkout block, see the new address for shipping being added to the Shipping address. +6. Uncheck the checkbox for `Use same address for billing`. +7. Look at the Billing address form and confirm it has the same address which was selected in the shipping calculator. + +## Feature plugin + +### Fix: Add font-weight controls to the Mini Cart block text. ([6760](https://github.com/woocommerce/woocommerce-blocks/pull/6760)) + +1. Make sure you have a blocks theme active (like Twenty Twenty-Two). +2. Navigate to Appearance > Editor (Beta) and add a Mini Cart block somewhere in your site. +3. In the editor, select the Mini Cart block and, in the block settings, choose Font Weight under the Typography section. +4. Adjust the font weight to something other than the Default. +5. Confirm changes are present in the editor. +6. Save changes and preview the frontend to confirm the changes have persisted. + + + +--- + +[We're hiring!](https://woocommerce.com/careers/) Come work with us! + +🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/internal-developers/testing/releases/830.md) + + + diff --git a/docs/internal-developers/testing/releases/831.md b/docs/internal-developers/testing/releases/831.md new file mode 100644 index 000000000..b2a269d90 --- /dev/null +++ b/docs/internal-developers/testing/releases/831.md @@ -0,0 +1,28 @@ +# Testing notes and ZIP for release 8.3.1 + +Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github.com/woocommerce/woocommerce-blocks/files/9358719/woocommerce-gutenberg-products-block.zip) + +## Feature plugin and package inclusion in WooCommerce + +### Prevent unnecessarily showing the item names in a shipping package if it's the only package. ([6899](https://github.com/woocommerce/woocommerce-blocks/pull/6899)) + +1. Set up shipping zones so you have multiple methods for your country (flat rate and free is fine) and a single method for a different country. +2. Install the ["Multiple Packages for WooCommerce" plugin](https://wordpress.org/plugins/multiple-packages-for-woocommerce/) +3. Navigate to WooCommerce -> Settings -> Multiple Packages +4. Adjust the settings to work based on "Per Product" +5. Add two items that require shipping to your cart. +6. Go to the Cart block. Ensure you see the item name listed under each package. +7. Remove one of the items, ensure the list of shipping options updates and does not include the item name. +8. Change your address to one that only has a single shipping method. Repeat steps 5-7. +9. Repeat 5-7 on the Checkout block too. + + + +--- + +[We're hiring!](https://woocommerce.com/careers/) Come work with us! + +🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/internal-developers/testing/releases/831.md) + + + diff --git a/docs/internal-developers/testing/releases/840.md b/docs/internal-developers/testing/releases/840.md new file mode 100644 index 000000000..26a35ec5f --- /dev/null +++ b/docs/internal-developers/testing/releases/840.md @@ -0,0 +1,139 @@ +# Testing notes and ZIP for release 8.4.0 + +Zip file for testing: [woocommerce-gutenberg-products-block.zip](https://github.com/woocommerce/woocommerce-blocks/files/9444105/woocommerce-gutenberg-products-block.zip) + +## Feature plugin and package inclusion in WooCommerce + +### Update the filter `Apply` buttons to match the new designs. ([6958](https://github.com/woocommerce/woocommerce-blocks/pull/6958)) + +1. Create a new page and add the `All Products` block and the filter pattern containing all filter blocks. +2. Save it and check the buttons look like the `After` screenshot on the editor and the frontend. + +| Before | After | +| ------ | ----- | +| Screenshot 2022-08-22 at 16 03 13 | Screenshot 2022-08-23 at 10 41 03| + +### Update the design of the Filter Products by Attribute block. ([6920](https://github.com/woocommerce/woocommerce-blocks/pull/6920)) + +1. Add the `Filter by Attribute` block to a page. +2. Check that it looks like the new design in the editor and the front-end. +3. Check that the `Reset` button appears when a checkbox is checked. +4. Edit the page and change the Display Style to dropdown. +5. Check that it looks like the new design in the editor and the front-end (it won't look exactly like the design, check [this conversation](p1660817888642199-slack-C02SGH7JBGS) for more context) + +| Before | After | +| ------ | ----- | +| Screenshot 2022-08-19 at 11 36 19 | Screenshot 2022-08-19 at 11 35 10 | +| Screenshot 2022-08-19 at 11 36 41| Screenshot 2022-08-19 at 11 37 15 | +| Screenshot 2022-08-19 at 11 38 01 | Screenshot 2022-08-19 at 11 37 28 | + +### Update the design of the Filter by Attribute block settings panel. ([6912](https://github.com/woocommerce/woocommerce-blocks/pull/6912)) + +1. Add the `Filter by Attribute` block to a page. +2. Check the copy and the design matches with the new design. +3. Check no regression has happened. + +### Terms and conditions, and Privacy policy links open in a new tab by default. ([6908](https://github.com/woocommerce/woocommerce-blocks/pull/6908)) + +1. Insert Checkout page and save the page. +2. On frontend, click on the terms or privacy links in the checkout block. +3. They should open in a new tab. + +### Layout updates to the Active Filters block. ([6905](https://github.com/woocommerce/woocommerce-blocks/pull/6905)) + +1. Add the Active Filters block alongside some other Filters blocks. +2. Apply some filters to the page. +3. Confirm the layout matches the **After** screenshot above. +4. Confirm the **Remove Filter** buttons for each active filter have a hover state of an alternate shade of grey - also confirm they function as expected. + +| Before | After | +| ------ | ----- | +| CleanShot 2022-08-24 at 09 22 27@2x | CleanShot 2022-08-24 at 09 19 27@2x | +| | | +| CleanShot 2022-08-24 at 09 21 47@2x | CleanShot 2022-08-24 at 09 20 16@2x | + +### Update the design of the Filter Products by Stock block. ([6883](https://github.com/woocommerce/woocommerce-blocks/pull/6883)) + +1. Add the Filter by Stock component to a page using the All Products block, and also a block template. +2. Check that the control panel for this block looks like the design (minus Typography) +3. On both the page and the template frontends select a checkbox and observe that it looks as it should do with the design. +4. Check that a "Reset" button appears and clicking this resets the filter again. +5. Now go to your Edit Page & Edit Template pages and enable "'Apply filters' button". +6. On the frontends again, re-select your filter options and check that they are not applied immediately until you click "Apply" +7. Check that when this block is used with the PHP template & the All Products block that regardless of whether the "Apply Filters" button is active, that clicking "Reset" immediately clears the selected filter options + +| Before | After | +| ------ | ----- | +| Screenshot 2022-08-17 at 12 33 57 | Screenshot 2022-08-17 at 12 32 28 | + +### Update the design of the Filter Products by Price block. ([6877](https://github.com/woocommerce/woocommerce-blocks/pull/6877)) + +1. Add `Filter Products by Price` block to a page. +2. Verify that the `Inline input fields` only shows when the `Price Range` is Editable. +3. Toggle Inline input fields, see the block in the editor updates accordingly. +4. Toggle Filter button, see the Reset and Apply button. +5. Add the All Products block then save the page. +6. On the front end, see the new style applied as in the editor. +7. Change the price using the slider then click the Apply button. +8. See the filter works as expected. +9. Click on the Reset button, see the price filter is reset. (Even if the filter button is enabled, clicking on the reset button should reset the filter query). +10. Tested again with PHP templates, ensure no regression. + +image + +### Allow making the Cart/Checkout block page the default one from within the editor. ([6867](https://github.com/woocommerce/woocommerce-blocks/pull/6867)) + +To test this feature you need the latest trunk of WooCommerce, or WooCommerce 6.9.0. For older versions of WC (pre 6.9.0), the notice would show the old text: + +image + +1. Make sure you have a Cart and Checkout pages in WooCommerce -> Settings -> Advanced. +2. Those pages urls can be `/cart` and `/checkout`. +3. Open a new page, give it a title, insert Cart block. +4. Select Cart block, you should see the notice, select an inner block, you should see the notice as well. +5. Click on the notice, it will load for a couple of seconds, once it's green, visit your new page. +6. Make sure it's on the previous url, so `/cart`. +7. Go back to settings, make sure your new page is that value there. +8. Do the same thing for Checkout block. +9. Open a new page, add Cart block, save the page and publish it. +10. Select the block or one of its inner blocks, start the flow again. +11. It should work, confirm that by visiting the frontend. + + + +### Register product search as a core/search variation when available. ([6191](https://github.com/woocommerce/woocommerce-blocks/pull/6191)) + +1. Ensure the Gutenberg version is ≥ 13.4 and it is deactivated. +2. With a block theme (2022 for example), add the Product Search block to the header. +3. See the Product Search is the independent block (as it is in `trunk`), not a variation of the Search block. See the block is editable in the editor and working as expected on the front end. +4. Activate Gutenberg. +5. On the front end, see the block is still working as expected and is still a WC block (notice the classes, and search icon). +6. Edit the header, see the Deprecation notice, and a call to action button to upgrade the search block to search variation. +7. Click on the CTA button to see if the block is converted to WC variation of the core search block. +8. Save and see the block functions flawlessly on the front end. +9. Edit the header again, try adding the Product Search block, only variation is available in the inserter. The legacy can't be found and inserted from the inserter. + + + +### Fixed a bug with a class name deriving from a translatable string. ([6914](https://github.com/woocommerce/woocommerce-blocks/pull/6914)) + +1. Add an item to your cart that has multiple variants. E.g. Hoodie (Blue, Logo) +2. Go to the Cart Block +3. Inspect the text for one of the variants (e.g. Colour: Blue) +4. Make sure there is a class called `wc-block-components-product-details__item` on the `
  • ` element. This should be a child of `