diff --git a/assets/js/blocks/rating-filter/block.tsx b/assets/js/blocks/rating-filter/block.tsx index 3b9894b07cc..64c8559504a 100644 --- a/assets/js/blocks/rating-filter/block.tsx +++ b/assets/js/blocks/rating-filter/block.tsx @@ -26,7 +26,7 @@ import FilterSubmitButton from '@woocommerce/base-components/filter-submit-butto import FilterResetButton from '@woocommerce/base-components/filter-reset-button'; import FormTokenField from '@woocommerce/base-components/form-token-field'; import { addQueryArgs, removeQueryArgs } from '@wordpress/url'; -import { changeUrl } from '@woocommerce/utils'; +import { changeUrl, normalizeQueryParams } from '@woocommerce/utils'; import classnames from 'classnames'; import { difference } from 'lodash'; import type { ReactElement } from 'react'; @@ -144,7 +144,7 @@ const RatingFilterBlock = ( { QUERY_PARAM_KEY ); - if ( url !== window.location.href ) { + if ( url !== normalizeQueryParams( window.location.href ) ) { changeUrl( url ); } @@ -155,7 +155,7 @@ const RatingFilterBlock = ( { [ QUERY_PARAM_KEY ]: checkedRatings.join( ',' ), } ); - if ( newUrl === window.location.href ) { + if ( newUrl === normalizeQueryParams( window.location.href ) ) { return; } diff --git a/assets/js/blocks/stock-filter/block.tsx b/assets/js/blocks/stock-filter/block.tsx index 37d8dda9da9..12e4dd6433c 100644 --- a/assets/js/blocks/stock-filter/block.tsx +++ b/assets/js/blocks/stock-filter/block.tsx @@ -32,7 +32,11 @@ import isShallowEqual from '@wordpress/is-shallow-equal'; import { decodeEntities } from '@wordpress/html-entities'; import { isBoolean, objectHasProp } from '@woocommerce/types'; import { addQueryArgs, removeQueryArgs } from '@wordpress/url'; -import { changeUrl, PREFIX_QUERY_ARG_FILTER_TYPE } from '@woocommerce/utils'; +import { + changeUrl, + PREFIX_QUERY_ARG_FILTER_TYPE, + normalizeQueryParams, +} from '@woocommerce/utils'; import { difference } from 'lodash'; import classnames from 'classnames'; @@ -224,7 +228,7 @@ const StockStatusFilterBlock = ( { QUERY_PARAM_KEY ); - if ( url !== window.location.href ) { + if ( url !== normalizeQueryParams( window.location.href ) ) { changeUrl( url ); } @@ -235,7 +239,7 @@ const StockStatusFilterBlock = ( { [ QUERY_PARAM_KEY ]: checkedOptions.join( ',' ), } ); - if ( newUrl === window.location.href ) { + if ( newUrl === normalizeQueryParams( window.location.href ) ) { return; } diff --git a/assets/js/utils/filters.ts b/assets/js/utils/filters.ts index 98548288fba..5faf1743bb3 100644 --- a/assets/js/utils/filters.ts +++ b/assets/js/utils/filters.ts @@ -1,7 +1,7 @@ /** * External dependencies */ -import { getQueryArg } from '@wordpress/url'; +import { getQueryArg, getQueryArgs, addQueryArgs } from '@wordpress/url'; import { getSettingWithCoercion } from '@woocommerce/settings'; import { isBoolean } from '@woocommerce/types'; @@ -39,3 +39,13 @@ export function changeUrl( newUrl: string ) { window.history.replaceState( {}, '', newUrl ); } } + +/** + * Run the query params through buildQueryString to normalise the params. + * + * @param {string} url URL to encode the search param from. + */ +export const normalizeQueryParams = ( url: string ) => { + const queryArgs = getQueryArgs( url ); + return addQueryArgs( url, queryArgs ); +}; diff --git a/assets/js/utils/test/filters.js b/assets/js/utils/test/filters.js new file mode 100644 index 00000000000..6fff2418715 --- /dev/null +++ b/assets/js/utils/test/filters.js @@ -0,0 +1,27 @@ +/** + * Internal dependencies + */ +import { normalizeQueryParams } from '../filters'; + +describe( 'normalizeQueryParams', () => { + test( 'does not change url if there is no query params', () => { + const input = 'https://example.com'; + const expected = 'https://example.com'; + + expect( normalizeQueryParams( input ) ).toBe( expected ); + } ); + + test( 'does not change search term if there is no special character', () => { + const input = 'https://example.com?foo=bar&s=asdf1234&baz=qux'; + const expected = 'https://example.com?foo=bar&s=asdf1234&baz=qux'; + + expect( normalizeQueryParams( input ) ).toBe( expected ); + } ); + + test( 'decodes single quote characters', () => { + const input = 'https://example.com?foo=bar%27&s=asd%27f1234&baz=qux%27'; + const expected = "https://example.com?foo=bar'&s=asd'f1234&baz=qux'"; + + expect( normalizeQueryParams( input ) ).toBe( expected ); + } ); +} );