hooks_use-hijack-wp-menu.js
import { React, ReactRouter } from '@gravityforms/libraries';
const { useEffect } = React;
const { useNavigate } = ReactRouter;
/**
* @function getSearchParamsObjFromKeys
* @description Get a search params object from an array of keys and search params provided.
*
* @since 4.0.2
*
* @param {Array|string} keys The keys to get from the search params.
* @param {URLSearchParams} searchParams The search params to get the keys from.
*
* @return {object} The search params object.
*/
const getSearchParamsObjFromKeys = ( keys = [], searchParams = null ) => {
if ( ! searchParams || ! keys.length ) {
return {};
}
if ( Array.isArray( keys ) ) {
return keys.reduce( ( acc, key ) => {
acc[ key ] = searchParams.get( key );
return acc;
}, {} );
}
return { [ keys ]: searchParams.get( keys ) };
};
/**
* @function addCurrentToMenuItem
* @description Add the current class and attributes to a menu item.
*
* @since 4.0.2
*
* @param {HTMLElement} item The menu item to add the current class and attributes to.
*/
const addCurrentToMenuItem = ( item ) => {
item.classList.add( 'current' );
const itemLink = item.querySelector( 'a' );
itemLink.classList.add( 'current' );
itemLink.setAttribute( 'aria-current', 'page' );
};
/**
* @function removeCurrentFromMenuItem
* @description Remove the current class and attributes from a menu item.
*
* @since 4.0.2
*
* @param {HTMLElement} item The menu item to remove the current class and attributes from.
*/
const removeCurrentFromMenuItem = ( item ) => {
item.classList.remove( 'current' );
const itemLink = item.querySelector( 'a' );
itemLink.classList.remove( 'current' );
itemLink.removeAttribute( 'aria-current' );
};
/**
* @function useHijackWpMenu
* @description Hijacks the click event on the menu.
*
* @since 4.0.2
*
* @param {string} menuId The ID of the menu to hijack.
* @param {Array|string} paramKeys The keys to get from the search params.
* @param {Function} setSearchParams The function to set the search params.
*/
const useHijackWpMenu = ( menuId = '', paramKeys = [], setSearchParams = () => {} ) => {
const navigate = useNavigate();
useEffect( () => {
const menu = document.getElementById( menuId );
if ( ! menu ) {
return;
}
/**
* @function hijackMenuClick
* @description Hijacks the click event on the menu.
*
* @since 4.0.2
*
* @param {Event} event The click event.
*/
const hijackMenuClick = ( event ) => {
event.preventDefault();
const link = event.currentTarget;
const href = link.getAttribute( 'href' );
const menuItems = menu.querySelectorAll( 'li:not(.wp-submenu-head)' );
menuItems.forEach( removeCurrentFromMenuItem );
if ( link.classList.contains( 'menu-top' ) ) {
// Link is a top-level menu item, update classes and aria attributes.
menuItems.forEach( ( item ) => {
if ( item.querySelector( 'a' )?.getAttribute( 'href' ) !== href ) {
return;
}
addCurrentToMenuItem( item );
} );
} else {
// Link is a submenu item, update classes and aria attributes.
addCurrentToMenuItem( link.parentElement );
}
const linkSearchParams = new URLSearchParams( href.split( '?' )[ 1 ] );
const newSearchParams = getSearchParamsObjFromKeys( paramKeys, linkSearchParams );
setSearchParams( newSearchParams );
navigate( `?${ linkSearchParams.toString() }`, { replace: true } );
};
const menuLinks = menu.querySelectorAll( 'a' );
menuLinks.forEach( ( link ) => {
link.addEventListener( 'click', hijackMenuClick );
} );
return () => {
menuLinks.forEach( ( link ) => {
link.removeEventListener( 'click', hijackMenuClick );
} );
};
}, [ menuId, paramKeys, setSearchParams, navigate ] );
};
export default useHijackWpMenu;