Category Filter works on Desktop but not on Mobile (AJAX issue)
-
Hi,
I’m having an issue with the category filter when using custom JS/PHP on a Lay Theme site.On desktop, everything works perfectly — my custom overlay menu triggers the .lay-thumbnailgrid-filter-anchor elements correctly, and the product grid filters instantly via AJAX (as expected).
On mobile, the exact same logic does not work:
the URL changes correctly (e.g. /all-products/#category-chairs)
sometimes I briefly see the correct filtered grid
but then Lay AJAX resets the grid and goes back to All
the click simulation on .lay-thumbnailgrid-filter-anchor is ignored
even forcing reload doesn't persist the category state
So the problem seems to be related to Lay’s mobile AJAX page transitions, which appear to override the filter state after the DOM gets replaced.
My question:
Is there a supported way to trigger category filtering on mobile via JS? -
hello i need the link and can you provide the custom code u used?
-
Hi Armin, thanks for your reply! Here is the link to the page where the issue happens: https://mediumspringgreen-bison-933621.hostingersite.com/all-products/
-
add_shortcode('resina_lay_filter_accordion', function($atts){ $atts = shortcode_atts([ 'title' => '', ], $atts); ob_start(); ?> <div class="resina-cat-accordion-wrap"> <?php if ( !empty($atts['title']) ) : ?> <div class="resina-cat-accordion-title"> <?php echo esc_html($atts['title']); ?> </div> <?php endif; ?> <div class="resina-cat-accordion" data-resina-cat-accordion> <!-- JS costruisce qui tutto l'accordion --> </div> </div> <?php return ob_get_clean(); }); add_action('wp_footer', function(){ ?> <script> (function(){ const RESINA_PRODUCTS_URL = '/all-products/'; const RESINA_CAT_LABELS = { "lamps": "Lamps", "chandelier": "Chandelier", "floor-lamps": "Floor lamps", "table-lamps": "Table lamps", "applique": "Applique", "tables": "Tables", "dining-tables": "Dining tables", "side-tables": "Side tables", "desk": "Desk", "carts-bar-carts":"Carts and Bar carts", "sittings": "Seatings", "chairs": "Chairs", "sofa": "Sofas", "armchairs": "Armchairs", "lounge-chairs": "Lounge Chairs", "storage": "Storage", "bookcases": "Bookcases", "sideboards": "Sideboards", "cabinets": "Cabinets", "wardrobes": "Wardrobes", "hang-clothes": "Hang clothes", "mirrors": "Mirror", "floor-mirrors": "Floor mirrors", "wall-mirrors": "Wall mirrors", "table-mirrors": "Table mirrors", "decor": "Decor", "poster": "Poster", "art": "Art", "home-decor": "Home decor" }; const RESINA_GROUPS = [ { label: "Lamps", slugs: ["lamps","chandelier","floor-lamps","table-lamps","applique"] }, { label: "Tables", slugs: ["tables","dining-tables","side-tables","desk","carts-bar-carts"] }, { label: "Seatings", slugs: ["sittings","chairs","sofa","armchairs","lounge-chairs"] }, { label: "Storage", slugs: ["storage","bookcases","sideboards","cabinets","wardrobes","hang-clothes"] }, { label: "Mirrors", slugs: ["mirrors","floor-mirrors","wall-mirrors","table-mirrors"] }, { label: "Decor", slugs: ["decor","poster","art","home-decor"] } ]; function getAnchors(){ return Array.from(document.querySelectorAll('.lay-thumbnailgrid-filter-anchor')); } function findAllAnchor(anchors){ return anchors.find(a => a.getAttribute('data-slug') === 'all') || anchors.find(a => a.getAttribute('data-id') === '0'); } function clickLay(el){ if(!el) return; const opts = { bubbles:true, cancelable:true, view:window }; const fire = (type) => { try{ if(type.startsWith('pointer') && window.PointerEvent){ el.dispatchEvent(new PointerEvent(type, opts)); } else { el.dispatchEvent(new MouseEvent(type, opts)); } }catch(e){} }; try{ el.focus({preventScroll:true}); }catch(e){} try{ el.scrollIntoView({block:'nearest', inline:'nearest'}); }catch(e){} try{ el.click(); }catch(e){} fire('pointerdown'); fire('mousedown'); fire('pointerup'); fire('mouseup'); fire('click'); setTimeout(function(){ try{ el.click(); }catch(e){} fire('pointerdown'); fire('mousedown'); fire('pointerup'); fire('mouseup'); fire('click'); }, 120); } function normalizePath(urlOrPath){ urlOrPath = urlOrPath.replace(/^https?:\/\/[^/]+/,''); urlOrPath = urlOrPath.split('#')[0].split('?')[0]; return urlOrPath.replace(/\/+$/,'') || '/'; } function isOnProductsPage(){ const current = normalizePath(window.location.pathname); const products = normalizePath(RESINA_PRODUCTS_URL); return current === products; } function closeOverlay(){ try{ const closeBtn = document.querySelector( '.lay-overlay-close, .overlay-close, [data-overlay-close]' ); if(closeBtn){ closeBtn.click(); } }catch(e){} try{ document.body.classList.remove('lay-overlay-open','overlay-open','open'); }catch(e){} } function initAccordions(){ document.querySelectorAll('[data-resina-cat-accordion]').forEach(function(container){ if(container.dataset.resinaBuilt === '1') return; container.dataset.resinaBuilt = '1'; const frag = document.createDocumentFragment(); const allBtn = document.createElement('button'); allBtn.type = 'button'; allBtn.className = 'rca-all-link'; allBtn.textContent = 'All products'; allBtn.dataset.slug = ''; frag.appendChild(allBtn); RESINA_GROUPS.forEach(group=>{ const item = document.createElement('div'); item.className = 'rca-item'; const toggle = document.createElement('button'); toggle.type = 'button'; toggle.className = 'rca-toggle'; const labelSpan = document.createElement('span'); labelSpan.className = 'rca-label'; labelSpan.textContent = group.label; const iconSpan = document.createElement('span'); iconSpan.className = 'rca-icon'; iconSpan.textContent = '+'; toggle.appendChild(labelSpan); toggle.appendChild(iconSpan); const panel = document.createElement('div'); panel.className = 'rca-panel'; group.slugs.forEach(slug=>{ if(!(slug in RESINA_CAT_LABELS)) return; const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'rca-link'; btn.textContent = RESINA_CAT_LABELS[slug]; btn.dataset.slug = slug; panel.appendChild(btn); }); item.appendChild(toggle); item.appendChild(panel); frag.appendChild(item); }); container.appendChild(frag); }); } document.addEventListener('click', function(e){ // Toggle gruppo const toggle = e.target.closest('.resina-cat-accordion .rca-toggle'); if(toggle){ const item = toggle.closest('.rca-item'); const panel = item.querySelector('.rca-panel'); const isOpen = item.classList.contains('is-open'); const container = toggle.closest('.resina-cat-accordion'); container.querySelectorAll('.rca-item').forEach(other=>{ if(other !== item){ other.classList.remove('is-open'); const op = other.querySelector('.rca-panel'); if(op){ op.style.maxHeight = 0; } } }); if(isOpen){ item.classList.remove('is-open'); if(panel){ panel.style.maxHeight = 0; } } else { item.classList.add('is-open'); if(panel){ panel.style.maxHeight = panel.scrollHeight + "px"; } } return; } // Click su All o categoria const linkBtn = e.target.closest('.resina-cat-accordion .rca-link, .resina-cat-accordion .rca-all-link'); if(linkBtn){ const slug = linkBtn.dataset.slug || ''; let targetUrl = RESINA_PRODUCTS_URL; if(slug){ targetUrl = RESINA_PRODUCTS_URL + '#category-' + slug; } // chiudi overlay closeOverlay(); if(isOnProductsPage()){ const anchors = getAnchors(); let anchor; if(slug){ anchor = anchors.find(a => a.getAttribute('data-slug') === slug); }else{ anchor = findAllAnchor(anchors); } const isMobile = window.matchMedia('(max-width: 768px)').matches; if(!isMobile && anchor){ // DESKTOP → filtro Lay live clickLay(anchor); history.replaceState(null, '', targetUrl); } else { // MOBILE → ricarica pagina con hash window.location.href = targetUrl; } }else{ // Non siamo su all-products → vai normalmente window.location.href = targetUrl; } return; } }); document.addEventListener('DOMContentLoaded', initAccordions); })(); </script> <?php }); -
wow!
can you try this:
<button type="button" class="rca-link" data-slug="dining-tables">Dining tables</button>
dont use <button> elements but instead use normal <divs>
or anything else except <button>really not sure if that may be it. probably that wont make a difference
another thing is:
if(!isMobile && anchor){ // DESKTOP → filtro Lay live clickLay(anchor); history.replaceState(null, '', targetUrl); } else { // MOBILE → ricarica pagina con hash window.location.href = targetUrl; }here, could you code it so it only replaces the hash:
window.location.hash = 'section1';
instead of using
window.location.href =
because the window.location.href =
line might reload the siteor try the way you do it in this one if statement:
history.replaceState(null, '', targetUrl);
instead of
window.location.href =
I also code custom websites or custom Lay features.
💿 Email me here: 💿
info@laytheme.com
Our Web Development company: 100k.studio
Want to tip me? https://www.paypal.com/paypalme/arminunruh
Before you post:
- When using a WordPress Cache plugin, disable it or clear your cache.
- Update Lay Theme and all Lay Theme Addons
- Disable all Plugins
- Go to Lay Options → Custom CSS & HTML, click "Turn Off All Custom Code", click "Save Changes"
This often solves issues you might run into
When you post:
- Post a link to where the problem is
- Does the problem happen on Chrome, Firefox, Safari or iPhone or Android?
- If the problem is difficult to explain, post screenshots / link to a video to explain it