1

I'm finding myself stuck with filtering entries that are related to categories using a category field. I'm looking to build a sub-navigation on a page, where I can select from a select field or from a dropdown nav.

I tried following this but no luck. It doesn't work for me. How to load entries via ajax when a filter is clicked?

I also would love to have 2 or 3 category fields. In the end, I am trying to create something very similar to crafts partner page filtering. https://craftcms.com/partners/category?locations=&partnerCapabilities=

If anyone could share their filtering snippets, I would greatly appreciate it :)

2

First you need some HTML/Twig logic to display your categories

<div>
    {% for category in categories %}
        <input data-id="{{ category.id }}" data-slug="{{ category.slug }}" type="checkbox" class="category-filter">{{ category.title }}
    {% endfor %}

    <a href="" id="submit">Submit</a>
</div>

Then some Javascript logic to make an ajax request, keep in mind you need some variables for csrf protection

window.csrfTokenName = "{{ craft.app.config.general.csrfTokenName|e('js') }}"
window.csrfTokenValue = "{{ craft.app.request.csrfToken|e('js') }}";
window.siteUrl = '{{ entry.getUrl() }}';
$(document).ready(function () {
    $('#submit').click(function (e) {
        e.preventDefault();
        var checked = $('.category-filter:checked');
        var ids = [];
        var slugs = [];
        $.each(checked, function (index, item) {
            ids.push(item.dataset.id);
            slugs.push(item.dataset.slug);
        });

        var data = {
            action: 'plugin-id/controller-id/action-id',
            ids: ids
        }
        data[window.csrfTokenName] = window.csrfTokenValue

        var newUrl = siteUrl + '?location=' + slugs.join();
        $.ajax({
            url: '/',
            data: data,
            type: 'POST',
            dataType: 'json',
            success: function (response) {
                console.log(response);
                history.replaceState({}, '', newUrl);
            }
        });
    })
});

And finally your Controller

public function actionIndex()
{
    $ids = Craft::$app->getRequest()->getBodyParam('ids');
    $entries = Entry::find()
        ->relatedTo($ids)
        ->asArray()
        ->select(['elements.id', 'title'])
        ->all();

    return $this->asJson([
        'entries' => $entries
    ]);
}
  • Is this to create a plugin? I've never dealt with a controller before, I really just need to filter some entries based on category field relations, similar to craftcms.com/partners I'm currently doing it using mixitup.js but I want to learn how to do it with craft and AJAX. – mateostabio Feb 21 at 19:40
  • You can't really perform a secure and good ajax request without a controller via plugin. I feel like you don't really know what ajax means. Because it sounds you just want to use it in sake for being able to say "I use ajax". Because doing it means to create a plugin and PHP. If you don't need the complex functionality then let it be – Robin Schambach Feb 21 at 19:43
  • Yep, never worked with ajax really. But all I know is that without it, the page would refresh. That's the only reason why I wanted to use it, but thanks for the answer and going through all the trouble. – mateostabio Feb 22 at 1:50
  • If you don't want to create a controller you can just hide your results with Javascript. That's what I mean – Robin Schambach Feb 22 at 6:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.