Product Collection: add control to toggle whether block is filterable in non archive context (#49627)

* Add syncWithFilters attribute to Product Collection

* Add SycnWithFilters Inspector Control to PC

* Minor import adjustments

* Move the controls to Inherit as they share the same labels

* Rename the attirbute to filterable

* Hide control for collections

* Consume the filterable

* Consume filterable attribute so it enables the filtering

* Bring back file format

* Bring back filterable

* Move filterable from attribute to query

* Improve checks

* Fix incorrent function name

* Add changelog

* Set the default filterable value on insert

* Update test selector

* Add E2E tests to #49627 (#49715)

* Remove unnecessary call to create new post

* Fix "Use page context" control tests

* Fix post ↔ template collection sync test

* Fix non-thenable linter errors

* Extend the "Use page context" default setting test

* Add test for filtering in non-archive context

* Add test for combining editor and front-end filters

* Fix lint

* Update plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/inspector-controls/inherit-query-control.tsx

Co-authored-by: Manish Menaria <the.manish.menaria@gmail.com>

* Improve query properties access

* Rename inherit-query-control to use-page-context-control to better depict its purpose

* Lint fix

---------

Co-authored-by: Bart Kalisz <bartlomiej.kalisz@gmail.com>
Co-authored-by: Manish Menaria <the.manish.menaria@gmail.com>
This commit is contained in:
Karol Manijak 2024-07-24 11:51:53 +02:00 committed by GitHub
parent e6d3890bdd
commit dace7ba296
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 289 additions and 166 deletions

View File

@ -32,7 +32,7 @@ const attributes = {
perPage: 5,
pages: 1,
},
hideControls: [ CoreFilterNames.ORDER ],
hideControls: [ CoreFilterNames.ORDER, CoreFilterNames.FILTERABLE ],
};
const heading: InnerBlockTemplate = [

View File

@ -31,7 +31,7 @@ const attributes = {
perPage: 5,
pages: 1,
},
hideControls: [ CoreFilterNames.FEATURED ],
hideControls: [ CoreFilterNames.FEATURED, CoreFilterNames.FILTERABLE ],
};
const heading: InnerBlockTemplate = [

View File

@ -40,7 +40,7 @@ const attributes = {
value: '-7 days',
},
},
hideControls: [ CoreFilterNames.ORDER ],
hideControls: [ CoreFilterNames.ORDER, CoreFilterNames.FILTERABLE ],
};
const heading: InnerBlockTemplate = [

View File

@ -34,7 +34,7 @@ const attributes = {
perPage: 5,
pages: 1,
},
hideControls: [ CoreFilterNames.ON_SALE ],
hideControls: [ CoreFilterNames.ON_SALE, CoreFilterNames.FILTERABLE ],
};
const heading: InnerBlockTemplate = [

View File

@ -35,7 +35,7 @@ const attributes = {
perPage: 5,
pages: 1,
},
hideControls: [ CoreFilterNames.ORDER ],
hideControls: [ CoreFilterNames.ORDER, CoreFilterNames.FILTERABLE ],
};
const heading: InnerBlockTemplate = [

View File

@ -62,6 +62,7 @@ export const DEFAULT_QUERY: ProductCollectionQuery = {
woocommerceHandPickedProducts: [],
timeFrame: undefined,
priceRange: undefined,
filterable: false,
};
export const DEFAULT_ATTRIBUTES: Pick<

View File

@ -36,7 +36,10 @@ import {
import { setQueryAttribute, getDefaultSettings } from '../../utils';
import UpgradeNotice from './upgrade-notice';
import ColumnsControl from './columns-control';
import InheritQueryControl from './inherit-query-control';
import {
InheritQueryControl,
FilterableControl,
} from './use-page-context-control';
import OrderByControl from './order-by-control';
import OnSaleControl from './on-sale-control';
import StockStatusControl from './stock-status-control';
@ -79,6 +82,8 @@ const ProductCollectionInspectorControls = (
const showQueryControls = inherit === false;
const showInheritQueryControl =
isArchiveTemplate && shouldShowFilter( CoreFilterNames.INHERIT );
const showFilterableControl =
! isArchiveTemplate && shouldShowFilter( CoreFilterNames.FILTERABLE );
const showOrderControl =
showQueryControls && shouldShowFilter( CoreFilterNames.ORDER );
const showOnSaleControl = shouldShowFilter( CoreFilterNames.ON_SALE );
@ -129,6 +134,9 @@ const ProductCollectionInspectorControls = (
{ showInheritQueryControl && (
<InheritQueryControl { ...queryControlProps } />
) }
{ showFilterableControl && (
<FilterableControl { ...queryControlProps } />
) }
<LayoutOptionsControl { ...displayControlProps } />
<ColumnsControl { ...displayControlProps } />
{ showOrderControl && (

View File

@ -3,7 +3,6 @@
*/
import { __ } from '@wordpress/i18n';
import { usePrevious } from '@woocommerce/base-hooks';
import { select } from '@wordpress/data';
import { useMemo } from '@wordpress/element';
import {
ToggleControl,
@ -17,62 +16,28 @@ import {
*/
import {
CoreFilterNames,
ProductCollectionQuery,
QueryControlProps,
type ProductCollectionQuery,
type QueryControlProps,
} from '../../types';
import { DEFAULT_QUERY } from '../../constants';
import { getDefaultValueOfInheritQueryFromTemplate } from '../../utils';
import {
getDefaultValueOfInherit,
getDefaultValueOfFilterable,
} from '../../utils';
const label = __( 'Sync with current query', 'woocommerce' );
const label = __( 'Use page context', 'woocommerce' );
const productArchiveHelpText = __(
'Enable to adjust the displayed products based on the current template and any applied filters.',
const helpText = __(
'Adjust the displayed products depending on the current template and any applied query filters.',
'woocommerce'
);
const productsByCategoryHelpText = __(
'Enable to adjust the displayed products based on the current category and any applied filters.',
'woocommerce'
);
const productsByTagHelpText = __(
'Enable to adjust the displayed products based on the current tag and any applied filters.',
'woocommerce'
);
const productsByAttributeHelpText = __(
'Enable to adjust the displayed products based on the current attribute and any applied filters.',
'woocommerce'
);
const searchResultsHelpText = __(
'Enable to adjust the displayed products based on the current search and any applied filters.',
'woocommerce'
);
const getHelpTextForTemplate = ( templateId: string ): string => {
if ( templateId.includes( '//taxonomy-product_cat' ) ) {
return productsByCategoryHelpText;
}
if ( templateId.includes( '//taxonomy-product_tag' ) ) {
return productsByTagHelpText;
}
if ( templateId.includes( '//taxonomy-product_attribute' ) ) {
return productsByAttributeHelpText;
}
if ( templateId.includes( '//product-search-results' ) ) {
return searchResultsHelpText;
}
return productArchiveHelpText;
};
const InheritQueryControl = ( {
setQueryAttribute,
trackInteraction,
query,
}: QueryControlProps ) => {
const inherit = query?.inherit;
const editSiteStore = select( 'core/edit-site' );
const queryObjectBeforeInheritEnabled = usePrevious(
query,
@ -81,13 +46,7 @@ const InheritQueryControl = ( {
}
);
const defaultValue = useMemo(
() => getDefaultValueOfInheritQueryFromTemplate(),
[]
);
const currentTemplateId = editSiteStore.getEditedPostId() as string;
const helpText = getHelpTextForTemplate( currentTemplateId );
const defaultValue = useMemo( () => getDefaultValueOfInherit(), [] );
return (
<ToolsPanelItem
@ -128,4 +87,41 @@ const InheritQueryControl = ( {
);
};
export default InheritQueryControl;
const FilterableControl = ( {
setQueryAttribute,
trackInteraction,
query,
}: QueryControlProps ) => {
const filterable = query?.filterable;
const defaultValue = useMemo( () => getDefaultValueOfFilterable(), [] );
return (
<ToolsPanelItem
label={ label }
hasValue={ () => filterable !== defaultValue }
isShownByDefault
onDeselect={ () => {
setQueryAttribute( {
filterable: defaultValue,
} );
trackInteraction( CoreFilterNames.FILTERABLE );
} }
>
<ToggleControl
className="wc-block-product-collection__inherit-query-control"
label={ label }
help={ helpText }
checked={ !! filterable }
onChange={ ( value ) => {
setQueryAttribute( {
filterable: value,
} );
trackInteraction( CoreFilterNames.FILTERABLE );
} }
/>
</ToolsPanelItem>
);
};
export { FilterableControl, InheritQueryControl };

View File

@ -23,7 +23,8 @@ import type {
} from '../types';
import { DEFAULT_ATTRIBUTES, INNER_BLOCKS_TEMPLATE } from '../constants';
import {
getDefaultValueOfInheritQueryFromTemplate,
getDefaultValueOfInherit,
getDefaultValueOfFilterable,
useSetPreviewState,
} from '../utils';
import InspectorControls from './inspector-controls';
@ -95,7 +96,8 @@ const ProductCollectionContent = ( {
...DEFAULT_ATTRIBUTES,
query: {
...( DEFAULT_ATTRIBUTES.query as ProductCollectionQuery ),
inherit: getDefaultValueOfInheritQueryFromTemplate(),
inherit: getDefaultValueOfInherit(),
filterable: getDefaultValueOfFilterable(),
},
...( attributes as Partial< ProductCollectionAttributes > ),
queryId,

View File

@ -28,6 +28,7 @@ export interface ProductCollectionAttributes {
*/
queryContextIncludes: string[];
forcePageReload: boolean;
filterable: boolean;
// eslint-disable-next-line @typescript-eslint/naming-convention
__privatePreviewState?: PreviewState;
}
@ -93,6 +94,7 @@ export interface ProductCollectionQuery {
isProductCollectionBlock: boolean;
woocommerceHandPickedProducts: string[];
priceRange: undefined | PriceRange;
filterable: boolean;
}
export type ProductCollectionEditComponentProps =
@ -118,13 +120,15 @@ export type ProductCollectionSetAttributes = (
attrs: Partial< ProductCollectionAttributes >
) => void;
export type TrackInteraction = ( filter: CoreFilterNames | string ) => void;
export type DisplayLayoutControlProps = {
displayLayout: ProductCollectionDisplayLayout;
setAttributes: ProductCollectionSetAttributes;
};
export type QueryControlProps = {
query: ProductCollectionQuery;
trackInteraction: ( filter: CoreFilterNames | string ) => void;
trackInteraction: TrackInteraction;
setQueryAttribute: ( attrs: Partial< ProductCollectionQuery > ) => void;
};
@ -150,6 +154,7 @@ export enum CoreFilterNames {
STOCK_STATUS = 'stock-status',
TAXONOMY = 'taxonomy',
PRICE_RANGE = 'price-range',
FILTERABLE = 'filterable',
}
export type CollectionName = CoreCollectionNames | string;

View File

@ -80,7 +80,9 @@ const isInProductArchive = () => {
: false;
};
const isFirstBlockThatSyncsWithQuery = () => {
const isFirstBlockThatUsesPageContext = (
property: 'inherit' | 'filterable'
) => {
// We use experimental selector because it's been graduated as stable (`getBlocksByName`)
// in Gutenberg 17.6 (https://github.com/WordPress/gutenberg/pull/58156) and will be
// available in WordPress 6.5.
@ -97,15 +99,23 @@ const isFirstBlockThatSyncsWithQuery = () => {
( clientId ) => {
const block = getBlock( clientId );
return block.attributes?.query?.inherit;
return block.attributes?.query?.[ property ];
}
);
return ! blockAlreadySyncedWithQuery;
};
export function getDefaultValueOfInheritQueryFromTemplate() {
return isInProductArchive() ? isFirstBlockThatSyncsWithQuery() : false;
export function getDefaultValueOfInherit() {
return isInProductArchive()
? isFirstBlockThatUsesPageContext( 'inherit' )
: false;
}
export function getDefaultValueOfFilterable() {
return ! isInProductArchive()
? isFirstBlockThatUsesPageContext( 'filterable' )
: false;
}
/**
@ -226,7 +236,8 @@ export const getDefaultQuery = (
...currentQuery,
orderBy: DEFAULT_QUERY.orderBy as TProductCollectionOrderBy,
order: DEFAULT_QUERY.order as TProductCollectionOrder,
inherit: getDefaultValueOfInheritQueryFromTemplate(),
inherit: getDefaultValueOfInherit(),
filterable: getDefaultValueOfFilterable(),
} );
export const getDefaultDisplayLayout = () =>
@ -246,7 +257,8 @@ export const getDefaultProductCollection = () =>
...DEFAULT_ATTRIBUTES,
query: {
...DEFAULT_ATTRIBUTES.query,
inherit: getDefaultValueOfInheritQueryFromTemplate(),
inherit: getDefaultValueOfInherit(),
filterable: getDefaultValueOfFilterable(),
},
},
createBlocksFromInnerBlocksTemplate( INNER_BLOCKS_TEMPLATE )

View File

@ -126,14 +126,12 @@ test.describe( 'Product Collection', () => {
} );
} );
test.describe( 'Product Collection Sidebar Settings', () => {
test.beforeEach( async ( { pageObject } ) => {
await pageObject.createNewPostAndInsertBlock();
} );
test.describe( 'Inspector Controls', () => {
test( 'Reflects the correct number of columns according to sidebar settings', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
await pageObject.setNumberOfColumns( 2 );
await expect( pageObject.productTemplate ).toHaveClass(
/columns-2/
@ -154,6 +152,8 @@ test.describe( 'Product Collection', () => {
test( 'Order By - sort products by title in descending order correctly', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
const sortedTitles = [
'WordPress Pennant',
'V-Neck T-Shirt',
@ -177,6 +177,8 @@ test.describe( 'Product Collection', () => {
test( 'Products can be filtered based on "on sale" status', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
const allProducts = pageObject.products;
const salePoducts = pageObject.products.filter( {
hasText: 'Product on sale',
@ -201,6 +203,8 @@ test.describe( 'Product Collection', () => {
test( 'Products can be filtered based on selection in handpicked products option', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
await pageObject.addFilter( 'Show Hand-picked Products' );
const filterName = 'Hand-picked Products';
@ -221,6 +225,7 @@ test.describe( 'Product Collection', () => {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
await pageObject.addFilter( 'Keyword' );
await pageObject.setKeyword( 'Album' );
@ -236,6 +241,8 @@ test.describe( 'Product Collection', () => {
test( 'Products can be filtered based on category.', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
const filterName = 'Product categories';
await pageObject.addFilter( 'Show product categories' );
await pageObject.setFilterComboboxValue( filterName, [
@ -276,6 +283,8 @@ test.describe( 'Product Collection', () => {
test( 'Products can be filtered based on tags.', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
const filterName = 'Product tags';
await pageObject.addFilter( 'Show product tags' );
await pageObject.setFilterComboboxValue( filterName, [
@ -296,6 +305,8 @@ test.describe( 'Product Collection', () => {
test( 'Products can be filtered based on product attributes like color, size etc.', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
await pageObject.addFilter( 'Show Product Attributes' );
await pageObject.setProductAttribute( 'Color', 'Green' );
@ -313,6 +324,8 @@ test.describe( 'Product Collection', () => {
test( 'Products can be filtered based on stock status (in stock, out of stock, or backorder).', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
await pageObject.setFilterComboboxValue( 'Stock status', [
'Out of stock',
] );
@ -331,6 +344,8 @@ test.describe( 'Product Collection', () => {
test( 'Products can be filtered based on featured status.', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
await expect( pageObject.products ).toHaveCount( 9 );
await pageObject.addFilter( 'Featured' );
@ -349,6 +364,8 @@ test.describe( 'Product Collection', () => {
test( 'Products can be filtered based on created date.', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
await expect( pageObject.products ).toHaveCount( 9 );
await pageObject.addFilter( 'Created' );
@ -376,6 +393,8 @@ test.describe( 'Product Collection', () => {
test( 'Products can be filtered based on price range.', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock();
await expect( pageObject.products ).toHaveCount( 9 );
await pageObject.addFilter( 'Price Range' );
@ -403,74 +422,62 @@ test.describe( 'Product Collection', () => {
await expect( pageObject.products ).toHaveCount( 4 );
} );
test.describe( 'Sync with current template', () => {
test( 'should not be visible on posts', async ( {
pageObject,
} ) => {
test.describe( '"Use page context" control', () => {
test( 'should be visible on posts', async ( { pageObject } ) => {
await pageObject.createNewPostAndInsertBlock();
const sidebarSettings =
await pageObject.locateSidebarSettings();
await expect(
sidebarSettings.locator(
SELECTORS.inheritQueryFromTemplateControl
)
).toBeHidden();
pageObject
.locateSidebarSettings()
.locator( SELECTORS.usePageContextControl )
).toBeVisible();
} );
const archiveTemplates = [
[
'woocommerce/woocommerce//archive-product',
'woocommerce/woocommerce//taxonomy-product_cat',
'woocommerce/woocommerce//taxonomy-product_tag',
'woocommerce/woocommerce//taxonomy-product_attribute',
'woocommerce/woocommerce//product-search-results',
];
const nonArchiveTemplates = [
'woocommerce/woocommerce//single-product',
'twentytwentyfour//home',
'twentytwentyfour//index',
];
archiveTemplates.map( async ( template ) => {
test( `should be visible in archive template: ${ template }`, async ( {
].forEach( ( slug ) => {
test( `should be visible in archive template: ${ slug }`, async ( {
pageObject,
editor,
} ) => {
await pageObject.goToEditorTemplate( template );
await pageObject.goToEditorTemplate( slug );
await pageObject.insertProductCollection();
await pageObject.chooseCollectionInTemplate();
await pageObject.focusProductCollection();
await editor.openDocumentSettingsSidebar();
const sidebarSettings =
await pageObject.locateSidebarSettings();
await expect(
sidebarSettings.locator(
SELECTORS.inheritQueryFromTemplateControl
)
pageObject
.locateSidebarSettings()
.locator( SELECTORS.usePageContextControl )
).toBeVisible();
} );
} );
nonArchiveTemplates.map( async ( template ) => {
test( `should not be visible in non-archive template: ${ template }`, async ( {
[
'woocommerce/woocommerce//single-product',
'twentytwentyfour//home',
'twentytwentyfour//index',
].forEach( ( slug ) => {
test( `should be visible in non-archive template: ${ slug }`, async ( {
pageObject,
editor,
} ) => {
await pageObject.goToEditorTemplate( template );
await pageObject.goToEditorTemplate( slug );
await pageObject.insertProductCollection();
await pageObject.chooseCollectionInTemplate();
await pageObject.focusProductCollection();
await editor.openDocumentSettingsSidebar();
const sidebarSettings =
await pageObject.locateSidebarSettings();
await expect(
sidebarSettings.locator(
SELECTORS.inheritQueryFromTemplateControl
)
).toBeHidden();
pageObject
.locateSidebarSettings()
.locator( SELECTORS.usePageContextControl )
).toBeVisible();
} );
} );
@ -482,18 +489,15 @@ test.describe( 'Product Collection', () => {
await pageObject.focusProductCollection();
await editor.openDocumentSettingsSidebar();
const sidebarSettings =
await pageObject.locateSidebarSettings();
const sidebarSettings = pageObject.locateSidebarSettings();
// Inherit query from template should be visible & enabled by default
await expect(
sidebarSettings.locator(
SELECTORS.inheritQueryFromTemplateControl
)
sidebarSettings.locator( SELECTORS.usePageContextControl )
).toBeVisible();
await expect(
sidebarSettings.locator(
`${ SELECTORS.inheritQueryFromTemplateControl } input`
`${ SELECTORS.usePageContextControl } input`
)
).toBeChecked();
@ -529,45 +533,136 @@ test.describe( 'Product Collection', () => {
).toBeChecked();
} );
test( 'is enabled by default in 1st Product Collection and disabled in 2nd+', async ( {
test( 'is enabled by default unless already enabled elsewhere', async ( {
pageObject,
editor,
} ) => {
const productCollection = editor.canvas.getByLabel(
'Block: Product Collection',
{ exact: true }
);
const usePageContextToggle = pageObject
.locateSidebarSettings()
.locator( SELECTORS.usePageContextControl )
.locator( 'input' );
// First Product Catalog
// Option should be visible & ENABLED by default
await pageObject.goToEditorTemplate();
await pageObject.focusProductCollection();
await editor.selectBlocks( productCollection.first() );
await editor.openDocumentSettingsSidebar();
const sidebarSettings =
await pageObject.locateSidebarSettings();
await expect(
sidebarSettings.locator(
SELECTORS.inheritQueryFromTemplateControl
)
).toBeVisible();
await expect(
sidebarSettings.locator(
`${ SELECTORS.inheritQueryFromTemplateControl } input`
)
).toBeChecked();
await expect( usePageContextToggle ).toBeChecked();
// Second Product Catalog
// Option should be visible & DISABLED by default
await pageObject.insertProductCollection();
await pageObject.chooseCollectionInTemplate( 'productCatalog' );
await editor.selectBlocks( productCollection.last() );
await expect( usePageContextToggle ).not.toBeChecked();
// Disable the option in the first Product Catalog
await editor.selectBlocks( productCollection.first() );
await usePageContextToggle.click();
// Third Product Catalog
// Option should be visible & ENABLED by default
await pageObject.insertProductCollection();
await pageObject.chooseCollectionInTemplate( 'productCatalog' );
await editor.selectBlocks( productCollection.last() );
await expect( usePageContextToggle ).toBeChecked();
} );
test( 'allows filtering in non-archive context', async ( {
pageObject,
editor,
page,
} ) => {
await pageObject.createNewPostAndInsertBlock();
await expect( pageObject.products ).toHaveCount( 9 );
await pageObject.insertProductCollection();
await pageObject.chooseCollectionInPost( 'productCatalog' );
await expect( pageObject.products ).toHaveCount( 18 );
await page.getByLabel( 'Toggle block inserter' ).click();
await page.getByRole( 'tab', { name: 'Patterns' } ).click();
await page
.getByPlaceholder( 'Search' )
.fill( 'product filters' );
await page.getByLabel( 'Product Filters' ).click();
const postId = await editor.publishPost();
await page.goto( `/?p=${ postId }` );
const productCollection = page.locator(
'.wp-block-woocommerce-product-collection'
);
await expect(
sidebarSettings.locator(
SELECTORS.inheritQueryFromTemplateControl
)
).toBeVisible();
productCollection.first().locator( SELECTORS.product )
).toHaveCount( 9 );
await expect(
sidebarSettings.locator(
`${ SELECTORS.inheritQueryFromTemplateControl } input`
)
).not.toBeChecked();
productCollection.last().locator( SELECTORS.product )
).toHaveCount( 9 );
await page
.getByRole( 'textbox', {
name: 'Filter products by maximum',
} )
.dblclick();
await page.keyboard.type( '10' );
await page.keyboard.press( 'Tab' );
await expect(
productCollection.first().locator( SELECTORS.product )
).toHaveCount( 1 );
await expect(
productCollection.last().locator( SELECTORS.product )
).toHaveCount( 9 );
} );
test( 'correctly combines editor and front-end filters', async ( {
pageObject,
editor,
page,
} ) => {
await pageObject.createNewPostAndInsertBlock();
await expect( pageObject.products ).toHaveCount( 9 );
await pageObject.addFilter( 'Show product categories' );
await pageObject.setFilterComboboxValue( 'Product categories', [
'Music',
] );
await page.getByLabel( 'Toggle block inserter' ).click();
await page.getByRole( 'tab', { name: 'Patterns' } ).click();
await page
.getByPlaceholder( 'Search' )
.fill( 'product filters' );
await page.getByLabel( 'Product Filters' ).click();
await expect( pageObject.products ).toHaveCount( 2 );
const postId = await editor.publishPost();
await page.goto( `/?p=${ postId }` );
await expect( pageObject.products ).toHaveCount( 2 );
await page
.getByRole( 'textbox', {
name: 'Filter products by maximum',
} )
.dblclick();
await page.keyboard.type( '5' );
await page.keyboard.press( 'Tab' );
await expect( pageObject.products ).toHaveCount( 1 );
} );
} );
} );
@ -787,17 +882,16 @@ test.describe( 'Product Collection', () => {
await expect( pageObject.products ).toHaveCount( 4 );
} );
test( "Product Catalog Collection can be added in post and doesn't sync query with template", async ( {
test( 'Product Catalog Collection can be added in post and syncs query with template', async ( {
pageObject,
} ) => {
await pageObject.createNewPostAndInsertBlock( 'productCatalog' );
const sidebarSettings = await pageObject.locateSidebarSettings();
const input = sidebarSettings.locator(
`${ SELECTORS.inheritQueryFromTemplateControl } input`
);
const usePageContextToggle = pageObject
.locateSidebarSettings()
.locator( `${ SELECTORS.usePageContextControl } input` );
await expect( input ).toBeHidden();
await expect( usePageContextToggle ).toBeVisible();
await expect( pageObject.products ).toHaveCount( 9 );
await pageObject.publishAndGoToFrontend();
@ -822,9 +916,9 @@ test.describe( 'Product Collection', () => {
await pageObject.chooseCollectionInTemplate();
await editor.openDocumentSettingsSidebar();
const sidebarSettings = await pageObject.locateSidebarSettings();
const sidebarSettings = pageObject.locateSidebarSettings();
const input = sidebarSettings.locator(
`${ SELECTORS.inheritQueryFromTemplateControl } input`
`${ SELECTORS.usePageContextControl } input`
);
await expect( input ).toBeChecked();
@ -854,8 +948,7 @@ test.describe( 'Product Collection', () => {
test( 'On Sale', async ( { pageObject } ) => {
await pageObject.createNewPostAndInsertBlock( 'onSale' );
const sidebarSettings =
await pageObject.locateSidebarSettings();
const sidebarSettings = pageObject.locateSidebarSettings();
const input = sidebarSettings.getByLabel(
SELECTORS.onSaleControlLabel
);
@ -865,8 +958,7 @@ test.describe( 'Product Collection', () => {
test( 'Featured', async ( { pageObject } ) => {
await pageObject.createNewPostAndInsertBlock( 'featured' );
const sidebarSettings =
await pageObject.locateSidebarSettings();
const sidebarSettings = pageObject.locateSidebarSettings();
const input = sidebarSettings.getByLabel(
SELECTORS.featuredControlLabel
);
@ -1477,7 +1569,7 @@ test.describe( 'Testing registerProductCollection', () => {
'myCustomCollection'
);
const sidebarSettings = await pageObject.locateSidebarSettings();
const sidebarSettings = pageObject.locateSidebarSettings();
const onsaleControl = sidebarSettings.getByLabel(
SELECTORS.onSaleControlLabel
);

View File

@ -38,7 +38,7 @@ export const SELECTORS = {
},
onSaleControlLabel: 'Show only products on sale',
featuredControlLabel: 'Show only featured products',
inheritQueryFromTemplateControl:
usePageContextControl:
'.wc-block-product-collection__inherit-query-control',
shrinkColumnsToFit: 'Responsive',
productSearchLabel: 'Search',
@ -374,7 +374,7 @@ class ProductCollectionPage {
}
async setNumberOfColumns( numberOfColumns: number ) {
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const inputField = sidebarSettings.getByRole( 'spinbutton', {
name: 'Columns',
} );
@ -390,7 +390,7 @@ class ProductCollectionPage {
| 'popularity/desc'
| 'rating/desc'
) {
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const orderByComboBox = sidebarSettings.getByRole( 'combobox', {
name: 'Order by',
} );
@ -400,7 +400,7 @@ class ProductCollectionPage {
}
async getOrderByElement() {
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
return sidebarSettings.getByRole( 'combobox', {
name: 'Order by',
} );
@ -423,7 +423,7 @@ class ProductCollectionPage {
onSale: true,
}
) {
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const input = sidebarSettings.getByLabel(
SELECTORS.onSaleControlLabel
);
@ -448,7 +448,7 @@ class ProductCollectionPage {
isLocatorsRefreshNeeded: true,
}
) {
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const input = sidebarSettings.getByLabel(
SELECTORS.featuredControlLabel
);
@ -475,7 +475,7 @@ class ProductCollectionPage {
const operatorSelector = SELECTORS.createdFilter.operator[ operator ];
const rangeSelector = SELECTORS.createdFilter.range[ range ];
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const operatorButton = sidebarSettings.getByLabel( operatorSelector );
const rangeButton = sidebarSettings.getByLabel( rangeSelector );
@ -487,7 +487,7 @@ class ProductCollectionPage {
const minInputSelector = SELECTORS.priceRangeFilter.min;
const maxInputSelector = SELECTORS.priceRangeFilter.max;
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const minInput = sidebarSettings.getByLabel( minInputSelector );
const maxInput = sidebarSettings.getByLabel( maxInputSelector );
@ -498,7 +498,7 @@ class ProductCollectionPage {
}
async setFilterComboboxValue( filterName: string, filterValue: string[] ) {
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const input = sidebarSettings.getByLabel( filterName );
await input.click();
@ -527,7 +527,7 @@ class ProductCollectionPage {
}
async setKeyword( keyword: string ) {
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const input = sidebarSettings.getByLabel( 'Keyword' );
await input.clear();
await input.fill( keyword );
@ -590,7 +590,7 @@ class ProductCollectionPage {
}
async setShrinkColumnsToFit( value = true ) {
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const input = sidebarSettings.getByLabel(
SELECTORS.shrinkColumnsToFit
);
@ -602,7 +602,7 @@ class ProductCollectionPage {
}
async setProductAttribute( attribute: 'Color' | 'Size', value: string ) {
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const productAttributesContainer = sidebarSettings.locator(
'.woocommerce-product-attributes'
@ -631,9 +631,9 @@ class ProductCollectionPage {
}
async setInheritQueryFromTemplate( inheritQueryFromTemplate: boolean ) {
const sidebarSettings = await this.locateSidebarSettings();
const sidebarSettings = this.locateSidebarSettings();
const input = sidebarSettings.locator(
`${ SELECTORS.inheritQueryFromTemplateControl } input`
`${ SELECTORS.usePageContextControl } input`
);
if ( inheritQueryFromTemplate ) {
await input.check();
@ -687,7 +687,7 @@ class ProductCollectionPage {
/**
* Locators
*/
async locateSidebarSettings() {
locateSidebarSettings() {
return this.page.getByRole( 'region', {
name: 'Editor settings',
} );

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Product Collection: Rename "Sync with current query" option to "Use page context" and make it working in non-archive context as well

View File

@ -524,7 +524,10 @@ class ProductCollection extends AbstractBlock {
// phpcs:ignore WordPress.DB.SlowDBQuery
$block_context_query['tax_query'] = ! empty( $query['tax_query'] ) ? $query['tax_query'] : array();
$is_exclude_applied_filters = ! ( $block->context['query']['inherit'] ?? false );
$inherit = $block->context['query']['inherit'] ?? false;
$filterable = $block->context['query']['filterable'] ?? false;
$is_exclude_applied_filters = ! ( $inherit || $filterable );
return $this->get_final_frontend_query( $block_context_query, $page, $is_exclude_applied_filters );
}