[Experimental] Add block text color support to interactivity filter blocks (#43068)

* [Experimental] Render headings as inner blocks of collection filters (#43109)
This commit is contained in:
Sam Seay 2023-12-28 22:06:35 +08:00 committed by GitHub
parent b36023e8aa
commit eabb27c72b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 289 additions and 127 deletions

View File

@ -2,62 +2,25 @@
* External dependencies * External dependencies
*/ */
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor'; import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
import { sprintf, __ } from '@wordpress/i18n';
import { getSetting } from '@woocommerce/settings'; import { getSetting } from '@woocommerce/settings';
import type { AttributeSetting } from '@woocommerce/types'; import type { AttributeSetting } from '@woocommerce/types';
const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] ); const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] );
const firstAttribute = ATTRIBUTES.find( Boolean );
const template = [ const template = [
[ 'woocommerce/collection-active-filters', {} ], [ 'woocommerce/collection-active-filters', {} ],
[
'core/heading',
{
content: __( 'Filter by Price', 'woocommerce' ),
level: 3,
},
],
[ 'woocommerce/collection-price-filter', {} ], [ 'woocommerce/collection-price-filter', {} ],
[
'core/heading',
{
content: __( 'Filter by Stock status', 'woocommerce' ),
level: 3,
},
],
[ 'woocommerce/collection-stock-filter', {} ], [ 'woocommerce/collection-stock-filter', {} ],
[
'core/heading',
{
content: __( 'Filter by Rating', 'woocommerce' ),
level: 3,
},
],
[ 'woocommerce/collection-rating-filter', {} ], [ 'woocommerce/collection-rating-filter', {} ],
]; ];
const firstAttribute = ATTRIBUTES.find( Boolean );
if ( firstAttribute ) { if ( firstAttribute ) {
template.push( template.push( [
[ 'woocommerce/collection-attribute-filter',
'core/heading', { attributeId: parseInt( firstAttribute?.attribute_id, 10 ) },
{ ] );
content: sprintf(
// translators: %s is the attribute label.
__( 'Filter by %s', 'woocommerce' ),
firstAttribute.attribute_label
),
level: 3,
},
],
[
'woocommerce/collection-attribute-filter',
{
attributeId: parseInt( firstAttribute?.attribute_id, 10 ),
},
]
);
} }
const Edit = () => { const Edit = () => {

View File

@ -5,20 +5,18 @@
"title": "Collection Active Filters", "title": "Collection Active Filters",
"description": "Display the currently active filters.", "description": "Display the currently active filters.",
"category": "woocommerce", "category": "woocommerce",
"keywords": [ "keywords": [ "WooCommerce" ],
"WooCommerce"
],
"textdomain": "woocommerce", "textdomain": "woocommerce",
"apiVersion": 2, "apiVersion": 2,
"ancestor": [ "ancestor": [ "woocommerce/collection-filters" ],
"woocommerce/collection-filters"
],
"supports": { "supports": {
"interactivity": true "interactivity": true,
"color": {
"text": true,
"background": false
}
}, },
"usesContext": [ "usesContext": [ "queryId" ],
"queryId"
],
"attributes": { "attributes": {
"displayStyle": { "displayStyle": {
"type": "string", "type": "string",

View File

@ -1,10 +1,11 @@
/** /**
* External dependencies * External dependencies
*/ */
import { useBlockProps } from '@wordpress/block-editor'; import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import classNames from 'classnames'; import classNames from 'classnames';
import { Disabled } from '@wordpress/components'; import { Disabled } from '@wordpress/components';
import { Template } from '@wordpress/blocks';
/** /**
* Internal dependencies * Internal dependencies
@ -20,9 +21,20 @@ const Edit = ( props: EditProps ) => {
className: 'wc-block-active-filters', className: 'wc-block-active-filters',
} ); } );
const template: Template[] = [
[
'core/heading',
{ content: __( 'Active Filters', 'woocommerce' ), level: 3 },
],
];
return ( return (
<div { ...blockProps }> <div { ...blockProps }>
<Inspector { ...props } /> <Inspector { ...props } />
<InnerBlocks
template={ template }
allowedBlocks={ [ 'core/heading' ] }
/>
<Disabled> <Disabled>
<ul <ul
className={ classNames( 'wc-block-active-filters__list', { className={ classNames( 'wc-block-active-filters__list', {

View File

@ -5,6 +5,7 @@ import { registerBlockType } from '@wordpress/blocks';
import { Icon } from '@wordpress/icons'; import { Icon } from '@wordpress/icons';
import { toggle } from '@woocommerce/icons'; import { toggle } from '@woocommerce/icons';
import { isExperimentalBuild } from '@woocommerce/block-settings'; import { isExperimentalBuild } from '@woocommerce/block-settings';
import { InnerBlocks } from '@wordpress/block-editor';
/** /**
* Internal dependencies * Internal dependencies
@ -24,5 +25,6 @@ if ( isExperimentalBuild() ) {
), ),
}, },
edit: Edit, edit: Edit,
save: InnerBlocks.Content,
} ); } );
} }

View File

@ -5,20 +5,18 @@
"title": "Collection Attribute Filter", "title": "Collection Attribute Filter",
"description": "Enable customers to filter the product grid by selecting one or more attributes, such as color.", "description": "Enable customers to filter the product grid by selecting one or more attributes, such as color.",
"category": "woocommerce", "category": "woocommerce",
"keywords": [ "keywords": [ "WooCommerce" ],
"WooCommerce"
],
"textdomain": "woocommerce", "textdomain": "woocommerce",
"apiVersion": 2, "apiVersion": 2,
"ancestor": [ "ancestor": [ "woocommerce/collection-filters" ],
"woocommerce/collection-filters"
],
"supports": { "supports": {
"interactivity": true "interactivity": true,
"color": {
"text": true,
"background": false
}
}, },
"usesContext": [ "usesContext": [ "collectionData" ],
"collectionData"
],
"attributes": { "attributes": {
"queryParam": { "queryParam": {
"type": "object", "type": "object",

View File

@ -1,25 +1,38 @@
/** /**
* External dependencies * External dependencies
*/ */
import styled from '@emotion/styled';
import FormTokenField from '@woocommerce/base-components/form-token-field'; import FormTokenField from '@woocommerce/base-components/form-token-field';
import { __, sprintf } from '@wordpress/i18n'; import { __, sprintf } from '@wordpress/i18n';
import { Icon, chevronDown } from '@wordpress/icons'; import { Icon, chevronDown } from '@wordpress/icons';
type Props = { type Props = {
label: string; label: string;
textColor: string;
};
export const AttributeDropdown = ( { label, textColor }: Props ) => {
const StyledFormTokenField = textColor
? styled( FormTokenField )`
.components-form-token-field__input::placeholder {
color: ${ textColor } !important;
}
`
: FormTokenField;
return (
<div className="wc-block-attribute-filter style-dropdown">
<StyledFormTokenField
suggestions={ [] }
placeholder={ sprintf(
/* translators: %s attribute name. */
__( 'Select %s', 'woocommerce' ),
label
) }
onChange={ () => null }
value={ [] }
/>
<Icon icon={ chevronDown } size={ 30 } />
</div>
);
}; };
export const AttributeDropdown = ( { label }: Props ) => (
<div className="wc-block-attribute-filter style-dropdown">
<FormTokenField
suggestions={ [] }
placeholder={ sprintf(
/* translators: %s attribute name. */
__( 'Select %s', 'woocommerce' ),
label
) }
onChange={ () => null }
value={ [] }
/>
<Icon icon={ chevronDown } size={ 30 } />
</div>
);

View File

@ -1,9 +1,13 @@
/** /**
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __, sprintf } from '@wordpress/i18n';
import { useEffect, useState } from '@wordpress/element'; import { useEffect, useState } from '@wordpress/element';
import { BlockControls, useBlockProps } from '@wordpress/block-editor'; import {
BlockControls,
InnerBlocks,
useBlockProps,
} from '@wordpress/block-editor';
import { getSetting } from '@woocommerce/settings'; import { getSetting } from '@woocommerce/settings';
import { import {
useCollection, useCollection,
@ -21,6 +25,7 @@ import {
withSpokenMessages, withSpokenMessages,
Notice, Notice,
} from '@wordpress/components'; } from '@wordpress/components';
import { Template } from '@wordpress/blocks';
/** /**
* Internal dependencies * Internal dependencies
@ -36,6 +41,8 @@ import { Inspector } from './components/inspector-controls';
import { AttributeCheckboxList } from './components/attribute-checkbox-list'; import { AttributeCheckboxList } from './components/attribute-checkbox-list';
import { AttributeDropdown } from './components/attribute-dropdown'; import { AttributeDropdown } from './components/attribute-dropdown';
import './style.scss'; import './style.scss';
import { extractBuiltInColor } from '../../utils';
import { useStyleProps } from '../../../../base/hooks';
const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] ); const ATTRIBUTES = getSetting< AttributeSetting[] >( 'attributes', [] );
@ -55,6 +62,13 @@ const Edit = ( props: EditProps ) => {
showCounts, showCounts,
} = blockAttributes; } = blockAttributes;
const { className, style } = useStyleProps( props.attributes );
const builtInColor = extractBuiltInColor( className );
const textColor = builtInColor
? `var(--wp--preset--color--${ builtInColor })`
: style.color;
const attributeObject = getAttributeFromId( attributeId ); const attributeObject = getAttributeFromId( attributeId );
const [ isEditing, setIsEditing ] = useState( const [ isEditing, setIsEditing ] = useState(
@ -83,6 +97,22 @@ const Edit = ( props: EditProps ) => {
const blockProps = useBlockProps(); const blockProps = useBlockProps();
const template: Template[] = [
[
'core/heading',
{
content: attributeObject
? sprintf(
// translators: %s is the attribute label.
__( 'Filter by %s', 'woocommerce' ),
attributeObject.label
)
: __( 'Filter Products by Attribute', 'woocommerce' ),
level: 3,
},
],
];
useEffect( () => { useEffect( () => {
if ( ! attributeObject?.taxonomy ) { if ( ! attributeObject?.taxonomy ) {
return; return;
@ -226,6 +256,10 @@ const Edit = ( props: EditProps ) => {
return ( return (
<Wrapper> <Wrapper>
<Inspector { ...props } /> <Inspector { ...props } />
<InnerBlocks
template={ template }
allowedBlocks={ [ 'core/heading' ] }
/>
<Disabled> <Disabled>
{ displayStyle === 'dropdown' ? ( { displayStyle === 'dropdown' ? (
<AttributeDropdown <AttributeDropdown
@ -233,6 +267,7 @@ const Edit = ( props: EditProps ) => {
attributeObject.label || attributeObject.label ||
__( 'attribute', 'woocommerce' ) __( 'attribute', 'woocommerce' )
} }
textColor={ textColor || '' }
/> />
) : ( ) : (
<AttributeCheckboxList <AttributeCheckboxList

View File

@ -3,6 +3,7 @@
*/ */
import { registerBlockType } from '@wordpress/blocks'; import { registerBlockType } from '@wordpress/blocks';
import { isExperimentalBuild } from '@woocommerce/block-settings'; import { isExperimentalBuild } from '@woocommerce/block-settings';
import { InnerBlocks } from '@wordpress/block-editor';
/** /**
* Internal dependencies * Internal dependencies
@ -14,5 +15,6 @@ import Edit from './edit';
if ( isExperimentalBuild() ) { if ( isExperimentalBuild() ) {
registerBlockType( metadata, { registerBlockType( metadata, {
edit: Edit, edit: Edit,
save: InnerBlocks.Content,
} ); } );
} }

View File

@ -1,8 +1,10 @@
/** /**
* External dependencies * External dependencies
*/ */
import { useBlockProps } from '@wordpress/block-editor'; import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
import classNames from 'classnames'; import classNames from 'classnames';
import { __ } from '@wordpress/i18n';
import { Template } from '@wordpress/blocks';
/** /**
* Internal dependencies * Internal dependencies
@ -20,9 +22,20 @@ const Edit = ( props: EditProps ) => {
} ), } ),
} ); } );
const template: Template[] = [
[
'core/heading',
{ content: __( 'Filter by Price', 'woocommerce' ), level: 3 },
],
];
return ( return (
<div { ...blockProps }> <div { ...blockProps }>
<Inspector { ...props } /> <Inspector { ...props } />
<InnerBlocks
template={ template }
allowedBlocks={ [ 'core/heading' ] }
/>
<PriceSlider { ...props } /> <PriceSlider { ...props } />
</div> </div>
); );

View File

@ -4,6 +4,7 @@
import { registerBlockType } from '@wordpress/blocks'; import { registerBlockType } from '@wordpress/blocks';
import { Icon, currencyDollar } from '@wordpress/icons'; import { Icon, currencyDollar } from '@wordpress/icons';
import { isExperimentalBuild } from '@woocommerce/block-settings'; import { isExperimentalBuild } from '@woocommerce/block-settings';
import { InnerBlocks } from '@wordpress/block-editor';
/** /**
* Internal dependencies * Internal dependencies
@ -23,5 +24,6 @@ if ( isExperimentalBuild() ) {
), ),
}, },
edit: Edit, edit: Edit,
save: InnerBlocks.Content,
} ); } );
} }

View File

@ -6,7 +6,11 @@
"category": "woocommerce", "category": "woocommerce",
"keywords": [ "WooCommerce" ], "keywords": [ "WooCommerce" ],
"supports": { "supports": {
"interactivity": true "interactivity": true,
"color": {
"background": false,
"text": true
}
}, },
"ancestor": [ "woocommerce/collection-filters" ], "ancestor": [ "woocommerce/collection-filters" ],
"usesContext": [ "collectionData" ], "usesContext": [ "collectionData" ],

View File

@ -4,8 +4,8 @@
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { Icon, chevronDown } from '@wordpress/icons'; import { Icon, chevronDown } from '@wordpress/icons';
import classnames from 'classnames'; import classnames from 'classnames';
import { useBlockProps } from '@wordpress/block-editor'; import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
import type { BlockEditProps } from '@wordpress/blocks'; import type { BlockEditProps, Template } from '@wordpress/blocks';
import Rating, { import Rating, {
RatingValues, RatingValues,
} from '@woocommerce/base-components/product-rating'; } from '@woocommerce/base-components/product-rating';
@ -20,6 +20,8 @@ import { useState, useMemo, useEffect } from '@wordpress/element';
import { CheckboxList } from '@woocommerce/blocks-components'; import { CheckboxList } from '@woocommerce/blocks-components';
import FormTokenField from '@woocommerce/base-components/form-token-field'; import FormTokenField from '@woocommerce/base-components/form-token-field';
import { Disabled, Notice, withSpokenMessages } from '@wordpress/components'; import { Disabled, Notice, withSpokenMessages } from '@wordpress/components';
import { useStyleProps } from '@woocommerce/base-hooks';
import styled from '@emotion/styled';
/** /**
* Internal dependencies * Internal dependencies
@ -31,6 +33,7 @@ import { formatSlug, getActiveFilters, generateUniqueId } from './utils';
import { useSetWraperVisibility } from '../../../filter-wrapper/context'; import { useSetWraperVisibility } from '../../../filter-wrapper/context';
import './editor.scss'; import './editor.scss';
import { Inspector } from '../attribute-filter/components/inspector-controls'; import { Inspector } from '../attribute-filter/components/inspector-controls';
import { extractBuiltInColor } from '../../utils';
const NoRatings = () => ( const NoRatings = () => (
<Notice status="warning" isDismissible={ false }> <Notice status="warning" isDismissible={ false }>
@ -47,10 +50,32 @@ const Edit = ( props: BlockEditProps< Attributes > ) => {
const { className } = props.attributes; const { className } = props.attributes;
const blockAttributes = props.attributes; const blockAttributes = props.attributes;
const { className: styleClass, style } = useStyleProps( props.attributes );
const builtInColor = extractBuiltInColor( styleClass );
const textColor = builtInColor
? `var(--wp--preset--color--${ builtInColor })`
: style.color;
const StyledFormTokenField = textColor
? styled( FormTokenField )`
.components-form-token-field__input::placeholder {
color: ${ textColor } !important;
}
`
: FormTokenField;
const blockProps = useBlockProps( { const blockProps = useBlockProps( {
className: classnames( 'wc-block-rating-filter', className ), className: classnames( 'wc-block-rating-filter', className ),
} ); } );
const template: Template[] = [
[
'core/heading',
{ content: __( 'Filter by Rating', 'woocommerce' ), level: 3 },
],
];
const isEditor = true; const isEditor = true;
const setWrapperVisibility = useSetWraperVisibility(); const setWrapperVisibility = useSetWraperVisibility();
@ -179,6 +204,10 @@ const Edit = ( props: BlockEditProps< Attributes > ) => {
<> <>
<Inspector { ...props } /> <Inspector { ...props } />
<div { ...blockProps }> <div { ...blockProps }>
<InnerBlocks
template={ template }
allowedBlocks={ [ 'core/heading' ] }
/>
<Disabled> <Disabled>
{ displayNoProductRatingsNotice && <NoRatings /> } { displayNoProductRatingsNotice && <NoRatings /> }
<div <div
@ -192,7 +221,7 @@ const Edit = ( props: BlockEditProps< Attributes > ) => {
> >
{ blockAttributes.displayStyle === 'dropdown' ? ( { blockAttributes.displayStyle === 'dropdown' ? (
<> <>
<FormTokenField <StyledFormTokenField
key={ remountKey } key={ remountKey }
className={ classnames( { className={ classnames( {
'single-selection': ! multiple, 'single-selection': ! multiple,

View File

@ -3,15 +3,13 @@
*/ */
import { registerBlockType } from '@wordpress/blocks'; import { registerBlockType } from '@wordpress/blocks';
import { Icon, starEmpty } from '@wordpress/icons'; import { Icon, starEmpty } from '@wordpress/icons';
import classNames from 'classnames'; import { InnerBlocks } from '@wordpress/block-editor';
import { useBlockProps } from '@wordpress/block-editor';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import edit from './edit'; import edit from './edit';
import metadata from './block.json'; import metadata from './block.json';
import type { Attributes } from './types';
registerBlockType( metadata, { registerBlockType( metadata, {
icon: { icon: {
@ -26,16 +24,5 @@ registerBlockType( metadata, {
...metadata.attributes, ...metadata.attributes,
}, },
edit, edit,
// Save the props to post content. save: InnerBlocks.Content,
save( { attributes }: { attributes: Attributes } ) {
const { className } = attributes;
return (
<div
{ ...useBlockProps.save( {
className: classNames( 'is-loading', className ),
} ) }
/>
);
},
} ); } );

View File

@ -1,14 +1,18 @@
{ {
"name": "woocommerce/collection-stock-filter", "name": "woocommerce/collection-stock-filter",
"version": "1.0.0", "version": "1.0.0",
"title": "Stock Filter", "title": "Collection Stock Filter",
"description": "Enable customers to filter the product collection by stock status.", "description": "Enable customers to filter the product collection by stock status.",
"category": "woocommerce", "category": "woocommerce",
"keywords": [ "WooCommerce", "filter", "stock" ], "keywords": [ "WooCommerce", "filter", "stock" ],
"supports": { "supports": {
"interactivity": true, "interactivity": true,
"html": false, "html": false,
"multiple": false "multiple": false,
"color": {
"text": true,
"background": false
}
}, },
"attributes": { "attributes": {
"className": { "className": {

View File

@ -3,22 +3,25 @@
*/ */
import { useMemo } from '@wordpress/element'; import { useMemo } from '@wordpress/element';
import classnames from 'classnames'; import classnames from 'classnames';
import { useBlockProps } from '@wordpress/block-editor'; import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
import { Disabled } from '@wordpress/components'; import { Disabled } from '@wordpress/components';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { Icon, chevronDown } from '@wordpress/icons'; import { Icon, chevronDown } from '@wordpress/icons';
import { CheckboxList } from '@woocommerce/blocks-components'; import { CheckboxList } from '@woocommerce/blocks-components';
import Label from '@woocommerce/base-components/filter-element-label'; import Label from '@woocommerce/base-components/filter-element-label';
import FormTokenField from '@woocommerce/base-components/form-token-field'; import FormTokenField from '@woocommerce/base-components/form-token-field';
import type { BlockEditProps } from '@wordpress/blocks'; import type { BlockEditProps, Template } from '@wordpress/blocks';
import { getSetting } from '@woocommerce/settings'; import { getSetting } from '@woocommerce/settings';
import { useCollectionData } from '@woocommerce/base-context/hooks'; import { useCollectionData } from '@woocommerce/base-context/hooks';
import { useStyleProps } from '@woocommerce/base-hooks';
import styled from '@emotion/styled';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { BlockProps } from './types'; import { BlockProps } from './types';
import { Inspector } from './components/inspector'; import { Inspector } from './components/inspector';
import { extractBuiltInColor } from '../../utils';
type CollectionData = { type CollectionData = {
// attribute_counts: null | unknown; // attribute_counts: null | unknown;
@ -40,6 +43,31 @@ const Edit = ( props: BlockEditProps< BlockProps > ) => {
), ),
} ); } );
const template: Template[] = [
[
'core/heading',
{
content: __( 'Filter by Stock Status', 'woocommerce' ),
level: 3,
},
],
];
const { className, style } = useStyleProps( props.attributes );
const builtInColor = extractBuiltInColor( className );
const textColor = builtInColor
? `var(--wp--preset--color--${ builtInColor })`
: style.color;
const StyledFormTokenField = textColor
? styled( FormTokenField )`
.components-form-token-field__input::placeholder {
color: ${ textColor } !important;
}
`
: FormTokenField;
const { showCounts, displayStyle } = props.attributes; const { showCounts, displayStyle } = props.attributes;
const stockStatusOptions: Record< string, string > = getSetting( const stockStatusOptions: Record< string, string > = getSetting(
'stockStatusOptions', 'stockStatusOptions',
@ -77,6 +105,10 @@ const Edit = ( props: BlockEditProps< BlockProps > ) => {
{ {
<div { ...blockProps }> <div { ...blockProps }>
<Inspector { ...props } /> <Inspector { ...props } />
<InnerBlocks
template={ template }
allowedBlocks={ [ 'core/heading' ] }
/>
<Disabled> <Disabled>
<div <div
className={ classnames( className={ classnames(
@ -89,7 +121,7 @@ const Edit = ( props: BlockEditProps< BlockProps > ) => {
> >
{ displayStyle === 'dropdown' ? ( { displayStyle === 'dropdown' ? (
<> <>
<FormTokenField <StyledFormTokenField
className={ classnames( { className={ classnames( {
'single-selection': true, 'single-selection': true,
'is-loading': false, 'is-loading': false,

View File

@ -4,6 +4,7 @@
import { registerBlockType } from '@wordpress/blocks'; import { registerBlockType } from '@wordpress/blocks';
import { Icon, box } from '@wordpress/icons'; import { Icon, box } from '@wordpress/icons';
import { isExperimentalBuild } from '@woocommerce/block-settings'; import { isExperimentalBuild } from '@woocommerce/block-settings';
import { InnerBlocks } from '@wordpress/block-editor';
/** /**
* Internal dependencies * Internal dependencies
@ -23,5 +24,6 @@ if ( isExperimentalBuild() ) {
), ),
}, },
edit, edit,
save: InnerBlocks.Content,
} ); } );
} }

View File

@ -0,0 +1,12 @@
/**
* Extracts the built-in color from a block class name string if it exists.
* Returns null if no built-in color is found.
*
* @param blockClassString The block class name string.
* @return {string|null} The color name or null if no built-in color is found.
*/
export const extractBuiltInColor = ( blockClassString: string ) => {
const regex = /has-(?!link|text|background)([a-z-]+)-color/;
const match = blockClassString.match( regex );
return match ? match[ 1 ] : null;
};

View File

@ -0,0 +1,4 @@
Significance: patch
Type: add
Comment: Add support for text color to experimental filter blocks

View File

@ -49,7 +49,7 @@ final class CollectionActiveFilters extends AbstractBlock {
$active_filters = apply_filters( 'collection_active_filters_data', array(), $this->get_filter_query_params( $query_id ) ); $active_filters = apply_filters( 'collection_active_filters_data', array(), $this->get_filter_query_params( $query_id ) );
if ( empty( $active_filters ) ) { if ( empty( $active_filters ) ) {
return $content; return '';
} }
$context = array( $context = array(
@ -68,8 +68,8 @@ final class CollectionActiveFilters extends AbstractBlock {
ob_start(); ob_start();
?> ?>
<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> <div <?php echo $wrapper_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<div <?php echo $wrapper_attributes; ?>> <?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<ul class="wc-block-active-filters__list %3$s"> <ul class="wc-block-active-filters__list %3$s">
<?php foreach ( $active_filters as $filter ) : ?> <?php foreach ( $active_filters as $filter ) : ?>
<li> <li>

View File

@ -2,6 +2,7 @@
namespace Automattic\WooCommerce\Blocks\BlockTypes; namespace Automattic\WooCommerce\Blocks\BlockTypes;
use Automattic\WooCommerce\Blocks\InteractivityComponents\Dropdown; use Automattic\WooCommerce\Blocks\InteractivityComponents\Dropdown;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
/** /**
* CollectionAttributeFilter class. * CollectionAttributeFilter class.
@ -132,7 +133,7 @@ final class CollectionAttributeFilter extends AbstractBlock {
empty( $block->context['collectionData']['attribute_counts'] ) || empty( $block->context['collectionData']['attribute_counts'] ) ||
empty( $attributes['attributeId'] ) empty( $attributes['attributeId'] )
) { ) {
return $content; return '';
} }
$product_attribute = wc_get_attribute( $attributes['attributeId'] ); $product_attribute = wc_get_attribute( $attributes['attributeId'] );
@ -179,13 +180,14 @@ final class CollectionAttributeFilter extends AbstractBlock {
); );
return sprintf( return sprintf(
'<div %1$s>%2$s</div>', '<div %1$s>%2$s%3$s</div>',
get_block_wrapper_attributes( get_block_wrapper_attributes(
array( array(
'data-wc-context' => wp_json_encode( $context ), 'data-wc-context' => wp_json_encode( $context ),
'data-wc-interactive' => wp_json_encode( array( 'namespace' => 'woocommerce/collection-attribute-filter' ) ), 'data-wc-interactive' => wp_json_encode( array( 'namespace' => 'woocommerce/collection-attribute-filter' ) ),
) )
), ),
$content,
$filter_content $filter_content
); );
} }
@ -197,6 +199,9 @@ final class CollectionAttributeFilter extends AbstractBlock {
* @param bool $attributes Block attributes. * @param bool $attributes Block attributes.
*/ */
private function render_attribute_dropdown( $options, $attributes ) { private function render_attribute_dropdown( $options, $attributes ) {
$text_color_class_and_style = StyleAttributesUtils::get_text_color_class_and_style( $attributes );
$text_color = $text_color_class_and_style['value'] ?? '';
$list_items = array(); $list_items = array();
$selected_item = array(); $selected_item = array();
@ -218,6 +223,7 @@ final class CollectionAttributeFilter extends AbstractBlock {
'items' => $list_items, 'items' => $list_items,
'action' => 'woocommerce/collection-attribute-filter::actions.navigate', 'action' => 'woocommerce/collection-attribute-filter::actions.navigate',
'selected_item' => $selected_item, 'selected_item' => $selected_item,
'text_color' => $text_color,
) )
); );
} }

View File

@ -116,7 +116,7 @@ final class CollectionPriceFilter extends AbstractBlock {
empty( $block->context['collectionData'] ) || empty( $block->context['collectionData'] ) ||
empty( $block->context['collectionData']['price_range'] ) empty( $block->context['collectionData']['price_range'] )
) { ) {
return $content; return '';
} }
$price_range = $block->context['collectionData']['price_range']; $price_range = $block->context['collectionData']['price_range'];
@ -147,7 +147,7 @@ final class CollectionPriceFilter extends AbstractBlock {
// Max range shouldn't be 0. // Max range shouldn't be 0.
if ( ! $max_range ) { if ( ! $max_range ) {
return $content; return '';
} }
// CSS variables for the range bar style. // CSS variables for the range bar style.
@ -197,6 +197,7 @@ final class CollectionPriceFilter extends AbstractBlock {
ob_start(); ob_start();
?> ?>
<div <?php echo $wrapper_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>> <div <?php echo $wrapper_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<div data-wc-context="<?php echo esc_attr( wp_json_encode( $data ) ); ?>" > <div data-wc-context="<?php echo esc_attr( wp_json_encode( $data ) ); ?>" >
<div <div
class="range" class="range"

View File

@ -3,6 +3,7 @@ namespace Automattic\WooCommerce\Blocks\BlockTypes;
use Automattic\WooCommerce\Blocks\InteractivityComponents\CheckboxList; use Automattic\WooCommerce\Blocks\InteractivityComponents\CheckboxList;
use Automattic\WooCommerce\Blocks\InteractivityComponents\Dropdown; use Automattic\WooCommerce\Blocks\InteractivityComponents\Dropdown;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
/** /**
* Collection Rating Filter Block * Collection Rating Filter Block
@ -110,10 +111,17 @@ final class CollectionRatingFilter extends AbstractBlock {
return ''; return '';
} }
$text_color_class_and_style = StyleAttributesUtils::get_text_color_class_and_style( $attributes );
$text_color = $text_color_class_and_style['value'] ?? '';
$rating_counts = $block->context['collectionData']['rating_counts'] ?? array(); $rating_counts = $block->context['collectionData']['rating_counts'] ?? array();
$display_style = $attributes['displayStyle'] ?? 'list'; $display_style = $attributes['displayStyle'] ?? 'list';
$show_counts = $attributes['showCounts'] ?? false; $show_counts = $attributes['showCounts'] ?? false;
if ( empty( $rating_counts ) ) {
return '';
}
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here. // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here.
$selected_ratings_query_param = isset( $_GET[ self::RATING_FILTER_QUERY_VAR ] ) ? sanitize_text_field( wp_unslash( $_GET[ self::RATING_FILTER_QUERY_VAR ] ) ) : ''; $selected_ratings_query_param = isset( $_GET[ self::RATING_FILTER_QUERY_VAR ] ) ? sanitize_text_field( wp_unslash( $_GET[ self::RATING_FILTER_QUERY_VAR ] ) ) : '';
@ -130,15 +138,17 @@ final class CollectionRatingFilter extends AbstractBlock {
'on_change' => 'woocommerce/collection-rating-filter::actions.onCheckboxChange', 'on_change' => 'woocommerce/collection-rating-filter::actions.onCheckboxChange',
) )
) : Dropdown::render( ) : Dropdown::render(
$this->get_dropdown_props( $rating_counts, $selected_ratings_query_param, $show_counts, $attributes['selectType'] ) $this->get_dropdown_props( $rating_counts, $selected_ratings_query_param, $show_counts, $attributes['selectType'], $text_color )
); );
return sprintf( return sprintf(
'<div %1$s> '<div %1$s>
<div class="wc-block-rating-filter__controls">%2$s</div> %2$s
<div class="wc-block-rating-filter__controls">%3$s</div>
<div class="wc-block-rating-filter__actions"></div> <div class="wc-block-rating-filter__actions"></div>
</div>', </div>',
$wrapper_attributes, $wrapper_attributes,
$content,
$input $input
); );
} }
@ -209,9 +219,10 @@ final class CollectionRatingFilter extends AbstractBlock {
* @param mixed $selected_ratings_query The url query param for selected ratings. * @param mixed $selected_ratings_query The url query param for selected ratings.
* @param bool $show_counts Whether to show the counts. * @param bool $show_counts Whether to show the counts.
* @param string $select_type The select type. (single|multiple). * @param string $select_type The select type. (single|multiple).
* @param string $text_color The text color.
* @return array<array-key, array> * @return array<array-key, array>
*/ */
private function get_dropdown_props( $rating_counts, $selected_ratings_query, $show_counts, $select_type ) { private function get_dropdown_props( $rating_counts, $selected_ratings_query, $show_counts, $select_type, $text_color ) {
$ratings_array = explode( ',', $selected_ratings_query ); $ratings_array = explode( ',', $selected_ratings_query );
$selected_items = array_reduce( $selected_items = array_reduce(
@ -249,6 +260,7 @@ final class CollectionRatingFilter extends AbstractBlock {
'select_type' => $select_type, 'select_type' => $select_type,
'selected_items' => $selected_items, 'selected_items' => $selected_items,
'action' => 'woocommerce/collection-rating-filter::actions.onDropdownChange', 'action' => 'woocommerce/collection-rating-filter::actions.onDropdownChange',
'text_color' => $text_color,
); );
} }
} }

View File

@ -2,6 +2,7 @@
namespace Automattic\WooCommerce\Blocks\BlockTypes; namespace Automattic\WooCommerce\Blocks\BlockTypes;
use Automattic\WooCommerce\Blocks\InteractivityComponents\Dropdown; use Automattic\WooCommerce\Blocks\InteractivityComponents\Dropdown;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
/** /**
* CollectionStockFilter class. * CollectionStockFilter class.
@ -127,10 +128,12 @@ final class CollectionStockFilter extends AbstractBlock {
return sprintf( return sprintf(
'<div %1$s> '<div %1$s>
<div class="wc-block-stock-filter__controls">%2$s</div> %2$s
<div class="wc-block-stock-filter__controls">%3$s</div>
<div class="wc-block-stock-filter__actions"></div> <div class="wc-block-stock-filter__actions"></div>
</div>', </div>',
$wrapper_attributes, $wrapper_attributes,
$content,
$this->get_stock_filter_html( $stock_status_counts, $attributes ), $this->get_stock_filter_html( $stock_status_counts, $attributes ),
); );
} }
@ -147,6 +150,9 @@ final class CollectionStockFilter extends AbstractBlock {
$show_counts = $attributes['showCounts'] ?? false; $show_counts = $attributes['showCounts'] ?? false;
$stock_statuses = wc_get_product_stock_status_options(); $stock_statuses = wc_get_product_stock_status_options();
$text_color_class_and_style = StyleAttributesUtils::get_text_color_class_and_style( $attributes );
$text_color = $text_color_class_and_style['value'] ?? '';
// check the url params to select initial item on page load. // check the url params to select initial item on page load.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here. // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verification is not required here.
$selected_stock_status = isset( $_GET[ self::STOCK_STATUS_QUERY_VAR ] ) ? sanitize_text_field( wp_unslash( $_GET[ self::STOCK_STATUS_QUERY_VAR ] ) ) : ''; $selected_stock_status = isset( $_GET[ self::STOCK_STATUS_QUERY_VAR ] ) ? sanitize_text_field( wp_unslash( $_GET[ self::STOCK_STATUS_QUERY_VAR ] ) ) : '';
@ -236,6 +242,7 @@ final class CollectionStockFilter extends AbstractBlock {
'items' => $list_items, 'items' => $list_items,
'action' => 'woocommerce/collection-stock-filter::actions.navigate', 'action' => 'woocommerce/collection-stock-filter::actions.navigate',
'selected_item' => $selected_item, 'selected_item' => $selected_item,
'text_color' => $text_color,
) )
); );
?> ?>

View File

@ -18,9 +18,10 @@ class Dropdown {
wp_enqueue_script( 'wc-interactivity-dropdown' ); wp_enqueue_script( 'wc-interactivity-dropdown' );
wp_enqueue_style( 'wc-interactivity-dropdown' ); wp_enqueue_style( 'wc-interactivity-dropdown' );
$select_type = $props['select_type'] ?? 'single'; $select_type = $props['select_type'] ?? 'single';
$selected_items = $props['selected_items'] ?? array();
$selected_items = $props['selected_items'] ?? array(); $text_color = $props['text_color'] ?? 'inherit';
$text_color_style = "color: {$text_color};";
// Items should be an array of objects with a label and value property. // Items should be an array of objects with a label and value property.
$items = $props['items'] ?? array(); $items = $props['items'] ?? array();
@ -31,11 +32,17 @@ class Dropdown {
'selectType' => $select_type, 'selectType' => $select_type,
); );
$action = $props['action'] ?? ''; $action = $props['action'] ?? '';
$namespace = wp_json_encode( array( 'namespace' => 'woocommerce/interactivity-dropdown' ) );
$namespace = wp_json_encode( array( 'namespace' => 'woocommerce/interactivity-dropdown' ) );
$wrapper_class = 'multiple' === $select_type ? '' : 'single-selection'; $wrapper_class = 'multiple' === $select_type ? '' : 'single-selection';
$input_id = wp_unique_id( 'wc-interactivity-dropdown-input-' );
wp_add_inline_style(
'wc-interactivity-dropdown',
"#$input_id::placeholder {
$text_color_style
}"
);
ob_start(); ob_start();
?> ?>
@ -57,6 +64,7 @@ class Dropdown {
<span <span
class="components-form-token-field__token-text" class="components-form-token-field__token-text"
data-wc-text="context.item.label" data-wc-text="context.item.label"
style="<?php echo esc_attr( $text_color_style ); ?>"
></span> ></span>
<button <button
type="button" type="button"
@ -76,7 +84,10 @@ class Dropdown {
data-wc-key="<?php echo esc_attr( $selected['label'] ); ?>" data-wc-key="<?php echo esc_attr( $selected['label'] ); ?>"
data-wc-each-child data-wc-each-child
> >
<span class="components-form-token-field__token-text"> <span
class="components-form-token-field__token-text"
style="<?php echo esc_attr( $text_color_style ); ?>"
>
<?php echo esc_html( $selected['label'] ); ?> <?php echo esc_html( $selected['label'] ); ?>
</span> </span>
<button <button
@ -89,8 +100,20 @@ class Dropdown {
</button> </button>
</span> </span>
<?php } ?> <?php } ?>
<?php } ?> <?php } ?>
<input id="components-form-token-input-1" type="text" autocomplete="off" data-wc-bind--placeholder="state.placeholderText" class="components-form-token-field__input" role="combobox" aria-expanded="false" aria-autocomplete="list" aria-describedby="components-form-token-suggestions-howto-1" value="" data-wc-key="input"> <input
id="<?php echo esc_attr( $input_id ); ?>"
readonly
type="text"
autocomplete="off"
data-wc-bind--placeholder="state.placeholderText"
class="components-form-token-field__input"
role="combobox"
aria-expanded="false"
aria-autocomplete="list"
value=""
data-wc-key="input"
>
<ul hidden data-wc-bind--hidden="!context.isOpen" class="components-form-token-field__suggestions-list" id="components-form-token-suggestions-1" role="listbox" data-wc-key="ul"> <ul hidden data-wc-bind--hidden="!context.isOpen" class="components-form-token-field__suggestions-list" id="components-form-token-suggestions-1" role="listbox" data-wc-key="ul">
<?php <?php
foreach ( $items as $item ) : foreach ( $items as $item ) :
@ -104,6 +127,7 @@ class Dropdown {
class="components-form-token-field__suggestion" class="components-form-token-field__suggestion"
data-wc-bind--aria-selected="state.isSelected" data-wc-bind--aria-selected="state.isSelected"
data-wc-context='<?php echo wp_json_encode( $context ); ?>' data-wc-context='<?php echo wp_json_encode( $context ); ?>'
style="<?php echo esc_attr( $text_color_style ); ?>"
> >
<?php // This attribute supports HTML so should be sanitized by caller. ?> <?php // This attribute supports HTML so should be sanitized by caller. ?>
<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> <?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>