• Resolved farhanhan173

    (@farhanhan173)


    Hello,

    I am currently using the Better Post Filter Widgets for Elementor plugin, and it is working well overall. However, I need some guidance to achieve a specific setup.

    On my blog page, I am using multiple Elementor Loop Grids to create a custom layout. The structure includes:

    • One single-column “hero” post at the top
    • A three-column grid below it

    To achieve this layout, I am using the offset option to exclude the hero post from the three-column grid.

    The issue I’m facing is that the filter functionality only works on one Loop Grid, as the plugin relies on a specific class/ID to trigger the filtering. I would like the filter to apply to both Loop Grids simultaneously, so that they stay in sync when a filter is selected.

    Is there a recommended way to filter multiple Loop Grids at the same time using this plugin?

    Any help or guidance would be greatly appreciated.

    Thank you

Viewing 14 replies - 1 through 14 (of 14 total)
  • Plugin Support Dara

    (@dara4)

    Hi @farhanhan173,

    At the moment, each filter widget is designed to target a single loop grid or post widget. Filtering multiple Loop Grids at the same time is not officially supported, mainly to avoid issues with pagination, and reset behavior.

    A possible workaround would be to use two identical filter widgets (one per Loop Grid), hide one of them, and mirror the selections with a script so both grids stay in sync.

    Proper multi-grid filtering is something I may explore in the future, but I want to make sure it is done reliably before supporting it.

    Hope that helps.

    Regards,
    Dara

    Thread Starter farhanhan173

    (@farhanhan173)

    Hi Dara,

    Thank you for the clear explanation and for taking the time to share the reasoning behind the current limitation. That makes sense, especially regarding pagination and reset behavior.

    The workaround you suggested, using two identical filter widgets and synchronizing their selections via a script, sounds reasonable.

    If possible, could you please recommended script on how to mirror the filter state between two widgets (as i am not very technical)

    That would be very helpful and would allow me to implement the solution correctly without unintended side effects.

    Thanks again for your support and for considering multi-grid filtering as a future enhancement.

    Best regards,

    Plugin Support Dara

    (@dara4)

    Hi @farhanhan173,

    Here is a simple workaround that can work well if your setup stays reasonably straightforward. I put together a small demo based on your use case.

    Before using it, please keep these points in mind:

    • The secondary filter must have a submit button. Auto-triggering the second filter can work, but explicit submit makes the behavior more predictable.
    • I recommend keeping the filters simple (checkboxes, radios, basic dropdowns, fixed numeric ranges).
    • Advanced fields like Select2 were not fully tested and may require extra coding to keep them in sync.
    • The script assumes that the main filter has the ID formA, and the second filter has the ID formB. These are IDs given to the filter only and should not be confused with the target widget IDs used by the filters.
    • Some events used in the script (such as “input” and “change”) may need adjustments depending on your filters. These events control how the script listens to user interactions on the form. More details can be found here: https://api.jquery.com/category/events/
    <script>
    (function($) {
    	// Debounce utility to add delays to inputs to avoid overwhelming the script.
        function debounce(fn, wait) {
            let timer;
            return function(...args) {
                clearTimeout(timer);
                timer = setTimeout(() => fn.apply(this, args), wait);
            };
        }
    
        const $formA = $('#formA');
        const $formB  = $('#formB');
    
        // 1. Checkboxes & radios.
        $formA.on('change', 'input[type="checkbox"], input[type="radio"]', function() {
            const name    = this.name;
            const value   = this.value;
            const checked = this.checked;
    
            if (!name || !value) return;
    
            const $target = $formB.find(<code>input[name=&quot;${name}&quot;][value=&quot;${value}&quot;]</code>);
            if ($target.length) {
                $target.prop('checked', checked);
            }
        });
    
        // 2. Text / number inputs.
        $formA.on('input', 'input:not([type="checkbox"]):not([type="radio"]), textarea', function() {
            const name = this.name;
            if (!name) return;
    
            const $targets = $formB.find(<code>[name=&quot;${name}&quot;]</code>);
            if ($targets.length) {
                $targets.val($(this).val());
            }
        });
    
        // 3. Select.
        $formA.on('change', 'select', function() {
            const name = this.name;
            if (!name) return;
    
            const value = $(this).val();
            const $formBSelect = $formB.find(<code>select[name=&quot;${name}&quot;]</code>);
    
            if ($formBSelect.length) {
                $formBSelect.val(value).trigger('change');
            }
        });
    
        // Debounced submit for formB.
        const debouncedSubmit = debounce(function() {
            const $btn = $formB.find('.submit-form');
            if ($btn.length) {
                $btn.trigger('click');
            }
        }, 600); // Debounce value can be adjusted (ms).
    
        $formA.on('input change', 'input, select, textarea', debouncedSubmit); // You may need to adjust these events depending on the fields used in your filters, especially for numeric ranges
    
        // 4. RESET sync.
        $formA.on('click', '.reset-form', function() {
            const slaveForm = $formB.find('form')[0];
            if (!slaveForm) return;
    
            slaveForm.reset();
    
            // Submit slave after reset
            setTimeout(function() {
                const $btn = $formB.find('.submit-form');
                if ($btn.length) {
                    $btn.trigger('click');
                }
            }, 100);  // Debounce value can be adjusted (ms).
        });
    
    })(jQuery);
    </script>

    Hopefully this gives you a workable solution for keeping both Loop Grids in sync. Let me know if this works for you.

    Regards,
    Dara

    Thread Starter farhanhan173

    (@farhanhan173)

    Hi Dara,

    First of all, thank you for your time, support, and the quick response to my query.

    I tried using the script, but unfortunately, it didn’t work. I replaced the filter IDs (e.g., filter-b15862f) as you suggested, but I wasn’t able to get it working. Please let me know if I may have used incorrect IDs.

    I also have another scenario in mind, if possible. Is there a way to hide the other loop grids when a filter is applied, so that only the relevant loop grid remains visible on the page?

    Thank you again for your wonderful work.

    Best regards

    Plugin Support Dara

    (@dara4)

    Hi @farhanhan173,

    Regarding the script I see there is a formatting error, from when I copy-pasted it so here is the corrected version:

    <script>
    (function($) {
        // Debounce utility to add delays to inputs to avoid overwhelming the script.
        function debounce(fn, wait) {
            var timer;
            return function() {
                var args = arguments;
                clearTimeout(timer);
                timer = setTimeout(function() {
                    fn.apply(this, args);
                }.bind(this), wait);
            };
        }
    
        var $formA = $('#formA');
        var $formB = $('#formB');
    
        // 1. Checkboxes & radios.
        $formA.on('change', 'input[type="checkbox"], input[type="radio"]', function() {
            var name    = this.name;
            var value   = this.value;
            var checked = this.checked;
    
            if (!name || !value) return;
    
            var $target = $formB.find('input[name="' + name + '"][value="' + value + '"]');
            if ($target.length) {
                $target.prop('checked', checked);
            }
        });
    
        // 2. Text / number inputs.
        $formA.on('input', 'input:not([type="checkbox"]):not([type="radio"]), textarea', function() {
            var name = this.name;
            if (!name) return;
    
            var $targets = $formB.find('[name="' + name + '"]');
            if ($targets.length) {
                $targets.val($(this).val());
            }
        });
    
        // 3. Select.
        $formA.on('change', 'select', function() {
            var name = this.name;
            if (!name) return;
    
            var value = $(this).val();
            var $formBSelect = $formB.find('select[name="' + name + '"]');
    
            if ($formBSelect.length) {
                $formBSelect.val(value).trigger('change');
            }
        });
    
        // Debounced submit for formB.
        var debouncedSubmit = debounce(function() {
            var $btn = $formB.find('.submit-form');
            if ($btn.length) {
                $btn.trigger('click');
            }
        }, 600);
    
        $formA.on('input change', 'input, select, textarea', debouncedSubmit);
    
        // 4. RESET sync.
        $formA.on('click', '.reset-form', function() {
            var slaveForm = $formB.find('form')[0];
            if (!slaveForm) return;
    
            slaveForm.reset();
    
            setTimeout(function() {
                var $btn = $formB.find('.submit-form');
                if ($btn.length) {
                    $btn.trigger('click');
                }
            }, 100);
        });
    
    })(jQuery);
    </script>

    To have it work, you need two filters on the page:

    • The first filter should have the ID formA
    • The second filter should have the ID formB
    • Make sure these IDs are set on the filter forms themselves, not on the targeted post widgets

    The second filter will only trigger if it includes a submit button. Once the IDs and the button are in place, the synchronization between the two filters should work as expected.

    Regarding your second scenario, at the moment there isn’t a built-in option to achieve this, it would also require custom javascript to handle.

    Let me know if you could make the script work, and I can help clarify anything else.

    Regards,
    Dara

    Thread Starter farhanhan173

    (@farhanhan173)

    Hi Dara,

    Thank you again for your swift reply.

    I tested the latest version of the script and in a moment when i click the submit button both grids fading like its working but finally only one grid filter the result. So not working in my case.

    I then worked on my second scenario (with the help of ChatGPT) as I think this is the best and simplest solution that we should use the same class the filter is using to target the loop grid, to hide the other loop grids (can be more than two), and click the reset button, all show up again. Below is the script i created, but it’s not working.

    <script>
    document.addEventListener('DOMContentLoaded', function () {

    const filters = document.querySelectorAll('.filter-container');
    const allGrids = document.querySelectorAll('.elementor-widget-loop-grid');

    if (!filters.length || !allGrids.length) return;

    filters.forEach(filter => {
    const form = filter.querySelector('form');
    if (!form) return;

    const targetSelector = filter.dataset.targetPostWidget;
    if (!targetSelector) return;

    form.addEventListener('submit', function () {

    // Hide all grids
    allGrids.forEach(grid => {
    grid.style.display = 'none';
    });

    // Show only the targeted grid
    document.querySelectorAll(targetSelector).forEach(grid => {
    grid.style.display = '';
    });

    });

    // Reset → show all grids
    const resetBtn = form.querySelector('button[type="reset"]');
    if (resetBtn) {
    resetBtn.addEventListener('click', function () {
    setTimeout(() => {
    allGrids.forEach(grid => {
    grid.style.display = '';
    });
    }, 200);
    });
    }
    });

    });
    </script>

    Can you please have a look at the script? it will also remove the requirment of having multiple filters.

    Thank you again for your time and considering this matter.

    Best regards

    Plugin Support Dara

    (@dara4)

    Hi @farhanhan173,

    For this case, I would recommend using CSS instead. It is easier to manage and tweak than javascript. The filter give a special class to the targeted widget when it’s active, so you can use this to your advantage:

    .elementor-element:has(.filter-active) .elementor-widget-loop-grid:not(.filter-active) {
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.3s ease;
    }
    
    .elementor-widget-loop-grid {
        transition: opacity 0.3s ease;
    }

    When interacting with the filter, the non-targeted post grid will fade out.

    Let me know if this solution works out for you.

    Regards,
    Dara

    Thread Starter farhanhan173

    (@farhanhan173)

    Hi @dara4

    The CSS solution worked for me but only when the both loop grids are in the same container. can we also hide the container but not just the loop grid?

    Thank you

    Best regards

    Plugin Support Dara

    (@dara4)

    Hi farhanhan173 (@farhanhan173),

    Sure, you can adjust the CSS like this so the entire parent container is hidden, not only the loop grid:

    <style>
    body:has(.elementor-widget-loop-grid.filter-active) 
    #YOURID:not(:has(.filter-active)) {
        opacity: 0;
        pointer-events: none;
    }
    
    #YOURID {
        transition: opacity 0.3s ease;
    }
    </style>

    Just replace #YOURID with the ID or class of the parent container you want to hide/show. You can also replace opacity: 0; by display: none;, if you want to remove the extra space left by the hidden container.

    Thread Starter farhanhan173

    (@farhanhan173)

    Thanks @dara4

    The solution worked perfectly for me. It also worked for multiple containers to hide them at a time. Again thank you so much for your wonderful support.

    Looking forward to see these as options in upcoming releases.

    Best regards.

    Plugin Support Dara

    (@dara4)

    Hi @farhanhan173,

    Great to hear that both solutions worked for you. Since both of you were able to implement the fixes successfully, I’ll go ahead and close this thread.

    Feel free to open a new thread if you have any other questions or run into anything else.

    Regards,
    Dara

    Plugin Support Dara

    (@dara4)

    Hi @farhanhan173,

    Just a quick follow-up on this topic.

    All the previous workarounds shared in this thread remain valid and can still be used if needed. However, starting from version 1.8.4, you no longer need to rely on custom scripts to sync multiple loop grid widgets.

    You can now use a comma-separated list of IDs or classes directly in the Post Widget Target field (eg.: .grid-1,#grid-2,.grid-3). The filter will internally handle all targeted widgets and keep them in sync automatically.

    Feel free to update and test it out. If anything behaves unexpectedly let me know and I’ll be happy to take a look.

    Regards,
    Dara

    Natacha

    (@chickwithbob)

    @dara4 I had the same issue as the OP and I have just installed your plugin and the multiple loop grids sync solution you developed in version 1.8.4+

    I have found a small bug –
    My first loop grid has a limit of 1 item to be shown (no pagination), my 2nd loop grid has pagination, 12 per page.

    Your filter targets both grids (great!), but it ignores the fact I have a limit of 1 item in the first grid – it returns shows all items.

    Hopefully you can fix this in future.

    • This reply was modified 3 weeks ago by Natacha.
    Plugin Support Dara

    (@dara4)

    Hi Natacha (@chickwithbob),

    When using a comma-separated list of classes or ID, each query is executed separately. Each widget keeps its own configuration and will return its own number of posts independently.

    If this is not what you are seeing, please check under the “Performance Settings” in your filter. The “number of posts” value should be set to -1 so the loop widget is using it’s own post per page setting, otherwise the number set on the filter widget will take over and decide the number of post to display for all widgets.

    Hope this help. Let me know if this fix the issue.

    Regards,
    Dara

Viewing 14 replies - 1 through 14 (of 14 total)

You must be logged in to reply to this topic.