Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Make Attribute Filter block compatible with PHP rendered Classic Template block #6204

Merged
merged 11 commits into from
Apr 14, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions assets/js/blocks/attribute-filter/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,50 @@ import isShallowEqual from '@wordpress/is-shallow-equal';
import { decodeEntities } from '@wordpress/html-entities';
import { Notice } from '@wordpress/components';
import classNames from 'classnames';
import { getSetting } from '@woocommerce/settings';
import { addQueryArgs, removeQueryArgs } from '@wordpress/url';

/**
* Internal dependencies
*/
import { getUrlParameter } from '../../utils/filters';
import { getAttributeFromID } from '../../utils/attributes';
import { updateAttributeFilter } from '../../utils/attributes-query';
import { previewAttributeObject, previewOptions } from './preview';
import { useBorderProps } from '../../hooks/style-attributes';
import './style.scss';

/**
* Formats filter values into a string for the URL parameters needed for filtering PHP templates.
*
* @param {string} url Current page URL.
* @param {Array} params Parameters and their constraints.
*
* @return {string} New URL with query parameters in it.
*/
function formatParams( url, params = [] ) {
const paramObject = {};

params.forEach( ( param ) => {
const { attribute, operator, slug } = param;

// Custom filters are prefix with `pa_` so we need to remove this.
const name = attribute.replace( 'pa_', '' );
const values = slug.join( ',' );
const queryType = `query_type_${ name }`;
const type = operator === 'or' ? 'in' : 'and';

// The URL parameter requires the prefix filter_ with the attribute name.
paramObject[ `filter_${ name }` ] = values;
paramObject[ queryType ] = type;
} );

// Clean the URL before we add our new query parameters to it.
const cleanUrl = removeQueryArgs( url, ...Object.keys( paramObject ) );

return addQueryArgs( cleanUrl, paramObject );
}

/**
* Component displaying an attribute filter.
*
Expand All @@ -40,6 +74,14 @@ const AttributeFilterBlock = ( {
attributes: blockAttributes,
isEditor = false,
} ) => {
const filteringForPhpTemplate = getSetting(
'is_rendering_php_template',
''
);
const [ hasSetPhpFilterDefaults, setHasSetPhpFilterDefaults ] = useState(
false
);

const attributeObject =
blockAttributes.isPreview && ! blockAttributes.attributeId
? previewAttributeObject
Expand Down Expand Up @@ -332,6 +374,66 @@ const AttributeFilterBlock = ( {
]
);

/**
* Important: For PHP rendered block templates only.
*
* When we render the PHP block template (e.g. Classic Block) we need to set the default checked values,
* and also update the URL when the filters are clicked/updated.
*/
useEffect( () => {
if ( filteringForPhpTemplate && attributeObject ) {
const defaultAttributeParam = getUrlParameter(
`filter_${ attributeObject.name }`
);
const defaultCheckedValue =
typeof defaultAttributeParam === 'string'
? defaultAttributeParam.split( ',' )
: [];

if ( defaultCheckedValue.length > 0 && checked.length === 0 ) {
setChecked( defaultCheckedValue );
}

const newUrl = formatParams(
window.location.href,
productAttributesQuery
);
if ( window.location.href !== newUrl ) {
window.location.href = newUrl;
}
}
}, [
filteringForPhpTemplate,
productAttributesQuery,
checked.length,
attributeObject,
] );

/**
* Important: For PHP rendered block templates only.
*
* When we set the default parameter values which we get from the URL in the above useEffect(),
* we need to run onSubmit which will set these values in state for the Active Filters block.
*/
useEffect( () => {
if ( filteringForPhpTemplate ) {
if (
checked.length > 0 &&
! hasSetPhpFilterDefaults &&
! attributeTermsLoading
) {
setHasSetPhpFilterDefaults( true );
onSubmit( checked );
}
}
}, [
onSubmit,
filteringForPhpTemplate,
checked,
hasSetPhpFilterDefaults,
attributeTermsLoading,
] );

// Short-circuit if no attribute is selected.
if ( ! attributeObject ) {
if ( isEditor ) {
Expand Down
19 changes: 4 additions & 15 deletions assets/js/blocks/price-filter/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,15 @@ import { useDebouncedCallback } from 'use-debounce';
import PropTypes from 'prop-types';
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
import { getSetting } from '@woocommerce/settings';
import { getQueryArg, addQueryArgs, removeQueryArgs } from '@wordpress/url';
import { addQueryArgs, removeQueryArgs } from '@wordpress/url';

/**
* Internal dependencies
*/
import usePriceConstraints from './use-price-constraints.js';
import { getUrlParameter } from '../../utils/filters';
import './style.scss';

/**
* Returns specified parameter from URL
*
* @param {string} paramName Parameter you want the value of.
*/
function findGetParameter( paramName ) {
if ( ! window ) {
return null;
}
return getQueryArg( window.location.href, paramName );
}

/**
* Formats filter values into a string for the URL parameters needed for filtering PHP templates.
*
Expand Down Expand Up @@ -71,8 +60,8 @@ const PriceFilterBlock = ( { attributes, isEditor = false } ) => {
''
);

const minPriceParam = findGetParameter( 'min_price' );
const maxPriceParam = findGetParameter( 'max_price' );
const minPriceParam = getUrlParameter( 'min_price' );
const maxPriceParam = getUrlParameter( 'max_price' );

const [ minPriceQuery, setMinPriceQuery ] = useQueryStateByKey(
'min_price',
Expand Down
16 changes: 16 additions & 0 deletions assets/js/utils/filters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* External dependencies
*/
import { getQueryArg } from '@wordpress/url';

/**
* Returns specified parameter from URL
*
* @param {string} name Parameter you want the value of.
*/
export function getUrlParameter( name: string ) {
if ( ! window ) {
return null;
}
return getQueryArg( window.location.href, name );
}