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:
parent
e6d3890bdd
commit
dace7ba296
|
@ -32,7 +32,7 @@ const attributes = {
|
|||
perPage: 5,
|
||||
pages: 1,
|
||||
},
|
||||
hideControls: [ CoreFilterNames.ORDER ],
|
||||
hideControls: [ CoreFilterNames.ORDER, CoreFilterNames.FILTERABLE ],
|
||||
};
|
||||
|
||||
const heading: InnerBlockTemplate = [
|
||||
|
|
|
@ -31,7 +31,7 @@ const attributes = {
|
|||
perPage: 5,
|
||||
pages: 1,
|
||||
},
|
||||
hideControls: [ CoreFilterNames.FEATURED ],
|
||||
hideControls: [ CoreFilterNames.FEATURED, CoreFilterNames.FILTERABLE ],
|
||||
};
|
||||
|
||||
const heading: InnerBlockTemplate = [
|
||||
|
|
|
@ -40,7 +40,7 @@ const attributes = {
|
|||
value: '-7 days',
|
||||
},
|
||||
},
|
||||
hideControls: [ CoreFilterNames.ORDER ],
|
||||
hideControls: [ CoreFilterNames.ORDER, CoreFilterNames.FILTERABLE ],
|
||||
};
|
||||
|
||||
const heading: InnerBlockTemplate = [
|
||||
|
|
|
@ -34,7 +34,7 @@ const attributes = {
|
|||
perPage: 5,
|
||||
pages: 1,
|
||||
},
|
||||
hideControls: [ CoreFilterNames.ON_SALE ],
|
||||
hideControls: [ CoreFilterNames.ON_SALE, CoreFilterNames.FILTERABLE ],
|
||||
};
|
||||
|
||||
const heading: InnerBlockTemplate = [
|
||||
|
|
|
@ -35,7 +35,7 @@ const attributes = {
|
|||
perPage: 5,
|
||||
pages: 1,
|
||||
},
|
||||
hideControls: [ CoreFilterNames.ORDER ],
|
||||
hideControls: [ CoreFilterNames.ORDER, CoreFilterNames.FILTERABLE ],
|
||||
};
|
||||
|
||||
const heading: InnerBlockTemplate = [
|
||||
|
|
|
@ -62,6 +62,7 @@ export const DEFAULT_QUERY: ProductCollectionQuery = {
|
|||
woocommerceHandPickedProducts: [],
|
||||
timeFrame: undefined,
|
||||
priceRange: undefined,
|
||||
filterable: false,
|
||||
};
|
||||
|
||||
export const DEFAULT_ATTRIBUTES: Pick<
|
||||
|
|
|
@ -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 && (
|
||||
|
|
|
@ -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 };
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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',
|
||||
} );
|
||||
|
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue