This repository has been archived by the owner on Feb 23, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 221
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MVP: Attribute filter block powered interactivity API (#11749)
* Update Interactivity API JS files * Disable TS checks in the Interactivity API for now * Add new SSR files * Replace wp_ prefixes with wc_ ones * Replace wp- prefix with wc- * Replace guternberg_ prefix with woocommerce_ * Remove file comments from Gutenberg * Rename files with `wp` prefix * Fix code to load Interactivity API php files * Remove TODO comments * Replace @WordPress with @woocommerce * Update Webpack configuration * Fix directive prefix * Remove interactivity folder from tsconfig exclude * Add client-side navigation meta tag code * Remove unneeded blocks.php file * Fix store tag id * Register Interactivity API runtime script * Fix Interactivity API runtime registering * Add Simple Price Filter block * Remove all files related to directive processing in PHP * Use values directly for SimplePriceFilter SSR * Reset pages to 0 when changing filter Note: we also need to do this with `/page/x` * wip * phpcs * register price filter as inner block * try: render block using save * add types * use min range var instead of 0 * inject dynamic data * query price data in editor * better injecting interactivity data * remove rounding * Product Collection Data endpoint doesn't care about current query so we remove the context for now * extract data injecting as a method, possbily a trait in the future * add sidebar setting * duplicating the markup in php render callback for safety * remove directive from edit component * show prices without decimal * use final class * use sample collection data response * prepare for multiple styles support * use collection data from context * cleanup props and props passing * pass only necessary states * retire heredoc in favor of late escaping * reorganize style * inherit style from current price filter react component, pre extract the component for multiple display style support * keep minPrice smaller than max * remove unnecessary active handler logic * update folder structure * avoid whitespace change * clean up * title * move inspector to component folder, ready to be extracted to inner block * block icon * block name * name * use inner block for view * inner block view switcher * try: process data in Collection Filtes block only * wip: query collection data from collection filters block only * provide all context from collection filters block * simplify context passing * feat: use default attribute to define filter type of view block * rename * remove price block * rename price slider to price, default price filter should be a slider * type cleanup * fix ancestor block name * only passing the collection data down * wip * recusive * editor preview * refactor: data fetching, context passing, and code organization * initial attribute filter block * feat: attribute selector * inspector control * wip * break the edit into smaller components * wip: editor component * extract checkbox list * wip editor preview * show count checkbox list * fix param aggregation for attribute filter blocks * post merge fix * fix param aggregation for attribute filters * fix: set correct selected attribute * WIP checkbox list * WIP checkbox list * avoid action name conflicts * Checkbox list front end * phpcs * update context on input, navigate on change * fix: attribute selection * dropdown * remove isDeepEqual * add: warning when attribute has no products or no attribute is selected * update type * update type --------- Co-authored-by: David Arenas <[email protected]> Co-authored-by: Luis Herranz <[email protected]>
- Loading branch information
1 parent
1da1fef
commit 7f2f23c
Showing
19 changed files
with
1,111 additions
and
8 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
assets/js/blocks/collection-filters/inner-blocks/attribute-filter/block.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{ | ||
"$schema": "https://schemas.wp.org/trunk/block.json", | ||
"name": "woocommerce/collection-attribute-filter", | ||
"version": "1.0.0", | ||
"title": "Collection Attribute Filter", | ||
"description": "Enable customers to filter the product grid by selecting one or more attributes, such as color.", | ||
"category": "woocommerce", | ||
"keywords": [ | ||
"WooCommerce" | ||
], | ||
"textdomain": "woo-gutenberg-products-block", | ||
"apiVersion": 2, | ||
"ancestor": [ | ||
"woocommerce/collection-filters" | ||
], | ||
"supports": { | ||
"interactivity": true | ||
}, | ||
"usesContext": [ | ||
"collectionData" | ||
], | ||
"attributes": { | ||
"queryParam": { | ||
"type": "object", | ||
"default": {} | ||
}, | ||
"attributeId": { | ||
"type": "number", | ||
"default": 0 | ||
}, | ||
"showCounts": { | ||
"type": "boolean", | ||
"default": false | ||
}, | ||
"queryType": { | ||
"type": "string", | ||
"default": "or" | ||
}, | ||
"displayStyle": { | ||
"type": "string", | ||
"default": "list" | ||
}, | ||
"selectType": { | ||
"type": "string", | ||
"default": "multiple" | ||
}, | ||
"isPreview": { | ||
"type": "boolean", | ||
"default": false | ||
} | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
...s/collection-filters/inner-blocks/attribute-filter/components/attribute-checkbox-list.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import FilterElementLabel from '@woocommerce/base-components/filter-element-label'; | ||
import { CheckboxList } from '@woocommerce/blocks-components'; | ||
import { AttributeTerm } from '@woocommerce/types'; | ||
|
||
type Props = { | ||
attributeTerms: AttributeTerm[]; | ||
showCounts?: boolean; | ||
}; | ||
export const AttributeCheckboxList = ( { | ||
attributeTerms, | ||
showCounts, | ||
}: Props ) => ( | ||
<CheckboxList | ||
className="attribute-checkbox-list" | ||
onChange={ () => null } | ||
options={ attributeTerms.map( ( term ) => ( { | ||
label: ( | ||
<FilterElementLabel | ||
name={ term.name } | ||
count={ showCounts ? term.count : null } | ||
/> | ||
), | ||
value: term.slug, | ||
} ) ) } | ||
/> | ||
); |
25 changes: 25 additions & 0 deletions
25
...blocks/collection-filters/inner-blocks/attribute-filter/components/attribute-dropdown.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import FormTokenField from '@woocommerce/base-components/form-token-field'; | ||
import { __, sprintf } from '@wordpress/i18n'; | ||
import { Icon, chevronDown } from '@wordpress/icons'; | ||
|
||
type Props = { | ||
label: string; | ||
}; | ||
export const AttributeDropdown = ( { label }: Props ) => ( | ||
<div className="attribute-dropdown"> | ||
<FormTokenField | ||
suggestions={ [] } | ||
placeholder={ sprintf( | ||
/* translators: %s attribute name. */ | ||
__( 'Select %s', 'woo-gutenberg-products-block' ), | ||
label | ||
) } | ||
onChange={ () => null } | ||
value={ [] } | ||
/> | ||
<Icon icon={ chevronDown } size={ 30 } /> | ||
</div> | ||
); |
89 changes: 89 additions & 0 deletions
89
...collection-filters/inner-blocks/attribute-filter/components/attribute-select-controls.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { sort } from 'fast-sort'; | ||
import { __, sprintf, _n } from '@wordpress/i18n'; | ||
import { SearchListControl } from '@woocommerce/editor-components/search-list-control'; | ||
import { getSetting } from '@woocommerce/settings'; | ||
import { SearchListItem } from '@woocommerce/editor-components/search-list-control/types'; | ||
import { AttributeSetting } from '@woocommerce/types'; | ||
|
||
const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] ); | ||
|
||
type AttributeSelectControlsProps = { | ||
isCompact: boolean; | ||
setAttributeId: ( id: number ) => void; | ||
attributeId: number; | ||
}; | ||
|
||
export const AttributeSelectControls = ( { | ||
isCompact, | ||
setAttributeId, | ||
attributeId, | ||
}: AttributeSelectControlsProps ) => { | ||
const messages = { | ||
clear: __( 'Clear selected attribute', 'woo-gutenberg-products-block' ), | ||
list: __( 'Product Attributes', 'woo-gutenberg-products-block' ), | ||
noItems: __( | ||
"Your store doesn't have any product attributes.", | ||
'woo-gutenberg-products-block' | ||
), | ||
search: __( | ||
'Search for a product attribute:', | ||
'woo-gutenberg-products-block' | ||
), | ||
selected: ( n: number ) => | ||
sprintf( | ||
/* translators: %d is the number of attributes selected. */ | ||
_n( | ||
'%d attribute selected', | ||
'%d attributes selected', | ||
n, | ||
'woo-gutenberg-products-block' | ||
), | ||
n | ||
), | ||
updated: __( | ||
'Product attribute search results updated.', | ||
'woo-gutenberg-products-block' | ||
), | ||
}; | ||
|
||
const list = sort( | ||
ATTRIBUTES.map( ( item ) => { | ||
return { | ||
id: parseInt( item.attribute_id, 10 ), | ||
name: item.attribute_label, | ||
}; | ||
} ) | ||
).asc( 'name' ); | ||
|
||
const onChange = ( selected: SearchListItem[] ) => { | ||
if ( ! selected || ! selected.length ) { | ||
return; | ||
} | ||
|
||
const selectedId = selected[ 0 ].id; | ||
const productAttribute = ATTRIBUTES.find( | ||
( attribute ) => attribute.attribute_id === selectedId.toString() | ||
); | ||
|
||
if ( ! productAttribute || attributeId === selectedId ) { | ||
return; | ||
} | ||
|
||
setAttributeId( selectedId as number ); | ||
}; | ||
|
||
return ( | ||
<SearchListControl | ||
className="woocommerce-product-attributes" | ||
list={ list } | ||
selected={ list.filter( ( { id } ) => id === attributeId ) } | ||
onChange={ onChange } | ||
messages={ messages } | ||
isSingle | ||
isCompact={ isCompact } | ||
/> | ||
); | ||
}; |
151 changes: 151 additions & 0 deletions
151
...blocks/collection-filters/inner-blocks/attribute-filter/components/inspector-controls.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
import { InspectorControls } from '@wordpress/block-editor'; | ||
import { | ||
PanelBody, | ||
ToggleControl, | ||
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis | ||
__experimentalToggleGroupControl as ToggleGroupControl, | ||
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis | ||
__experimentalToggleGroupControlOption as ToggleGroupControlOption, | ||
} from '@wordpress/components'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { AttributeSelectControls } from './attribute-select-controls'; | ||
import { EditProps } from '../types'; | ||
|
||
export const Inspector = ( { attributes, setAttributes }: EditProps ) => { | ||
const { attributeId, showCounts, queryType, displayStyle, selectType } = | ||
attributes; | ||
return ( | ||
<InspectorControls key="inspector"> | ||
<PanelBody | ||
title={ __( | ||
'Display Settings', | ||
'woo-gutenberg-products-block' | ||
) } | ||
> | ||
<ToggleControl | ||
label={ __( | ||
'Display product count', | ||
'woo-gutenberg-products-block' | ||
) } | ||
checked={ showCounts } | ||
onChange={ () => | ||
setAttributes( { | ||
showCounts: ! showCounts, | ||
} ) | ||
} | ||
/> | ||
<ToggleGroupControl | ||
label={ __( | ||
'Allow selecting multiple options?', | ||
'woo-gutenberg-products-block' | ||
) } | ||
value={ selectType || 'multiple' } | ||
onChange={ ( value: string ) => | ||
setAttributes( { | ||
selectType: value, | ||
} ) | ||
} | ||
className="wc-block-attribute-filter__multiple-toggle" | ||
> | ||
<ToggleGroupControlOption | ||
value="multiple" | ||
label={ __( | ||
'Multiple', | ||
'woo-gutenberg-products-block' | ||
) } | ||
/> | ||
<ToggleGroupControlOption | ||
value="single" | ||
label={ __( 'Single', 'woo-gutenberg-products-block' ) } | ||
/> | ||
</ToggleGroupControl> | ||
{ selectType === 'multiple' && ( | ||
<ToggleGroupControl | ||
label={ __( | ||
'Filter Conditions', | ||
'woo-gutenberg-products-block' | ||
) } | ||
help={ | ||
queryType === 'and' | ||
? __( | ||
'Choose to return filter results for all of the attributes selected.', | ||
'woo-gutenberg-products-block' | ||
) | ||
: __( | ||
'Choose to return filter results for any of the attributes selected.', | ||
'woo-gutenberg-products-block' | ||
) | ||
} | ||
value={ queryType } | ||
onChange={ ( value: string ) => | ||
setAttributes( { | ||
queryType: value, | ||
} ) | ||
} | ||
className="wc-block-attribute-filter__conditions-toggle" | ||
> | ||
<ToggleGroupControlOption | ||
value="and" | ||
label={ __( | ||
'All', | ||
'woo-gutenberg-products-block' | ||
) } | ||
/> | ||
<ToggleGroupControlOption | ||
value="or" | ||
label={ __( | ||
'Any', | ||
'woo-gutenberg-products-block' | ||
) } | ||
/> | ||
</ToggleGroupControl> | ||
) } | ||
<ToggleGroupControl | ||
label={ __( | ||
'Display Style', | ||
'woo-gutenberg-products-block' | ||
) } | ||
value={ displayStyle } | ||
onChange={ ( value: string ) => | ||
setAttributes( { | ||
displayStyle: value, | ||
} ) | ||
} | ||
className="wc-block-attribute-filter__display-toggle" | ||
> | ||
<ToggleGroupControlOption | ||
value="list" | ||
label={ __( 'List', 'woo-gutenberg-products-block' ) } | ||
/> | ||
<ToggleGroupControlOption | ||
value="dropdown" | ||
label={ __( | ||
'Dropdown', | ||
'woo-gutenberg-products-block' | ||
) } | ||
/> | ||
</ToggleGroupControl> | ||
</PanelBody> | ||
<PanelBody | ||
title={ __( | ||
'Content Settings', | ||
'woo-gutenberg-products-block' | ||
) } | ||
initialOpen={ false } | ||
> | ||
<AttributeSelectControls | ||
isCompact={ true } | ||
attributeId={ attributeId } | ||
setAttributes={ setAttributes } | ||
/> | ||
</PanelBody> | ||
</InspectorControls> | ||
); | ||
}; |
Oops, something went wrong.