8889841ccontext.ts 0000644 00000001307 15053766355 0006620 0 ustar 00 /**
* External dependencies
*/
import { createContext, useContext } from '@wordpress/element';
/**
* Context consumed by inner blocks.
*/
export type FilterContextProps = {
wrapper?: React.RefObject< HTMLDivElement >;
};
export const FilterBlockContext: React.Context< FilterContextProps > =
createContext< FilterContextProps >( {} );
export const useFilterBlockContext = (): FilterContextProps => {
return useContext( FilterBlockContext );
};
export const useSetWraperVisibility = () => {
const { wrapper } = useFilterBlockContext();
return ( isVisible: boolean ) => {
if ( ! wrapper ) {
return;
}
if ( wrapper.current ) {
wrapper.current.hidden = isVisible ? false : true;
}
};
};
frontend.ts 0000644 00000000665 15053766355 0006761 0 ustar 00 /**
* External dependencies
*/
import { renderParentBlock } from '@woocommerce/atomic-utils';
import { getRegisteredBlockComponents } from '@woocommerce/blocks-registry';
/**
* Internal dependencies
*/
import Block from './block';
renderParentBlock( {
blockName: 'woocommerce/filter-wrapper',
selector: '.wp-block-woocommerce-filter-wrapper',
Block,
blockMap: getRegisteredBlockComponents( 'woocommerce/filter-wrapper' ),
} );
register-components.ts 0000644 00000002632 15053766355 0011145 0 ustar 00 /**
* External dependencies
*/
import { registerBlockComponent } from '@woocommerce/blocks-registry';
import { lazy } from '@wordpress/element';
import { WC_BLOCKS_BUILD_URL } from '@woocommerce/block-settings';
// Modify webpack publicPath at runtime based on location of WordPress Plugin.
// eslint-disable-next-line no-undef,camelcase
__webpack_public_path__ = WC_BLOCKS_BUILD_URL;
registerBlockComponent( {
blockName: 'woocommerce/active-filters',
component: lazy(
() =>
import(
/* webpackChunkName: "active-filters-wrapper" */
'../active-filters/block-wrapper'
)
),
} );
registerBlockComponent( {
blockName: 'woocommerce/price-filter',
component: lazy(
() =>
import(
/* webpackChunkName: "price-filter-wrapper" */
'../price-filter/block-wrapper'
)
),
} );
registerBlockComponent( {
blockName: 'woocommerce/stock-filter',
component: lazy(
() =>
import(
/* webpackChunkName: "stock-filter-wrapper" */
'../stock-filter/block-wrapper'
)
),
} );
registerBlockComponent( {
blockName: 'woocommerce/attribute-filter',
component: lazy(
() =>
import(
/* webpackChunkName: "attribute-filter-wrapper" */
'../attribute-filter/block-wrapper'
)
),
} );
registerBlockComponent( {
blockName: 'woocommerce/rating-filter',
component: lazy(
() =>
import(
/* webpackChunkName: "rating-filter-wrapper" */
'../rating-filter/block-wrapper'
)
),
} );
block.json 0000644 00000000543 15053766355 0006552 0 ustar 00 {
"name": "woocommerce/filter-wrapper",
"version": "1.0.0",
"title": "Filter Block",
"category": "woocommerce",
"keywords": [ "WooCommerce" ],
"attributes": {
"filterType": {
"type": "string"
},
"heading": {
"type": "string"
}
},
"textdomain": "woocommerce",
"apiVersion": 2,
"$schema": "https://schemas.wp.org/trunk/block.json"
}
edit.tsx 0000644 00000001343 15053766355 0006251 0 ustar 00 /**
* External dependencies
*/
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
import type { BlockEditProps } from '@wordpress/blocks';
/**
* Internal dependencies
*/
import { Attributes } from './types';
const Edit = ( { attributes }: BlockEditProps< Attributes > ) => {
const blockProps = useBlockProps();
return (
);
};
export default Edit;
types.ts 0000644 00000000107 15053766355 0006275 0 ustar 00 export interface Attributes {
heading: string;
filterType: string;
}
upgrade.tsx 0000644 00000004131 15053766355 0006751 0 ustar 00 /**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { createBlock } from '@wordpress/blocks';
import type { BlockInstance } from '@wordpress/blocks';
import { useDispatch, useSelect } from '@wordpress/data';
import { Button } from '@wordpress/components';
import { Warning } from '@wordpress/block-editor';
interface UpgradeNoticeProps {
clientId: string;
setAttributes: ( attributes: Record< string, unknown > ) => void;
attributes: Record< string, unknown >;
filterType: undefined | string;
}
export const UpgradeNotice = ( {
clientId,
setAttributes,
filterType,
attributes,
}: UpgradeNoticeProps ) => {
const { replaceBlock } = useDispatch( 'core/block-editor' );
const { heading, headingLevel } = attributes;
const isInsideFilterWrapper = useSelect(
( select ) => {
const { getBlockParentsByBlockName } =
select( 'core/block-editor' );
return (
getBlockParentsByBlockName(
clientId,
'woocommerce/filter-wrapper'
).length > 0
);
},
[ clientId ]
);
const upgradeFilterBlockHandler = () => {
const filterWrapperInnerBlocks: BlockInstance[] = [
createBlock( `woocommerce/${ filterType }`, {
...attributes,
heading: '',
} ),
];
if ( heading && heading !== '' ) {
filterWrapperInnerBlocks.unshift(
createBlock( 'core/heading', {
content: heading,
level: headingLevel ?? 2,
} )
);
}
replaceBlock(
clientId,
createBlock(
'woocommerce/filter-wrapper',
{
heading,
filterType,
},
[ ...filterWrapperInnerBlocks ]
)
);
setAttributes( {
heading: '',
lock: {
remove: true,
},
} );
};
if ( isInsideFilterWrapper || ! filterType ) {
return null;
}
const actions = [
,
];
return (
{ __(
'Filter block: We have improved this block to make styling easier. Upgrade it using the button below.',
'woo-gutenberg-products-block'
) }
);
};
index.tsx 0000644 00000014606 15053766355 0006441 0 ustar 00 /**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { createBlock, registerBlockType } from '@wordpress/blocks';
import type { BlockInstance } from '@wordpress/blocks';
import { toggle } from '@woocommerce/icons';
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
import {
Icon,
category,
currencyDollar,
box,
starEmpty,
} from '@wordpress/icons';
/**
* Internal dependencies
*/
import edit from './edit';
import metadata from './block.json';
const filterBlocksWidgets = [
{
widgetId: 'woocommerce_layered_nav_filters',
name: 'active-filters',
heading: __( 'Active filters', 'woo-gutenberg-products-block' ),
},
{
widgetId: 'woocommerce_price_filter',
name: 'price-filter',
heading: __( 'Filter by price', 'woo-gutenberg-products-block' ),
},
{
widgetId: 'woocommerce_layered_nav',
name: 'attribute-filter',
heading: __( 'Filter by attribute', 'woo-gutenberg-products-block' ),
},
{
widgetId: 'woocommerce_rating_filter',
name: 'rating-filter',
heading: __( 'Filter by rating', 'woo-gutenberg-products-block' ),
},
];
const getTransformAttributes = ( instance, filterType: string ) => {
switch ( filterType ) {
case 'attribute-filter':
return {
attributeId: 0,
showCounts: true,
queryType: instance?.raw?.query_type || 'or',
heading: '',
displayStyle: instance?.raw?.display_type || 'list',
showFilterButton: false,
selectType: instance?.raw?.select_type || 'multiple',
isPreview: false,
};
case 'active-filters':
return {
displayStyle: 'list',
heading: '',
};
case 'price-filter':
return {
heading: '',
showInputFields: false,
showFilterButton: true,
inlineInput: false,
};
default:
return {};
}
};
const isFilterWidget = ( widgetId: string ) =>
filterBlocksWidgets.some( ( item ) => item.widgetId === widgetId );
const getFilterBlockObject = ( widgetId: string ) => {
const filterBlock = filterBlocksWidgets.find(
( item ) => item.widgetId === widgetId
);
return filterBlock;
};
const transformFilterBlock = (
filterType: string,
attributes: Record< string, unknown >,
title: string
) => {
const filterWrapperInnerBlocks: BlockInstance[] = [
createBlock( `woocommerce/${ filterType }`, attributes ),
];
filterWrapperInnerBlocks.unshift(
createBlock( 'core/heading', {
content: title,
level: 3,
} )
);
return createBlock(
'woocommerce/filter-wrapper',
{
filterType,
},
filterWrapperInnerBlocks
);
};
registerBlockType( metadata, {
edit,
save() {
return (
);
},
variations: [
{
name: 'active-filters',
title: __( 'Active Filters', 'woo-gutenberg-products-block' ),
description: __(
'Display the currently active filters.',
'woo-gutenberg-products-block'
),
/**
* We need to handle the isActive function differently for this
* variation. The `attributes` is empty for default variation. So we
* set this variation as active if `filterType` is not passed.
*/
isActive: ( attributes ) =>
attributes.filterType === 'active-filters' ||
! attributes.filterType,
attributes: {
heading: __( 'Active filters', 'woo-gutenberg-products-block' ),
filterType: 'active-filters',
},
icon: {
src: (
),
},
isDefault: true,
},
{
name: 'price-filter',
title: __( 'Filter by Price', 'woo-gutenberg-products-block' ),
description: __(
'Enable customers to filter the product grid by choosing a price range.',
'woo-gutenberg-products-block'
),
isActive: ( attributes ) =>
attributes.filterType === 'price-filter',
attributes: {
filterType: 'price-filter',
heading: __(
'Filter by price',
'woo-gutenberg-products-block'
),
},
icon: {
src: (
),
},
},
{
name: 'stock-filter',
title: __( 'Filter by Stock', 'woo-gutenberg-products-block' ),
description: __(
'Enable customers to filter the product grid by stock status.',
'woo-gutenberg-products-block'
),
isActive: ( attributes ) =>
attributes.filterType === 'stock-filter',
attributes: {
filterType: 'stock-filter',
heading: __(
'Filter by stock status',
'woo-gutenberg-products-block'
),
},
icon: {
src: (
),
},
},
{
name: 'attribute-filter',
title: __( 'Filter by Attribute', 'woo-gutenberg-products-block' ),
description: __(
'Enable customers to filter the product grid by selecting one or more attributes, such as color.',
'woo-gutenberg-products-block'
),
isActive: ( attributes ) =>
attributes.filterType === 'attribute-filter',
attributes: {
filterType: 'attribute-filter',
heading: __(
'Filter by attribute',
'woo-gutenberg-products-block'
),
},
icon: {
src: (
),
},
},
{
name: 'rating-filter',
title: __( 'Filter by Rating', 'woo-gutenberg-products-block' ),
description: __(
'Enable customers to filter the product grid by rating.',
'woo-gutenberg-products-block'
),
isActive: ( attributes ) =>
attributes.filterType === 'rating-filter',
attributes: {
filterType: 'rating-filter',
heading: __(
'Filter by rating',
'woo-gutenberg-products-block'
),
},
icon: {
src: (
),
},
},
],
transforms: {
from: [
{
type: 'block',
blocks: [ 'core/legacy-widget' ],
// We can't transform if raw instance isn't shown in the REST API.
isMatch: ( { idBase, instance } ) =>
isFilterWidget( idBase ) && !! instance?.raw,
transform: ( { idBase, instance } ) => {
const filterBlockObject = getFilterBlockObject( idBase );
if ( ! filterBlockObject ) return null;
return transformFilterBlock(
filterBlockObject.name,
getTransformAttributes(
instance,
filterBlockObject.name
),
instance?.raw?.title || filterBlockObject.heading
);
},
},
],
},
} );
block.tsx 0000644 00000001037 15053766355 0006416 0 ustar 00 /**
* External dependencies
*/
import { useRef } from '@wordpress/element';
/**
* Internal dependencies
*/
import './register-components';
import { FilterBlockContext } from './context';
type Props = {
children: JSX.Element[];
};
const Block = ( { children }: Props ): JSX.Element => {
const wrapper = useRef( null );
return (
{ children }
);
};
export default Block;