Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Product Collection: Add stock status filter #9580

Merged
merged 20 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e4abb25
Add columns control to product collection block editor settings
imanish003 May 15, 2023
43b2d1c
Merge branch 'trunk' into 9356-product-collection-editor-settings-col…
imanish003 May 15, 2023
65582af
Refactor: Simplify Fallback Return in ColumnsControl Component
imanish003 May 16, 2023
e03ecf6
Feature: Add 'Order By' Control to Product Collection Inspector
imanish003 May 16, 2023
91b5cb4
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
imanish003 May 16, 2023
5e5c6b1
Add more options to OrderBy type
imanish003 May 16, 2023
9cfa07e
Merge branch 'trunk' into 9359-product-collection-editor-settings-ord…
imanish003 May 17, 2023
7954c13
Add orderby handling on frontend & editor
imanish003 May 17, 2023
b756198
Merge branch 'trunk' into 9359-product-collection-editor-settings-ord…
imanish003 May 17, 2023
bed6be4
Merge branch 'trunk' into 9359-product-collection-editor-settings-ord…
imanish003 May 18, 2023
724f894
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
imanish003 May 19, 2023
e5a43cf
Add 'on sale' filter and enhance settings management in product colle…
imanish003 May 19, 2023
2e77956
Merge branch 'trunk' into 9361-product-collection-filters-on-sale
imanish003 May 22, 2023
a832d97
Add stock status filter to WooCommerce product collection block
imanish003 May 24, 2023
c4188da
Refactor Stock Status control of Product Collection block
imanish003 May 24, 2023
2d5e3f9
Merge branch 'trunk' into 9362-product-collection-filters-stock-status
imanish003 May 24, 2023
255b164
Resolve conflicts
imanish003 May 25, 2023
d1e29ef
Fix: Default values of attributes not saving as serialized block comment
imanish003 May 26, 2023
0c30f5b
Replace usage of 'statii' with 'statuses' in stock status handling
imanish003 May 26, 2023
c99646e
Merge branch 'trunk' into 9362-product-collection-filters-stock-status
imanish003 May 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 3 additions & 25 deletions assets/js/blocks/product-collection/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,13 @@
"type": "number"
},
"query": {
"type": "object",
"default": {
"perPage": 9,
"pages": 0,
"offset": 0,
"postType": "product",
"order": "asc",
"orderBy": "title",
"author": "",
"search": "",
"exclude": [],
"sticky": "",
"inherit": false,
"taxQuery": null,
"parents": [],
"isProductCollectionBlock": true,
"woocommerceOnSale": false
}
"type": "object"
},
"tagName": {
"type": "string",
"default": "div"
"type": "string"
},
"displayLayout": {
"type": "object",
"default": {
"type": "flex",
"columns": 3
}
"type": "object"
}
},
"providesContext": {
Expand Down
78 changes: 78 additions & 0 deletions assets/js/blocks/product-collection/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* External dependencies
*/
import { getSetting } from '@woocommerce/settings';
import { objectOmit } from '@woocommerce/utils';

/**
* Internal dependencies
*/
import {
ProductCollectionAttributes,
TProductCollectionOrder,
TProductCollectionOrderBy,
ProductCollectionQuery,
ProductCollectionDisplayLayout,
} from './types';

export const STOCK_STATUS_OPTIONS = getSetting< Record< string, string > >(
'stockStatusOptions',
[]
);

const GLOBAL_HIDE_OUT_OF_STOCK = getSetting< boolean >(
'hideOutOfStockItems',
false
);

export const getDefaultStockStatuses = () => {
return GLOBAL_HIDE_OUT_OF_STOCK
? Object.keys( objectOmit( STOCK_STATUS_OPTIONS, 'outofstock' ) )
: Object.keys( STOCK_STATUS_OPTIONS );
};

export const DEFAULT_ATTRIBUTES: Partial< ProductCollectionAttributes > = {
query: {
perPage: 9,
pages: 0,
offset: 0,
postType: 'product',
order: 'asc',
orderBy: 'title',
author: '',
search: '',
exclude: [],
sticky: '',
inherit: false,
taxQuery: '',
parents: [],
isProductCollectionBlock: true,
woocommerceOnSale: false,
woocommerceStockStatus: getDefaultStockStatuses(),
},
tagName: 'div',
displayLayout: {
type: 'flex',
columns: 3,
},
};

export const getDefaultSettings = (
currentAttributes: ProductCollectionAttributes
): Partial< ProductCollectionAttributes > => ( {
displayLayout:
DEFAULT_ATTRIBUTES.displayLayout as ProductCollectionDisplayLayout,
query: {
...currentAttributes.query,
orderBy: ( DEFAULT_ATTRIBUTES.query as ProductCollectionQuery )
.orderBy as TProductCollectionOrderBy,
order: ( DEFAULT_ATTRIBUTES.query as ProductCollectionQuery )
.order as TProductCollectionOrder,
},
} );

export const DEFAULT_FILTERS = {
woocommerceOnSale: ( DEFAULT_ATTRIBUTES.query as ProductCollectionQuery )
.woocommerceOnSale,
woocommerceStockStatus: getDefaultStockStatuses(),
};
11 changes: 10 additions & 1 deletion assets/js/blocks/product-collection/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ImageSizing } from '../../atomic/blocks/product-elements/image/types';
import { ProductCollectionAttributes } from './types';
import { VARIATION_NAME as PRODUCT_TITLE_ID } from './variations/elements/product-title';
import InspectorControls from './inspector-controls';
import { DEFAULT_ATTRIBUTES } from './constants';

export const INNER_BLOCKS_TEMPLATE: InnerBlockTemplate[] = [
[
Expand Down Expand Up @@ -82,11 +83,19 @@ const Edit = ( props: BlockEditProps< ProductCollectionAttributes > ) => {

const instanceId = useInstanceId( Edit );

/**
* Because of issue https://github.com/WordPress/gutenberg/issues/7342,
* We are using this workaround to set default attributes.
*/
useEffect( () => {
setAttributes( { ...DEFAULT_ATTRIBUTES, ...attributes } );
}, [ setAttributes ] );

// We need this for multi-query block pagination.
// Query parameters for each block are scoped to their ID.
useEffect( () => {
if ( ! Number.isFinite( queryId ) ) {
setAttributes( { queryId: instanceId } );
setAttributes( { queryId: Number( instanceId ) } );
}
}, [ queryId, instanceId, setAttributes ] );

Expand Down
3 changes: 0 additions & 3 deletions assets/js/blocks/product-collection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ import './variations';
if ( isExperimentalBuild() ) {
registerBlockType( metadata, {
icon,
attributes: {
...metadata.attributes,
},
edit,
save,
} );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
ProductCollectionAttributes,
ProductCollectionDisplayLayout,
} from '../types';
import { getDefaultSettings } from './constants';
import { getDefaultSettings } from '../constants';

const ColumnsControl = (
props: BlockEditProps< ProductCollectionAttributes >
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import ColumnsControl from './columns-control';
import OrderByControl from './order-by-control';
import OnSaleControl from './on-sale-control';
import { setQueryAttribute } from './utils';
import { DEFAULT_FILTERS, getDefaultSettings } from './constants';
import { DEFAULT_FILTERS, getDefaultSettings } from '../constants';
import StockStatusControl from './stock-status-control';

const ProductCollectionInspectorControls = (
props: BlockEditProps< ProductCollectionAttributes >
Expand All @@ -45,6 +46,7 @@ const ProductCollectionInspectorControls = (
} }
>
<OnSaleControl { ...props } />
<StockStatusControl { ...props } />
</ToolsPanel>
</InspectorControls>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
* Internal dependencies
*/
import { ProductCollectionAttributes } from '../types';
import { setQueryAttribute } from './utils';

const OnSaleControl = (
props: BlockEditProps< ProductCollectionAttributes >
Expand All @@ -23,14 +24,11 @@ const OnSaleControl = (
return (
<ToolsPanelItem
label={ __( 'On Sale', 'woo-gutenberg-products-block' ) }
hasValue={ () => query.woocommerceOnSale }
hasValue={ () => query.woocommerceOnSale === true }
isShownByDefault
onDeselect={ () => {
props.setAttributes( {
query: {
...query,
woocommerceOnSale: false,
},
setQueryAttribute( props, {
woocommerceOnSale: false,
} );
} }
>
Expand All @@ -41,11 +39,8 @@ const OnSaleControl = (
) }
checked={ query.woocommerceOnSale || false }
onChange={ ( woocommerceOnSale ) => {
props.setAttributes( {
query: {
...query,
woocommerceOnSale,
},
setQueryAttribute( props, {
woocommerceOnSale,
} );
} }
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
TProductCollectionOrder,
TProductCollectionOrderBy,
} from '../types';
import { getDefaultSettings } from './constants';
import { getDefaultSettings } from '../constants';

const orderOptions = [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { BlockEditProps } from '@wordpress/blocks';
import fastDeepEqual from 'fast-deep-equal/es6';
import {
FormTokenField,
// @ts-expect-error Using experimental features
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import { ProductCollectionAttributes } from '../types';
import { setQueryAttribute } from './utils';
import { STOCK_STATUS_OPTIONS, getDefaultStockStatuses } from '../constants';

/**
* Gets the id of a specific stock status from its text label
*
* In theory, we could use a `saveTransform` function on the
* `FormFieldToken` component to do the conversion. However, plugins
* can add custom stock statuses which don't conform to our naming
* conventions.
*/
function getStockStatusIdByLabel( statusLabel: FormTokenField.Value ) {
const label =
typeof statusLabel === 'string' ? statusLabel : statusLabel.value;

return Object.entries( STOCK_STATUS_OPTIONS ).find(
( [ , value ] ) => value === label
)?.[ 0 ];
}

const StockStatusControl = (
props: BlockEditProps< ProductCollectionAttributes >
) => {
const { query } = props.attributes;
return (
<ToolsPanelItem
label={ __( 'Stock status', 'woo-gutenberg-products-block' ) }
hasValue={ () =>
! fastDeepEqual(
query.woocommerceStockStatus,
getDefaultStockStatuses()
)
}
onDeselect={ () => {
setQueryAttribute( props, {
woocommerceStockStatus: getDefaultStockStatuses(),
} );
} }
isShownByDefault
>
<FormTokenField
label={ __( 'Stock status', 'woo-gutenberg-products-block' ) }
onChange={ ( statusLabels ) => {
const woocommerceStockStatus = statusLabels
.map( getStockStatusIdByLabel )
.filter( Boolean ) as string[];

setQueryAttribute( props, {
woocommerceStockStatus,
} );
} }
suggestions={ Object.values( STOCK_STATUS_OPTIONS ) }
validateInput={ ( value: string ) =>
Object.values( STOCK_STATUS_OPTIONS ).includes( value )
}
value={
query?.woocommerceStockStatus?.map(
( key ) => STOCK_STATUS_OPTIONS[ key ]
) || []
}
__experimentalExpandOnFocus={ true }
/>
</ToolsPanelItem>
);
};

export default StockStatusControl;
16 changes: 16 additions & 0 deletions assets/js/blocks/product-collection/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface ProductCollectionAttributes {
];
templateSlug: string;
displayLayout: ProductCollectionDisplayLayout;
tagName: string;
}

export interface ProductCollectionDisplayLayout {
Expand All @@ -30,6 +31,21 @@ export interface ProductCollectionQuery {
sticky: string;
taxQuery: string;
woocommerceOnSale: boolean;
/**
* Filter products by their stock status.
*
* Will generate the following `meta_query`:
*
* ```
* array(
* 'key' => '_stock_status',
* 'value' => (array) $stock_statuses,
* 'compare' => 'IN',
* ),
* ```
*/
woocommerceStockStatus?: string[];
isProductCollectionBlock?: boolean;
}

export type TProductCollectionOrder = 'asc' | 'desc';
Expand Down
Loading