Replace Products (Beta) with Product Collection in product archive templates (#48112)

* Replace Products (Beta) with Product Collection block in blockified template

* Add necessary attributes that influences the look of blocks

* Replace Products (Beta) with Product Collection block in product search results

* Replace Products (Beta) with Product Collection block in products by attribute

* Replace Products (Beta) with Product Collection block in products by category

* Replace Products (Beta) with Product Collection block in products by tag

* Replace Products (Beta) with Product Collection when transforming from classic product archive

* Change the no results content in blockified search results template

* Replace Products (Beta) with Product Collection block in product search results

* Add product search in no results content of blockified product search result

* Add ts-ignore before createBlocksFromInnerBlocksTemplate imports

* Add changelog

* Remove step of replacing Products (Beta) with Product Collection in compatibility layer tests

* Remove step of replacing Products (Beta) with Product Collection in Product Collection tests

* Fix lint

* Update E2E tests of Product Collection

* Adjust Products (Beta) E2E tests

* Add Product Collection focus step in E2E tests

* Improve the way PC block is focused

* Further tests adjustments and new tests comparing classic template with Product Collection

* Bring back the click on body

* Include tips from reviewer

* Enter edit mode, step that I accidentally removde

* Bring the E2E test flow with updating product catalog

* Change the way of removing focus from PC block in tests

* Fix lint

* Improve the layout of search in No Results

* Use previous patterns in Product Search No Results to preserve translations

* Add Search button label in product search form pattern

* Fix lint

* Improve comment explanation

* Extract No Results content to separate pattern in order to make the content translatable

* Lint fix

* Add missing footer to the blockified Products by Tag template

* Exclude woocommerce/patterns from phpcs rules that dont apply there

* Make PC block responsive by default in product archive templates

* Fix typo

* Fix typo

---------

Co-authored-by: Manish Menaria <the.manish.menaria@gmail.com>
This commit is contained in:
Karol Manijak 2024-06-12 15:45:09 +02:00 committed by GitHub
parent 5a4835ea39
commit 635524b481
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 363 additions and 240 deletions

View File

@ -3,13 +3,14 @@
*/
import { useRef, useEffect } from '@wordpress/element';
import { useRegistry, dispatch } from '@wordpress/data';
import { useEditorContext } from '@woocommerce/base-context';
import {
createBlock,
getBlockType,
// @ts-expect-error Type definitions for this function are missing in Gutenberg
createBlocksFromInnerBlocksTemplate,
TemplateArray,
} from '@wordpress/blocks';
import { useEditorContext } from '@woocommerce/base-context';
/**
* Internal dependencies

View File

@ -1,18 +1,20 @@
/**
* External dependencies
*/
import {
createBlock,
createBlocksFromInnerBlocksTemplate,
type BlockInstance,
} from '@wordpress/blocks';
import { isWpVersion } from '@woocommerce/settings';
import { __, sprintf } from '@wordpress/i18n';
import {
INNER_BLOCKS_TEMPLATE as productsInnerBlocksTemplate,
QUERY_DEFAULT_ATTRIBUTES as productsQueryDefaultAttributes,
PRODUCT_QUERY_VARIATION_NAME as productsVariationName,
} from '@woocommerce/blocks/product-query/constants';
INNER_BLOCKS_TEMPLATE as productCollectionInnerBlocksTemplate,
DEFAULT_ATTRIBUTES as productCollectionDefaultAttributes,
DEFAULT_QUERY as productCollectionDefaultQuery,
} from '@woocommerce/blocks/product-collection/constants';
import {
createBlock,
// @ts-expect-error Type definitions for this function are missing in Gutenberg
createBlocksFromInnerBlocksTemplate,
type BlockInstance,
} from '@wordpress/blocks';
/**
* Internal dependencies
@ -20,19 +22,22 @@ import {
import { createArchiveTitleBlock, createRowBlock } from './utils';
import { OnClickCallbackParameter, type InheritedAttributes } from './types';
const createProductsBlock = ( inheritedAttributes: InheritedAttributes ) =>
const createProductCollectionBlock = (
inheritedAttributes: InheritedAttributes
) =>
createBlock(
'core/query',
'woocommerce/product-collection',
{
...productsQueryDefaultAttributes,
...productCollectionDefaultAttributes,
...inheritedAttributes,
namespace: productsVariationName,
query: {
...productsQueryDefaultAttributes.query,
...productCollectionDefaultQuery,
inherit: true,
},
},
createBlocksFromInnerBlocksTemplate( productsInnerBlocksTemplate )
createBlocksFromInnerBlocksTemplate(
productCollectionInnerBlocksTemplate
)
);
const getBlockifiedTemplate = (
@ -53,7 +58,7 @@ const getBlockifiedTemplate = (
],
inheritedAttributes
),
createProductsBlock( inheritedAttributes ),
createProductCollectionBlock( inheritedAttributes ),
].filter( Boolean ) as BlockInstance[];
const getBlockifiedTemplateWithTermDescription = (

View File

@ -1,19 +1,20 @@
/**
* External dependencies
*/
import { isWpVersion } from '@woocommerce/settings';
import { __, sprintf } from '@wordpress/i18n';
import {
INNER_BLOCKS_TEMPLATE as productCollectionInnerBlocksTemplate,
DEFAULT_ATTRIBUTES as productCollectionDefaultAttributes,
DEFAULT_QUERY as productCollectionDefaultQuery,
} from '@woocommerce/blocks/product-collection/constants';
import {
createBlock,
// @ts-expect-error Type definitions for this function are missing in Guteberg
createBlocksFromInnerBlocksTemplate,
type BlockInstance,
type InnerBlockTemplate,
} from '@wordpress/blocks';
import { isWpVersion } from '@woocommerce/settings';
import { __, sprintf } from '@wordpress/i18n';
import {
INNER_BLOCKS_TEMPLATE as productsInnerBlocksTemplate,
QUERY_DEFAULT_ATTRIBUTES as productsQueryDefaultAttributes,
PRODUCT_QUERY_VARIATION_NAME as productsVariationName,
} from '@woocommerce/blocks/product-query/constants';
/**
* Internal dependencies
@ -43,18 +44,23 @@ const extendInnerBlocksWithNoResultsContent = (
innerBlocks: InnerBlockTemplate[],
inheritedAttributes: InheritedAttributes
) => {
// InnerBlockTemplate is an array block representation so properties
// like name or attributes need to be accessed with array indexes.
const nameArrayIndex = 0;
const attributesArrayIndex = 1;
const noResultsContent = [
createNoResultsParagraph(),
createProductSearch(),
];
const noResultsBlockName = 'core/query-no-results';
const noResultsBlockName = 'woocommerce/product-collection-no-results';
const noResultsBlockIndex = innerBlocks.findIndex(
( block ) => block[ 0 ] === noResultsBlockName
( block ) => block[ nameArrayIndex ] === noResultsBlockName
);
const noResultsBlock = innerBlocks[ noResultsBlockIndex ];
const attributes = {
...( noResultsBlock[ 1 ] || {} ),
...( noResultsBlock[ attributesArrayIndex ] || {} ),
...inheritedAttributes,
};
@ -65,31 +71,34 @@ const extendInnerBlocksWithNoResultsContent = (
];
return [
...productsInnerBlocksTemplate.slice( 0, noResultsBlockIndex ),
...innerBlocks.slice( 0, noResultsBlockIndex ),
extendedNoResults,
...productsInnerBlocksTemplate.slice( noResultsBlockIndex + 1 ),
...innerBlocks.slice( noResultsBlockIndex + 1 ),
];
};
const createProductsBlock = ( inheritedAttributes: InheritedAttributes ) => {
const productsInnerBlocksWithNoResults =
const createProductCollectionBlock = (
inheritedAttributes: InheritedAttributes
) => {
const productCollectionInnerBlocksWithNoResults =
extendInnerBlocksWithNoResultsContent(
productsInnerBlocksTemplate,
productCollectionInnerBlocksTemplate,
inheritedAttributes
);
return createBlock(
'core/query',
'woocommerce/product-collection',
{
...productsQueryDefaultAttributes,
...productCollectionDefaultAttributes,
...inheritedAttributes,
namespace: productsVariationName,
query: {
...productsQueryDefaultAttributes.query,
...productCollectionDefaultQuery,
inherit: true,
},
},
createBlocksFromInnerBlocksTemplate( productsInnerBlocksWithNoResults )
createBlocksFromInnerBlocksTemplate(
productCollectionInnerBlocksWithNoResults
)
);
};
@ -104,7 +113,7 @@ const getBlockifiedTemplate = ( inheritedAttributes: InheritedAttributes ) =>
],
inheritedAttributes
),
createProductsBlock( inheritedAttributes ),
createProductCollectionBlock( inheritedAttributes ),
].filter( Boolean ) as BlockInstance[];
const isConversionPossible = () => {

View File

@ -6,7 +6,7 @@ import { objectOmit } from '@woocommerce/utils';
import {
type InnerBlockTemplate,
createBlock,
// @ts-expect-error Missing types in Gutenberg
// @ts-expect-error Type definitions for this function are missing in Guteberg
createBlocksFromInnerBlocksTemplate,
} from '@wordpress/blocks';

View File

@ -92,10 +92,6 @@ test.describe( 'Compatibility Layer with Product Collection block', () => {
await requestUtils.activatePlugin(
'woocommerce-blocks-test-product-collection-compatibility-layer'
);
await pageObject.replaceProductsWithProductCollectionInTemplate(
'woocommerce/woocommerce//archive-product'
);
await pageObject.goToProductCatalogFrontend();
} );

View File

@ -118,9 +118,7 @@ test.describe( 'Product Collection', () => {
editor,
pageObject,
} ) => {
await pageObject.replaceProductsWithProductCollectionInTemplate(
'woocommerce/woocommerce//archive-product'
);
await pageObject.goToEditorTemplate();
await expect(
editor.canvas.locator( '[data-testid="product-image"]:visible' )
@ -460,7 +458,8 @@ test.describe( 'Product Collection', () => {
pageObject,
editor,
} ) => {
await pageObject.goToProductCatalogAndInsertCollection();
await pageObject.goToEditorTemplate();
await pageObject.focusProductCollection();
await editor.openDocumentSettingsSidebar();
const sidebarSettings =
@ -516,7 +515,8 @@ test.describe( 'Product Collection', () => {
} ) => {
// First Product Catalog
// Option should be visible & ENABLED by default
await pageObject.goToProductCatalogAndInsertCollection();
await pageObject.goToEditorTemplate();
await pageObject.focusProductCollection();
await editor.openDocumentSettingsSidebar();
const sidebarSettings =
@ -788,10 +788,18 @@ test.describe( 'Product Collection', () => {
test( 'Product Catalog Collection can be added in product archive and syncs query with template', async ( {
pageObject,
editor,
admin,
} ) => {
await pageObject.goToProductCatalogAndInsertCollection(
'productCatalog'
);
await admin.visitSiteEditor( {
postId: 'woocommerce/woocommerce//archive-product',
postType: 'wp_template',
} );
await editor.enterEditMode();
await editor.setContent( '' );
await pageObject.insertProductCollection();
await pageObject.chooseCollectionInTemplate();
await editor.openDocumentSettingsSidebar();
const sidebarSettings = await pageObject.locateSidebarSettings();
@ -1132,14 +1140,9 @@ test.describe( 'Product Collection', () => {
];
genericArchiveTemplates.forEach( ( { name, path } ) => {
test( `${ name } template`, async ( {
editor,
page,
pageObject,
} ) => {
await pageObject.replaceProductsWithProductCollectionInTemplate(
path
);
test( `${ name } template`, async ( { editor, pageObject } ) => {
await pageObject.goToEditorTemplate( path );
await pageObject.focusProductCollection();
const previewButtonLocator = editor.canvas.locator(
'button[data-test-id="product-collection-preview-button"]'
@ -1148,8 +1151,12 @@ test.describe( 'Product Collection', () => {
// The preview button should be visible
await expect( previewButtonLocator ).toBeVisible();
// The preview button should be hidden when the block is not selected
await page.click( 'body' );
// The preview button should be hidden when the block is not selected.
// Changing focus.
const otherBlockSelector = editor.canvas.getByLabel(
'Block: Archive Title'
);
await editor.selectBlocks( otherBlockSelector );
await expect( previewButtonLocator ).toBeHidden();
// Preview button should be visible when any of inner block is selected
@ -1169,9 +1176,7 @@ test.describe( 'Product Collection', () => {
editor,
pageObject,
} ) => {
await pageObject.replaceProductsWithProductCollectionInTemplate(
'woocommerce/woocommerce//archive-product'
);
await pageObject.goToEditorTemplate();
const productTemplate = editor.canvas.getByLabel(
BLOCK_LABELS.productTemplate
);
@ -1204,7 +1209,9 @@ test.describe( 'Product Collection', () => {
pageObject,
editor,
} ) => {
await pageObject.goToProductCatalogAndInsertCollection( 'onSale' );
await pageObject.goToEditorTemplate();
await pageObject.insertProductCollection();
await pageObject.chooseCollectionInTemplate( 'onSale' );
const productTemplate = editor.canvas.getByLabel(
BLOCK_LABELS.productTemplate
@ -1235,4 +1242,87 @@ test.describe( 'Product Collection', () => {
await expect( productTemplate ).toBeVisible();
} );
} );
const templates = {
// This test is disabled because archives are disabled for attributes by default. This can be uncommented when this is toggled on.
//'taxonomy-product_attribute': {
// templateTitle: 'Product Attribute',
// slug: 'taxonomy-product_attribute',
// frontendPage: '/product-attribute/color/',
// legacyBlockName: 'woocommerce/legacy-template',
//},
'taxonomy-product_cat': {
templateTitle: 'Product Category',
slug: 'taxonomy-product_cat',
frontendPage: '/product-category/music/',
legacyBlockName: 'woocommerce/legacy-template',
expectedProductsCount: 2,
},
'taxonomy-product_tag': {
templateTitle: 'Product Tag',
slug: 'taxonomy-product_tag',
frontendPage: '/product-tag/recommended/',
legacyBlockName: 'woocommerce/legacy-template',
expectedProductsCount: 2,
},
'archive-product': {
templateTitle: 'Product Catalog',
slug: 'archive-product',
frontendPage: '/shop/',
legacyBlockName: 'woocommerce/legacy-template',
expectedProductsCount: 16,
},
'product-search-results': {
templateTitle: 'Product Search Results',
slug: 'product-search-results',
frontendPage: '/?s=shirt&post_type=product',
legacyBlockName: 'woocommerce/legacy-template',
expectedProductsCount: 3,
},
};
for ( const {
templateTitle,
slug,
frontendPage,
legacyBlockName,
expectedProductsCount,
} of Object.values( templates ) ) {
test.describe( `${ templateTitle } template`, () => {
test( 'Product Collection block matches with classic template block', async ( {
pageObject,
admin,
editor,
page,
} ) => {
const getProductNamesFromClassicTemplate = async () => {
const products = page.locator(
'.woocommerce-loop-product__title'
);
await expect( products ).toHaveCount(
expectedProductsCount
);
return products.allTextContents();
};
await admin.visitSiteEditor( {
postId: `woocommerce/woocommerce//${ slug }`,
postType: 'wp_template',
} );
await editor.enterEditMode();
await editor.insertBlock( { name: legacyBlockName } );
await editor.canvas.locator( 'body' ).click();
await editor.saveSiteEditorEntities();
await page.goto( frontendPage );
await pageObject.refreshLocators( 'frontend' );
const classicProducts =
await getProductNamesFromClassicTemplate();
const productCollectionProducts =
await pageObject.getProductNames();
expect( classicProducts ).toEqual( productCollectionProducts );
} );
} );
}
} );

View File

@ -2,7 +2,7 @@
* External dependencies
*/
import { Locator, Page } from '@playwright/test';
import { Editor, Admin, expect } from '@woocommerce/e2e-utils';
import { Editor, Admin } from '@woocommerce/e2e-utils';
import { BlockRepresentation } from '@wordpress/e2e-test-utils-playwright/build-types/editor/insert-block';
/**
@ -194,25 +194,16 @@ class ProductCollectionPage {
);
}
async replaceProductsWithProductCollectionInTemplate(
template: string,
collection?: Collections
// Going to Product Catalog by default
async goToEditorTemplate(
template = 'woocommerce/woocommerce//archive-product'
) {
await this.admin.visitSiteEditor( {
postId: template,
postType: 'wp_template',
} );
await this.editor.enterEditMode();
await expect(
this.editor.canvas.locator( `[data-type="core/query"]` )
).toBeVisible();
await this.replaceBlockByBlockName( 'core/query', this.BLOCK_SLUG );
await this.chooseCollectionInTemplate( collection );
await this.refreshLocators( 'editor' );
await this.editor.saveSiteEditorEntities();
}
async goToProductCatalogFrontend() {
@ -251,13 +242,6 @@ class ProductCollectionPage {
);
}
async goToProductCatalogAndInsertCollection( collection?: Collections ) {
await this.goToTemplateAndInsertCollection(
'woocommerce/woocommerce//archive-product',
collection
);
}
async searchProducts( phrase: string ) {
await this.page
.getByLabel( SELECTORS.productSearchLabel )
@ -450,13 +434,24 @@ class ProductCollectionPage {
await this.refreshLocators( 'editor' );
}
async focusProductCollection() {
const editorSelector = this.editor.canvas
.getByLabel( 'Block: Product Collection', { exact: true } )
.first();
const postSelector = this.page
.getByLabel( 'Block: Product Collection', { exact: true } )
.first();
await Promise.any( [
this.editor.selectBlocks( editorSelector ),
this.editor.selectBlocks( postSelector ),
] );
}
async clickDisplaySettings() {
// Select the block, so that toolbar is visible.
const block = this.page
.locator( `[data-type="${ this.BLOCK_SLUG }"]` )
.first();
await this.editor.selectBlocks( block );
await this.focusProductCollection();
// Open the display settings.
await this.page
.getByRole( 'button', { name: 'Display settings' } )
@ -606,6 +601,11 @@ class ProductCollectionPage {
return this.page.getByRole( 'heading' );
}
async getProductNames() {
const products = this.page.locator( '.wp-block-post-title' );
return products.allTextContents();
}
/**
* Private methods to be used by the class.
*/

View File

@ -9,6 +9,7 @@ import { test, expect, BlockData } from '@woocommerce/e2e-utils';
import {
getProductsNameFromClassicTemplate,
getProductsNameFromProductQuery,
insertProductsQuery,
} from './utils';
const blockData: BlockData = {
@ -35,12 +36,12 @@ const templates = {
frontendPage: '/product-category/music/',
legacyBlockName: 'woocommerce/legacy-template',
},
// We don't have products with tags in the test site. Uncomment this when we have products with tags.
// 'taxonomy-product_tag': {
// templateTitle: 'Product Tag',
// slug: 'taxonomy-product_tag',
// frontendPage: '/product-tag/hoodie/',
// },
'taxonomy-product_tag': {
templateTitle: 'Product Tag',
slug: 'taxonomy-product_tag',
frontendPage: '/product-tag/recommended/',
legacyBlockName: 'woocommerce/legacy-template',
},
'archive-product': {
templateTitle: 'Product Catalog',
slug: 'archive-product',
@ -56,7 +57,7 @@ const templates = {
};
test.describe( `${ blockData.name } Block `, () => {
test( 'when Inherit Query from template is enabled all the settings that customize the query should be hidden', async ( {
test( 'when Inherits Query From Template other options are hidden, show up otherwise', async ( {
admin,
editor,
page,
@ -65,14 +66,12 @@ test.describe( `${ blockData.name } Block `, () => {
postId: 'woocommerce/woocommerce//archive-product',
postType: 'wp_template',
} );
await editor.canvas.locator( 'body' ).click();
await editor.enterEditMode();
await editor.setContent( '' );
await insertProductsQuery( editor );
const block = await editor.getBlockByName( blockData.name );
await editor.selectBlocks( block );
await editor.openDocumentSettingsSidebar();
const advancedFilterOption = page.getByLabel(
'Advanced Filters options'
);
@ -82,30 +81,6 @@ test.describe( `${ blockData.name } Block `, () => {
await expect( advancedFilterOption ).toBeHidden();
await expect( inheritQueryFromTemplateOption ).toBeVisible();
} );
test( 'when Inherit Query from template is disabled all the settings that customize the query should be visble', async ( {
admin,
editor,
page,
} ) => {
await admin.visitSiteEditor( {
postId: 'woocommerce/woocommerce//archive-product',
postType: 'wp_template',
} );
await editor.canvas.locator( 'body' ).click();
const block = await editor.getBlockByName( blockData.name );
await editor.selectBlocks( block );
await editor.openDocumentSettingsSidebar();
const advancedFilterOption = page.getByLabel(
'Advanced Filters options'
);
const inheritQueryFromTemplateOption = page.getByLabel(
'Inherit query from template'
);
await inheritQueryFromTemplateOption.click();
@ -130,17 +105,11 @@ for ( const {
postId: `woocommerce/woocommerce//${ slug }`,
postType: 'wp_template',
} );
await editor.enterEditMode();
await editor.setContent( '' );
await insertProductsQuery( editor );
await editor.insertBlock( { name: legacyBlockName } );
await editor.canvas.locator( 'body' ).click();
const block = await editor.getBlockByName( blockData.name );
const clientId = ( await block.getAttribute( 'data-block' ) ) ?? '';
const parentClientId =
( await editor.getBlockRootClientId( clientId ) ) ?? '';
await editor.selectBlocks( block );
await editor.insertBlock(
{ name: legacyBlockName },
{ clientId: parentClientId }
);
await editor.saveSiteEditorEntities();

View File

@ -1,7 +1,8 @@
/**
* External dependencies
*/
import { Page } from '@playwright/test';
import type { Page } from '@playwright/test';
import type { Editor } from '@woocommerce/e2e-utils';
export const getProductsNameFromClassicTemplate = async ( page: Page ) => {
const products = page.locator( '.woocommerce-loop-product__title' );
@ -12,3 +13,40 @@ export const getProductsNameFromProductQuery = async ( page: Page ) => {
const products = page.locator( '.wp-block-query .wp-block-post-title' );
return products.allTextContents();
};
export const productQueryInnerBlocksTemplate = [
{
name: 'core/post-template',
attributes: {
__woocommerceNamespace:
'woocommerce/product-query/product-template',
},
innerBlocks: [
{ name: 'woocommerce/product-image' },
{
name: 'core/post-title',
attributes: {
__woocommerceNamespace:
'woocommerce/product-query/product-title',
},
},
{ name: 'woocommerce/product-price' },
{ name: 'woocommerce/product-button' },
],
},
{ name: 'core/query-pagination' },
{ name: 'core/query-no-results' },
];
export const insertProductsQuery = async ( editor: Editor ) => {
await editor.insertBlock( {
name: 'core/query',
attributes: {
namespace: 'woocommerce/product-query',
query: {
inherit: true,
},
},
innerBlocks: productQueryInnerBlocksTemplate,
} );
};

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Product Archive templates: Replace the default block from Products (Beta) to Product Collection block

View File

@ -0,0 +1,14 @@
<?php
/**
* Title: No Products Found - Clear Filters
* Slug: woocommerce/no-products-found-clear-filters
* Inserter: no
* Categories: WooCommerce
*/
?>
<!-- wp:paragraph {"fontSize":"medium"} -->
<p class="has-medium-font-size"><strong><?php echo esc_html_x( 'No results found', 'Message explaining that there are no products found', 'woocommerce' ); ?></strong></p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p><?php echo esc_html_x( 'You can try', 'Used in sentence: You can try clearing any filters or head to our store\'s home.', 'woocommerce' ); ?> <a class="wc-link-clear-any-filters" href="#"><?php echo esc_html_x( 'clearing any filters', 'Used in sentence: You can try clearing any filters or head to our store\'s home.', 'woocommerce' ); ?></a> <?php echo esc_html_x( 'or head to our', 'Used in sentence: You can try clearing any filters or head to our store\'s home.', 'woocommerce' ); ?> <a class="wc-link-stores-home" href="#"><?php echo esc_html_x( 'store\'s home', 'Used in sentence: You can try clearing any filters or head to our store\'s home.', 'woocommerce' ); ?></a></p>
<!-- /wp:paragraph -->

View File

@ -6,4 +6,5 @@
* Categories: WooCommerce
*/
?>
<!-- wp:search {"showLabel":false,"placeholder":"<?php echo esc_attr_x( 'Search products…', 'placeholder for search field', 'woocommerce' ); ?>","query":{"post_type":"product"}} /-->
<!-- wp:search {"showLabel":false,"placeholder":"<?php echo esc_attr_x( 'Search products…', 'placeholder for search field', 'woocommerce' ); ?>","buttonText":"<?php echo esc_attr_x( 'Search', 'button label of product search block', 'woocommerce' ); ?>","query":{"post_type":"product"}} /-->

View File

@ -114,6 +114,10 @@
<rule ref="Squiz.Commenting.FileComment.MissingPackageTag">
<exclude-pattern>src/</exclude-pattern>
<exclude-pattern>tests/php/</exclude-pattern>
<exclude-pattern>patterns</exclude-pattern>
</rule>
<rule ref="Squiz.Commenting.FileComment.SpacingAfterComment">
<exclude-pattern>patterns</exclude-pattern>
</rule>
<rule ref="Squiz.Commenting.FileComment.Missing">
<exclude-pattern>src/</exclude-pattern>

View File

@ -16,26 +16,29 @@
<!-- wp:woocommerce/catalog-sorting /-->
</div>
<!-- /wp:group -->
<!-- wp:query {"queryId":0,"query":{"perPage":9,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","author":"","search":"","exclude":[],"sticky":"","inherit":true,"__woocommerceAttributes":[],"__woocommerceStockStatus":["instock","outofstock","onbackorder"]},"displayLayout":{"type":"flex","columns":3},"namespace":"woocommerce/product-query","align":"wide"} -->
<div class="wp-block-query alignwide">
<!-- wp:post-template {"className":"products-block-post-template","__woocommerceNamespace":"woocommerce/product-query/product-template"} -->
<!-- wp:woocommerce/product-image {"isDescendentOfQueryLoop":true, "imageSizing":"thumbnail"} /-->
<!-- wp:post-title {"textAlign":"center","level":3,"fontSize":"medium","isLink":true,"__woocommerceNamespace":"woocommerce/product-query/product-title"} /-->
<!-- wp:woocommerce/product-price {"isDescendentOfQueryLoop":true,"textAlign":"center","fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- wp:woocommerce/product-button {"isDescendentOfQueryLoop":true,"textAlign":"center","fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- /wp:post-template -->
<!-- wp:woocommerce/product-collection {"query":{"woocommerceAttributes":[],"woocommerceStockStatus":["instock","outofstock","onbackorder"],"taxQuery":{},"isProductCollectionBlock":true,"perPage":10,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","author":"","search":"","exclude":[],"sticky":"","inherit":true},"tagName":"div","displayLayout":{"type":"flex","columns":3,"shrinkColumns":true},"convertedFromProducts":false,"queryContextIncludes":["collection"],"align":"wide"} -->
<div class="wp-block-woocommerce-product-collection alignwide">
<!-- wp:woocommerce/product-template -->
<!-- wp:woocommerce/product-image {"imageSizing":"thumbnail","isDescendentOfQueryLoop":true} /-->
<!-- wp:post-title {"textAlign":"center","level":3,"isLink":true,"fontSize":"medium","__woocommerceNamespace":"woocommerce/product-collection/product-title"} /-->
<!-- wp:woocommerce/product-price {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- wp:woocommerce/product-button {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- /wp:woocommerce/product-template -->
<!-- wp:query-pagination {"layout":{"type":"flex","justifyContent":"center"}} -->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- /wp:query-pagination -->
<!-- wp:query-no-results -->
<!-- wp:pattern {"slug":"woocommerce/no-products-found"} /-->
<!-- /wp:query-no-results -->
</div>
<!-- /wp:query -->
<!-- wp:woocommerce/product-collection-no-results -->
<!-- wp:group {"layout":{"type":"flex","orientation":"vertical","justifyContent":"center","flexWrap":"wrap"}} -->
<div class="wp-block-group">
<!-- wp:pattern {"slug":"woocommerce/no-products-found-clear-filters"} /-->
</div>
<!-- /wp:group -->
<!-- /wp:woocommerce/product-collection-no-results --></div>
<!-- /wp:woocommerce/product-collection -->
</main>
<!-- /wp:group -->

View File

@ -14,27 +14,26 @@
<!-- wp:woocommerce/catalog-sorting /-->
</div>
<!-- /wp:group -->
<!-- wp:query {"queryId":0,"query":{"perPage":9,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","author":"","search":"","exclude":[],"sticky":"","inherit":true,"__woocommerceAttributes":[],"__woocommerceStockStatus":["instock","outofstock","onbackorder"]},"displayLayout":{"type":"flex","columns":3},"namespace":"woocommerce/product-query","align":"wide"} -->
<div class="wp-block-query alignwide">
<!-- wp:post-template {"className":"products-block-post-template","__woocommerceNamespace":"woocommerce/product-query/product-template"} -->
<!-- wp:woocommerce/product-image {"isDescendentOfQueryLoop":true, "imageSizing":"thumbnail"} /-->
<!-- wp:post-title {"textAlign":"center","level":3,"fontSize":"medium","isLink":true,"__woocommerceNamespace":"woocommerce/product-query/product-title"} /-->
<!-- wp:woocommerce/product-price {"isDescendentOfQueryLoop":true,"textAlign":"center","fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- wp:woocommerce/product-button {"isDescendentOfQueryLoop":true,"textAlign":"center","fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- /wp:post-template -->
<!-- wp:woocommerce/product-collection {"query":{"woocommerceAttributes":[],"woocommerceStockStatus":["instock","outofstock","onbackorder"],"taxQuery":{},"isProductCollectionBlock":true,"perPage":10,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","author":"","search":"","exclude":[],"sticky":"","inherit":true},"tagName":"div","displayLayout":{"type":"flex","columns":3,"shrinkColumns":true},"convertedFromProducts":false,"queryContextIncludes":["collection"],"align":"wide"} -->
<div class="wp-block-woocommerce-product-collection alignwide">
<!-- wp:woocommerce/product-template -->
<!-- wp:woocommerce/product-image {"imageSizing":"thumbnail","isDescendentOfQueryLoop":true} /-->
<!-- wp:post-title {"textAlign":"center","level":3,"isLink":true,"fontSize":"medium","__woocommerceNamespace":"woocommerce/product-collection/product-title"} /-->
<!-- wp:woocommerce/product-price {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- wp:woocommerce/product-button {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- /wp:woocommerce/product-template -->
<!-- wp:query-pagination {"layout":{"type":"flex","justifyContent":"center"}} -->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- /wp:query-pagination -->
<!-- wp:query-no-results -->
<!-- wp:pattern {"slug":"woocommerce/no-products-found"} /-->
<!-- wp:pattern {"slug":"woocommerce/product-search-form"} /-->
<!-- /wp:query-no-results -->
</div>
<!-- /wp:query -->
<!-- wp:woocommerce/product-collection-no-results {"align":"wide"} -->
<!-- wp:pattern {"slug":"woocommerce/no-products-found"} /-->
<!-- wp:pattern {"slug":"woocommerce/product-search-form"} /-->
<!-- /wp:woocommerce/product-collection-no-results --></div>
<!-- /wp:woocommerce/product-collection -->
</main>
<!-- /wp:group -->

View File

@ -16,33 +16,29 @@
</div>
<!-- /wp:group -->
<!-- wp:query {"queryId":0,"query":{"perPage":9,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","author":"","search":"","exclude":[],"sticky":"","inherit":true,"__woocommerceAttributes":[],"__woocommerceStockStatus":["instock","outofstock","onbackorder"]},"displayLayout":{"type":"flex","columns":3},"namespace":"woocommerce/product-query","align":"wide"} -->
<div class="wp-block-query alignwide">
<!-- wp:post-template {"className":"products-block-post-template","__woocommerceNamespace":"woocommerce/product-query/product-template"} -->
<!-- wp:woocommerce/product-image {"imageSizing":"thumbnail","isDescendentOfQueryLoop":true} /-->
<!-- wp:post-title {"textAlign":"center","level":3,"isLink":true,"style":{"spacing":{"margin":{"bottom":"0.75rem","top":"0"}}},"fontSize":"medium","__woocommerceNamespace":"woocommerce/product-query/product-title"} /-->
<!-- wp:woocommerce/product-price {"isDescendentOfQueryLoop":true,"textAlign":"center","fontSize":"small"} /-->
<!-- wp:woocommerce/product-button {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small"} /-->
<!-- /wp:post-template -->
<!-- wp:woocommerce/product-collection {"query":{"woocommerceAttributes":[],"woocommerceStockStatus":["instock","outofstock","onbackorder"],"taxQuery":{},"isProductCollectionBlock":true,"perPage":10,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","author":"","search":"","exclude":[],"sticky":"","inherit":true},"tagName":"div","displayLayout":{"type":"flex","columns":3,"shrinkColumns":true},"convertedFromProducts":false,"queryContextIncludes":["collection"],"align":"wide"} -->
<div class="wp-block-woocommerce-product-collection alignwide">
<!-- wp:woocommerce/product-template -->
<!-- wp:woocommerce/product-image {"imageSizing":"thumbnail","isDescendentOfQueryLoop":true} /-->
<!-- wp:post-title {"textAlign":"center","level":3,"isLink":true,"fontSize":"medium","__woocommerceNamespace":"woocommerce/product-collection/product-title"} /-->
<!-- wp:woocommerce/product-price {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- wp:woocommerce/product-button {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- /wp:woocommerce/product-template -->
<!-- wp:query-pagination {"layout":{"type":"flex","justifyContent":"center"}} -->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- /wp:query-pagination -->
<!-- wp:query-no-results -->
<!-- wp:paragraph {"placeholder":"Add text or blocks that will display when a query returns no results."} -->
<p></p>
<!-- /wp:paragraph -->
<!-- /wp:query-no-results -->
</div>
<!-- /wp:query -->
<!-- wp:woocommerce/product-collection-no-results -->
<!-- wp:group {"layout":{"type":"flex","orientation":"vertical","justifyContent":"center","flexWrap":"wrap"}} -->
<div class="wp-block-group">
<!-- wp:pattern {"slug":"woocommerce/no-products-found-clear-filters"} /-->
</div>
<!-- /wp:group -->
<!-- /wp:woocommerce/product-collection-no-results --></div>
<!-- /wp:woocommerce/product-collection -->
</main>
<!-- /wp:group -->

View File

@ -16,33 +16,29 @@
</div>
<!-- /wp:group -->
<!-- wp:query {"queryId":0,"query":{"perPage":9,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","author":"","search":"","exclude":[],"sticky":"","inherit":true,"__woocommerceAttributes":[],"__woocommerceStockStatus":["instock","outofstock","onbackorder"]},"displayLayout":{"type":"flex","columns":3},"namespace":"woocommerce/product-query","align":"wide"} -->
<div class="wp-block-query alignwide">
<!-- wp:post-template {"className":"products-block-post-template","__woocommerceNamespace":"woocommerce/product-query/product-template"} -->
<!-- wp:woocommerce/product-image {"imageSizing":"thumbnail","isDescendentOfQueryLoop":true} /-->
<!-- wp:post-title {"textAlign":"center","level":3,"isLink":true,"style":{"spacing":{"margin":{"bottom":"0.75rem","top":"0"}}},"fontSize":"medium","__woocommerceNamespace":"woocommerce/product-query/product-title"} /-->
<!-- wp:woocommerce/product-price {"isDescendentOfQueryLoop":true,"textAlign":"center","fontSize":"small"} /-->
<!-- wp:woocommerce/product-button {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small"} /-->
<!-- /wp:post-template -->
<!-- wp:woocommerce/product-collection {"query":{"woocommerceAttributes":[],"woocommerceStockStatus":["instock","outofstock","onbackorder"],"taxQuery":{},"isProductCollectionBlock":true,"perPage":10,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","author":"","search":"","exclude":[],"sticky":"","inherit":true},"tagName":"div","displayLayout":{"type":"flex","columns":3,"shrinkColumns":true},"convertedFromProducts":false,"queryContextIncludes":["collection"],"align":"wide"} -->
<div class="wp-block-woocommerce-product-collection alignwide">
<!-- wp:woocommerce/product-template -->
<!-- wp:woocommerce/product-image {"imageSizing":"thumbnail","isDescendentOfQueryLoop":true} /-->
<!-- wp:post-title {"textAlign":"center","level":3,"isLink":true,"fontSize":"medium","__woocommerceNamespace":"woocommerce/product-collection/product-title"} /-->
<!-- wp:woocommerce/product-price {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- wp:woocommerce/product-button {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- /wp:woocommerce/product-template -->
<!-- wp:query-pagination {"layout":{"type":"flex","justifyContent":"center"}} -->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- /wp:query-pagination -->
<!-- wp:query-no-results -->
<!-- wp:paragraph {"placeholder":"Add text or blocks that will display when a query returns no results."} -->
<p></p>
<!-- /wp:paragraph -->
<!-- /wp:query-no-results -->
</div>
<!-- /wp:query -->
<!-- wp:woocommerce/product-collection-no-results -->
<!-- wp:group {"layout":{"type":"flex","orientation":"vertical","justifyContent":"center","flexWrap":"wrap"}} -->
<div class="wp-block-group">
<!-- wp:pattern {"slug":"woocommerce/no-products-found-clear-filters"} /-->
</div>
<!-- /wp:group -->
<!-- /wp:woocommerce/product-collection-no-results --></div>
<!-- /wp:woocommerce/product-collection -->
</main>
<!-- /wp:group -->

View File

@ -16,31 +16,29 @@
</div>
<!-- /wp:group -->
<!-- wp:query {"queryId":0,"query":{"perPage":9,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","author":"","search":"","exclude":[],"sticky":"","inherit":true,"__woocommerceAttributes":[],"__woocommerceStockStatus":["instock","outofstock","onbackorder"]},"displayLayout":{"type":"flex","columns":3},"namespace":"woocommerce/product-query","align":"wide"} -->
<div class="wp-block-query alignwide">
<!-- wp:post-template {"className":"products-block-post-template","__woocommerceNamespace":"woocommerce/product-query/product-template"} -->
<!-- wp:woocommerce/product-image {"imageSizing":"thumbnail","isDescendentOfQueryLoop":true} /-->
<!-- wp:post-title {"textAlign":"center","level":3,"isLink":true,"style":{"spacing":{"margin":{"bottom":"0.75rem","top":"0"}}},"fontSize":"medium","__woocommerceNamespace":"woocommerce/product-query/product-title"} /-->
<!-- wp:woocommerce/product-price {"isDescendentOfQueryLoop":true,"textAlign":"center","fontSize":"small"} /-->
<!-- wp:woocommerce/product-button {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small"} /-->
<!-- /wp:post-template -->
<!-- wp:woocommerce/product-collection {"query":{"woocommerceAttributes":[],"woocommerceStockStatus":["instock","outofstock","onbackorder"],"taxQuery":{},"isProductCollectionBlock":true,"perPage":10,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","author":"","search":"","exclude":[],"sticky":"","inherit":true},"tagName":"div","displayLayout":{"type":"flex","columns":3,"shrinkColumns":true},"convertedFromProducts":false,"queryContextIncludes":["collection"],"align":"wide"} -->
<div class="wp-block-woocommerce-product-collection alignwide">
<!-- wp:woocommerce/product-template -->
<!-- wp:woocommerce/product-image {"imageSizing":"thumbnail","isDescendentOfQueryLoop":true} /-->
<!-- wp:post-title {"textAlign":"center","level":3,"isLink":true,"fontSize":"medium","__woocommerceNamespace":"woocommerce/product-collection/product-title"} /-->
<!-- wp:woocommerce/product-price {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- wp:woocommerce/product-button {"textAlign":"center","isDescendentOfQueryLoop":true,"fontSize":"small","style":{"spacing":{"margin":{"bottom":"1rem"}}}} /-->
<!-- /wp:woocommerce/product-template -->
<!-- wp:query-pagination {"layout":{"type":"flex","justifyContent":"center"}} -->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- /wp:query-pagination -->
<!-- wp:query-no-results -->
<!-- wp:paragraph {"placeholder":"Add text or blocks that will display when a query returns no results."} -->
<p></p>
<!-- /wp:paragraph -->
<!-- /wp:query-no-results -->
</div>
<!-- /wp:query -->
<!-- wp:woocommerce/product-collection-no-results -->
<!-- wp:group {"layout":{"type":"flex","orientation":"vertical","justifyContent":"center","flexWrap":"wrap"}} -->
<div class="wp-block-group">
<!-- wp:pattern {"slug":"woocommerce/no-products-found-clear-filters"} /-->
</div>
<!-- /wp:group -->
<!-- /wp:woocommerce/product-collection-no-results --></div>
<!-- /wp:woocommerce/product-collection -->
</main>
<!-- wp:template-part {"slug":"footer"} /-->