Skip to content

Commit

Permalink
add taxonomy filter block
Browse files Browse the repository at this point in the history
  • Loading branch information
dinhtungdu committed Mar 7, 2024
1 parent 6304792 commit 703d80b
Show file tree
Hide file tree
Showing 17 changed files with 998 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export const BLOCK_NAME_MAP = {
'stock-filter': 'woocommerce/product-filter-stock-status',
'rating-filter': 'woocommerce/product-filter-rating',
'attribute-filter': 'woocommerce/product-filter-attribute',
'taxonomy-filter': 'woocommerce/product-filter-taxonomy',
};
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,26 @@ if ( isExperimentalBuild() ) {
),
},
},
{
name: 'product-filter-taxonomy',
title: __( 'Product Filter: Taxonomy (Beta)', 'woocommerce' ),
description: __(
'Enable customers to filter the product collection by selecting one or more taxonomy, such as category.',
'woocommerce'
),
attributes: {
filterType: 'taxonomy-filter',
heading: __( 'Filter by Taxonomy', 'woocommerce' ),
},
icon: {
src: (
<Icon
icon={ category }
className="wc-block-editor-components-block-icon"
/>
),
},
},
],
transforms: {
from: [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"name": "woocommerce/product-filter-taxonomy",
"version": "1.0.0",
"title": "Product Filter: Taxonomy (Beta)",
"description": "Enable customers to filter the product grid by selecting one or more taxonomy, such as category.",
"category": "woocommerce",
"keywords": [
"WooCommerce"
],
"textdomain": "woocommerce",
"apiVersion": 2,
"ancestor": [
"woocommerce/product-filter"
],
"supports": {
"interactivity": true,
"inserter": false,
"color": {
"text": true,
"background": false
}
},
"usesContext": [
"query",
"queryId"
],
"attributes": {
"taxonomyName": {
"type": "string",
"default": ""
},
"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
}
}
}
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="wc-block-attribute-filter style-list"
onChange={ () => null }
options={ attributeTerms.map( ( term ) => ( {
label: (
<FilterElementLabel
name={ term.name }
count={ showCounts ? term.count : null }
/>
),
value: term.slug,
} ) ) }
/>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { Icon, chevronDown } from '@wordpress/icons';

/**
* Internal dependencies
*/
import { PreviewDropdown } from '../../components/preview-dropdown';

type Props = {
label: string;
};

export const AttributeDropdown = ( { label }: Props ) => {
return (
<div className="wc-block-attribute-filter style-dropdown">
<PreviewDropdown
placeholder={ sprintf(
/* translators: %s attribute name. */
__( 'Select %s', 'woocommerce' ),
label
) }
/>
<Icon icon={ chevronDown } size={ 30 } />
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* 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', 'woocommerce' ),
list: __( 'Product Attributes', 'woocommerce' ),
noItems: __(
"Your store doesn't have any product attributes.",
'woocommerce'
),
search: __( 'Search for a product attribute:', 'woocommerce' ),
selected: ( n: number ) =>
sprintf(
/* translators: %d is the number of attributes selected. */
_n(
'%d attribute selected',
'%d attributes selected',
n,
'woocommerce'
),
n
),
updated: __(
'Product attribute search results updated.',
'woocommerce'
),
};

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 }
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { InspectorControls } from '@wordpress/block-editor';
import {
PanelBody,
ToggleControl,
SelectControl,
// @ts-expect-error - no types.
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToggleGroupControl as ToggleGroupControl,
// @ts-expect-error - no types.
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToggleGroupControlOption as ToggleGroupControlOption,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import { EditProps } from '../types';

export const Inspector = ( { attributes, setAttributes }: EditProps ) => {
const { taxonomyName, showCounts, queryType, displayStyle, selectType } =
attributes;

const taxonomies = useSelect( ( select ) => {
const { getTaxonomies } = select( 'core' );
return getTaxonomies( {
type: 'product',
per_page: -1,
} );
} );

console.log( taxonomies );

return (
<InspectorControls key="inspector">
<PanelBody title={ __( 'Filter Settings', 'woocommerce' ) }>
{ taxonomies && (
<SelectControl
label={ __( 'Select taxonomy', 'woocommerce' ) }
value={ taxonomyName }
options={ taxonomies.map( ( item ) => ( {
value: item.slug,
label: item.name,
} ) ) }
onChange={ ( newTaxonomy ) =>
setAttributes( { taxonomyName: newTaxonomy } )
}
/>
) }
<ToggleControl
label={ __( 'Display product count', 'woocommerce' ) }
checked={ showCounts }
onChange={ () =>
setAttributes( {
showCounts: ! showCounts,
} )
}
/>
<ToggleGroupControl
label={ __(
'Allow selecting multiple options?',
'woocommerce'
) }
value={ selectType || 'multiple' }
onChange={ ( value: string ) =>
setAttributes( {
selectType: value,
} )
}
className="wc-block-attribute-filter__multiple-toggle"
>
<ToggleGroupControlOption
value="multiple"
label={ __( 'Multiple', 'woocommerce' ) }
/>
<ToggleGroupControlOption
value="single"
label={ __( 'Single', 'woocommerce' ) }
/>
</ToggleGroupControl>
{ selectType === 'multiple' && (
<ToggleGroupControl
label={ __( 'Filter Conditions', 'woocommerce' ) }
help={
queryType === 'and'
? __(
'Choose to return filter results for all of the attributes selected.',
'woocommerce'
)
: __(
'Choose to return filter results for any of the attributes selected.',
'woocommerce'
)
}
value={ queryType }
onChange={ ( value: string ) =>
setAttributes( {
queryType: value,
} )
}
className="wc-block-attribute-filter__conditions-toggle"
>
<ToggleGroupControlOption
value="and"
label={ __( 'All', 'woocommerce' ) }
/>
<ToggleGroupControlOption
value="or"
label={ __( 'Any', 'woocommerce' ) }
/>
</ToggleGroupControl>
) }
<ToggleGroupControl
label={ __( 'Display Style', 'woocommerce' ) }
value={ displayStyle }
onChange={ ( value: string ) =>
setAttributes( {
displayStyle: value,
} )
}
className="wc-block-attribute-filter__display-toggle"
>
<ToggleGroupControlOption
value="list"
label={ __( 'List', 'woocommerce' ) }
/>
<ToggleGroupControlOption
value="dropdown"
label={ __( 'Dropdown', 'woocommerce' ) }
/>
</ToggleGroupControl>
</PanelBody>
</InspectorControls>
);
};

0 comments on commit 703d80b

Please sign in to comment.