Make Filter Products by Stock block compatible with PHP rendered Classic Template block (https://github.com/woocommerce/woocommerce-blocks/pull/6261)
* Enable Attribute Filter block to work with the PHP rendered Classic Template block * Check for presence of option before rendering it * improve filter product by attribute * fix pagination problem * fix check when two filter block with same attribute are used * fix filter by stock for PHP templates * fix naming and comment * Update filter key in ClassicTemplate * Update stock filter block for PHP templates when the filter button is enabled * Remove unused useEffect and fix ESLint error * Set active stock filter and track using local state * ESLint fix * Remove unncessary dependencies from useEffect Co-authored-by: tjcafferkey <tjcafferkey@gmail.com>
This commit is contained in:
parent
268d6e1a34
commit
881c202717
|
@ -22,6 +22,10 @@ import classNames from 'classnames';
|
|||
import { getSettingWithCoercion } from '@woocommerce/settings';
|
||||
import { getQueryArgs, removeQueryArgs } from '@wordpress/url';
|
||||
import { isBoolean, isString } from '@woocommerce/types';
|
||||
import {
|
||||
PREFIX_QUERY_ARG_FILTER_TYPE,
|
||||
PREFIX_QUERY_ARG_QUERY_TYPE,
|
||||
} from '@woocommerce/utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -36,6 +40,7 @@ import {
|
|||
getActiveFilters,
|
||||
areAllFiltersRemoved,
|
||||
isQueryArgsEqual,
|
||||
parseTaxonomyToGenerateURL,
|
||||
} from './utils';
|
||||
|
||||
/**
|
||||
|
@ -392,9 +397,20 @@ const AttributeFilterBlock = ( {
|
|||
getQueryArgs( window.location.href )
|
||||
);
|
||||
|
||||
const parsedTaxonomy = parseTaxonomyToGenerateURL(
|
||||
attributeObject?.taxonomy
|
||||
);
|
||||
|
||||
const url = currentQueryArgKeys.reduce(
|
||||
( currentUrl, queryArg ) =>
|
||||
removeQueryArgs( currentUrl, queryArg ),
|
||||
queryArg.includes(
|
||||
PREFIX_QUERY_ARG_QUERY_TYPE + parsedTaxonomy
|
||||
) ||
|
||||
queryArg.includes(
|
||||
PREFIX_QUERY_ARG_FILTER_TYPE + parsedTaxonomy
|
||||
)
|
||||
? removeQueryArgs( currentUrl, queryArg )
|
||||
: currentUrl,
|
||||
window.location.href
|
||||
);
|
||||
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
*/
|
||||
import { addQueryArgs, removeQueryArgs } from '@wordpress/url';
|
||||
import { QueryArgs } from '@wordpress/url/build-types/get-query-args';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { getUrlParameter } from '../../utils/filters';
|
||||
import {
|
||||
getUrlParameter,
|
||||
PREFIX_QUERY_ARG_FILTER_TYPE,
|
||||
PREFIX_QUERY_ARG_QUERY_TYPE,
|
||||
} from '@woocommerce/utils';
|
||||
|
||||
interface Param {
|
||||
attribute: string;
|
||||
|
@ -15,6 +15,9 @@ interface Param {
|
|||
slug: Array< string >;
|
||||
}
|
||||
|
||||
export const parseTaxonomyToGenerateURL = ( taxonomy: string ) =>
|
||||
taxonomy.replace( 'pa_', '' );
|
||||
|
||||
export const formatParams = ( url: string, params: Array< Param > = [] ) => {
|
||||
const paramObject: Record< string, string > = {};
|
||||
|
||||
|
@ -22,13 +25,13 @@ export const formatParams = ( url: string, params: Array< Param > = [] ) => {
|
|||
const { attribute, slug, operator } = param;
|
||||
|
||||
// Custom filters are prefix with `pa_` so we need to remove this.
|
||||
const name = attribute.replace( 'pa_', '' );
|
||||
const name = parseTaxonomyToGenerateURL( attribute );
|
||||
const values = slug.join( ',' );
|
||||
const queryType = `query_type_${ name }`;
|
||||
const queryType = `${ PREFIX_QUERY_ARG_QUERY_TYPE }${ name }`;
|
||||
const type = operator === 'in' ? 'or' : 'and';
|
||||
|
||||
// The URL parameter requires the prefix filter_ with the attribute name.
|
||||
paramObject[ `filter_${ name }` ] = values;
|
||||
paramObject[ `${ PREFIX_QUERY_ARG_FILTER_TYPE }${ name }` ] = values;
|
||||
paramObject[ queryType ] = type;
|
||||
} );
|
||||
|
||||
|
|
|
@ -9,19 +9,25 @@ import {
|
|||
useQueryStateByContext,
|
||||
useCollectionData,
|
||||
} from '@woocommerce/base-context/hooks';
|
||||
import { getSetting } from '@woocommerce/settings';
|
||||
import { getSetting, getSettingWithCoercion } from '@woocommerce/settings';
|
||||
import { useCallback, useEffect, useState, useMemo } from '@wordpress/element';
|
||||
import CheckboxList from '@woocommerce/base-components/checkbox-list';
|
||||
import FilterSubmitButton from '@woocommerce/base-components/filter-submit-button';
|
||||
import Label from '@woocommerce/base-components/filter-element-label';
|
||||
import isShallowEqual from '@wordpress/is-shallow-equal';
|
||||
import { decodeEntities } from '@wordpress/html-entities';
|
||||
import { isBoolean } from '@woocommerce/types';
|
||||
import { addQueryArgs, removeQueryArgs } from '@wordpress/url';
|
||||
import { PREFIX_QUERY_ARG_FILTER_TYPE } from '@woocommerce/utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { previewOptions } from './preview';
|
||||
import './style.scss';
|
||||
import { getActiveFilters } from './utils';
|
||||
|
||||
export const QUERY_PARAM_KEY = PREFIX_QUERY_ARG_FILTER_TYPE + 'stock_status';
|
||||
|
||||
/**
|
||||
* Component displaying an stock status filter.
|
||||
|
@ -34,6 +40,16 @@ const StockStatusFilterBlock = ( {
|
|||
attributes: blockAttributes,
|
||||
isEditor = false,
|
||||
} ) => {
|
||||
const filteringForPhpTemplate = getSettingWithCoercion(
|
||||
'is_rendering_php_template',
|
||||
false,
|
||||
isBoolean
|
||||
);
|
||||
|
||||
const [ hasSetPhpFilterDefaults, setHasSetPhpFilterDefaults ] = useState(
|
||||
false
|
||||
);
|
||||
|
||||
const [ hideOutOfStockItems ] = useState(
|
||||
getSetting( 'hideOutOfStockItems', false )
|
||||
);
|
||||
|
@ -46,7 +62,9 @@ const StockStatusFilterBlock = ( {
|
|||
: { outofstock, ...otherStockStatusOptions }
|
||||
);
|
||||
|
||||
const [ checked, setChecked ] = useState( [] );
|
||||
const [ checked, setChecked ] = useState(
|
||||
getActiveFilters( STOCK_STATUS_OPTIONS, QUERY_PARAM_KEY )
|
||||
);
|
||||
const [ displayedOptions, setDisplayedOptions ] = useState(
|
||||
blockAttributes.isPreview ? previewOptions : []
|
||||
);
|
||||
|
@ -148,6 +166,33 @@ const StockStatusFilterBlock = ( {
|
|||
initialOptions,
|
||||
] );
|
||||
|
||||
/**
|
||||
* Used to redirect the page when filters are changed so templates using the Classic Template block can filter.
|
||||
*
|
||||
* @param {Array} checkedOptions Array of checked stock options.
|
||||
*/
|
||||
const redirectPageForPhpTemplate = ( checkedOptions ) => {
|
||||
if ( checkedOptions.length === 0 ) {
|
||||
const url = removeQueryArgs(
|
||||
window.location.href,
|
||||
QUERY_PARAM_KEY
|
||||
);
|
||||
|
||||
if ( url !== window.location.href ) {
|
||||
window.location.href = url;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const newUrl = addQueryArgs( window.location.href, {
|
||||
[ QUERY_PARAM_KEY ]: checkedOptions.join( ',' ),
|
||||
} );
|
||||
|
||||
if ( newUrl !== window.location.href ) {
|
||||
window.location.href = newUrl;
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = useCallback(
|
||||
( isChecked ) => {
|
||||
if ( isEditor ) {
|
||||
|
@ -156,8 +201,17 @@ const StockStatusFilterBlock = ( {
|
|||
if ( isChecked ) {
|
||||
setProductStockStatusQuery( checked );
|
||||
}
|
||||
// For PHP templates when the filter button is enabled.
|
||||
if ( filteringForPhpTemplate ) {
|
||||
redirectPageForPhpTemplate( checked );
|
||||
}
|
||||
},
|
||||
[ isEditor, setProductStockStatusQuery, checked ]
|
||||
[
|
||||
isEditor,
|
||||
setProductStockStatusQuery,
|
||||
checked,
|
||||
filteringForPhpTemplate,
|
||||
]
|
||||
);
|
||||
|
||||
// Track checked STATE changes - if state changes, update the query.
|
||||
|
@ -183,6 +237,37 @@ const StockStatusFilterBlock = ( {
|
|||
}
|
||||
}, [ checked, currentCheckedQuery, previousCheckedQuery ] );
|
||||
|
||||
/**
|
||||
* Important: For PHP rendered block templates only.
|
||||
*/
|
||||
useEffect( () => {
|
||||
if ( filteringForPhpTemplate ) {
|
||||
setChecked( checked );
|
||||
// Only automatically redirect if the filter button is not active.
|
||||
if ( ! blockAttributes.showFilterButton ) {
|
||||
redirectPageForPhpTemplate( checked );
|
||||
}
|
||||
}
|
||||
}, [ filteringForPhpTemplate, checked, blockAttributes.showFilterButton ] );
|
||||
|
||||
/**
|
||||
* Important: For PHP rendered block templates only.
|
||||
*/
|
||||
useEffect( () => {
|
||||
if ( ! hasSetPhpFilterDefaults && filteringForPhpTemplate ) {
|
||||
setProductStockStatusQuery(
|
||||
getActiveFilters( STOCK_STATUS_OPTIONS, QUERY_PARAM_KEY )
|
||||
);
|
||||
setHasSetPhpFilterDefaults( true );
|
||||
}
|
||||
}, [
|
||||
STOCK_STATUS_OPTIONS,
|
||||
filteringForPhpTemplate,
|
||||
setProductStockStatusQuery,
|
||||
hasSetPhpFilterDefaults,
|
||||
setHasSetPhpFilterDefaults,
|
||||
] );
|
||||
|
||||
/**
|
||||
* When a checkbox in the list changes, update state.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { isString } from '@woocommerce/types';
|
||||
import { getUrlParameter } from '@woocommerce/utils';
|
||||
|
||||
export const getActiveFilters = (
|
||||
filters: Record< string, string >,
|
||||
queryParamKey: 'filter_stock_status'
|
||||
) => {
|
||||
const params = getUrlParameter( queryParamKey );
|
||||
|
||||
if ( ! params ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parsedParams = isString( params ) ? params.split( ',' ) : params;
|
||||
|
||||
return Object.keys( filters ).filter( ( filter ) =>
|
||||
parsedParams.includes( filter )
|
||||
);
|
||||
};
|
|
@ -8,6 +8,10 @@ import { getQueryArg } from '@wordpress/url';
|
|||
*
|
||||
* @param {string} name Parameter you want the value of.
|
||||
*/
|
||||
|
||||
export const PREFIX_QUERY_ARG_QUERY_TYPE = 'query_type_';
|
||||
export const PREFIX_QUERY_ARG_FILTER_TYPE = 'filter_';
|
||||
|
||||
export function getUrlParameter( name: string ) {
|
||||
if ( ! window ) {
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
export * from './attributes-query';
|
||||
export * from './attributes';
|
||||
export * from './filters';
|
||||
export * from './global-style';
|
||||
export * from './notices';
|
||||
export * from './products';
|
||||
export * from './shared-attributes';
|
||||
export * from './useThrottle';
|
|
@ -87,6 +87,7 @@ const getAlias = ( options = {} ) => {
|
|||
`../assets/js/${ pathPart }previews/`
|
||||
),
|
||||
'@woocommerce/types': path.resolve( __dirname, `../assets/js/types/` ),
|
||||
'@woocommerce/utils': path.resolve( __dirname, `../assets/js/utils/` ),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -24,12 +24,17 @@ class ClassicTemplate extends AbstractDynamicBlock {
|
|||
*/
|
||||
protected $api_version = '2';
|
||||
|
||||
const FILTER_PRODUCTS_BY_STOCK_QUERY_PARAM = 'filter_stock_status';
|
||||
|
||||
/**
|
||||
* Initialize this block.
|
||||
*/
|
||||
protected function initialize() {
|
||||
parent::initialize();
|
||||
add_filter( 'render_block', array( $this, 'add_alignment_class_to_wrapper' ), 10, 2 );
|
||||
add_filter( 'query_vars', array( $this, 'add_query_vars_filter' ) );
|
||||
add_filter( 'woocommerce_product_query_meta_query', array( $this, 'filter_products_by_stock' ), 10, 2 );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -254,4 +259,51 @@ class ClassicTemplate extends AbstractDynamicBlock {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filter products by stock status when as query param there is "filter_stock_status"
|
||||
*
|
||||
* @param array $meta_query Meta query.
|
||||
* @return array
|
||||
*/
|
||||
public function filter_products_by_stock( $meta_query ) {
|
||||
if ( is_admin() ) {
|
||||
return $meta_query;
|
||||
}
|
||||
|
||||
$stock_status = array_keys( wc_get_product_stock_status_options() );
|
||||
$values = get_query_var( self::FILTER_PRODUCTS_BY_STOCK_QUERY_PARAM );
|
||||
|
||||
$values_to_array = explode( ',', $values );
|
||||
|
||||
$filtered_values = array_filter(
|
||||
$values_to_array,
|
||||
function( $value ) use ( $stock_status ) {
|
||||
return in_array( $value, $stock_status, true );
|
||||
}
|
||||
);
|
||||
|
||||
if ( ! empty( $filtered_values ) ) {
|
||||
|
||||
$meta_query[] = array(
|
||||
'key' => '_stock_status',
|
||||
'value' => $filtered_values,
|
||||
'compare' => 'IN',
|
||||
);
|
||||
}
|
||||
return $meta_query;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add custom query params
|
||||
*
|
||||
* @param array $vars Query vars.
|
||||
* @return array Query vars.
|
||||
*/
|
||||
public function add_query_vars_filter( $vars ) {
|
||||
$vars[] = self::FILTER_PRODUCTS_BY_STOCK_QUERY_PARAM;
|
||||
return $vars;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
"@woocommerce/shared-context": "assets/js/shared/context",
|
||||
"@woocommerce/shared-hocs": "assets/js/shared/hocs",
|
||||
"@woocommerce/blocks-test-utils": "tests/utils",
|
||||
"@woocommerce/types": "assets/js/types"
|
||||
"@woocommerce/types": "assets/js/types",
|
||||
"@woocommerce/utils": "assets/js/utils"
|
||||
},
|
||||
"setupFiles": [
|
||||
"@wordpress/jest-preset-default/scripts/setup-globals.js",
|
||||
|
|
|
@ -55,7 +55,8 @@
|
|||
"@woocommerce/shared-hocs": [ "assets/js/shared/hocs" ],
|
||||
"@woocommerce/type-defs/*": [ "assets/js/types/type-defs/*" ],
|
||||
"@woocommerce/types": [ "assets/js/types" ],
|
||||
"@woocommerce/storybook-controls": [ "storybook/custom-controls" ]
|
||||
"@woocommerce/storybook-controls": [ "storybook/custom-controls" ],
|
||||
"@woocommerce/utils": [ "assets/js/utils" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue