AJAX Post Filtering In WordPress

By August 16, 2017 Blog, Sage, Wordpress
WordPress Tutorials by Allure Web Solutions

In this post I’m describing the process for AJAX post filtering All credits go to Misha Rudrastyh. My contribution is to make add two features. The first is making it work with Sage 9 namespacing. The second is to make the filtering working without pressing a submit button. The example below is for the Sage 9 them, but can easily be modified to work with any theme.

The Post Filter

This goes into app/helpers.php.

/**
 * Post Filter
 */
if (!function_exists(__NAMESPACE__ . '\\filter_posts')) :
    function filter_posts()
    {
        ?>
        <div class="post-filter">
            <form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php" method="POST" id="filter">
                <p>FILTER POSTS BY</p>
                <?php wp_dropdown_categories(
                    array(
                        'orderby' => 'name',
                        'show_count' => false,
                        'show_option_all' => 'All Categories',
                        'hide_if_empty' => true,
                        'name' => 'categoryfilter',
                    ))
                ?>
                <input type="hidden" name="action" value="myfilter">
            </form>
        </div>
        <?php
    }
endif;

The Filtering Function

This goes into app/helpers.php.

/**
 * Post filter function
 */
function post_filter_function()
{
    $args = array(
        'orderby' => 'date', // we will sort posts by date
        'order' => $_POST['date'] // ASC or DESC
    );

    // for taxonomies / categories
    if (isset($_POST['categoryfilter']))
        $args['tax_query'] = array(
            array(
                'taxonomy' => 'category',
                'field' => 'id',
                'terms' => $_POST['categoryfilter']
            )
        );

    $query = new \WP_Query($args);

    if ($query->have_posts()) :
        echo '<div class="row">';
        while ($query->have_posts()): $query->the_post();
            ?>
            <article <?= post_class(); ?>>
                <div class="row no-gutters">
                    <?php $post_image = get_the_post_thumbnail($post_id, 'thumbnail', array('class' => 'post-image'));
                    if (!empty($post_image))
                        echo '<div class="entry entry-image">' . $post_image . '</div>'
                    ?>

                    <div class="entry entry-content">
                        <header>
                            <time class="updated" datetime="<?= get_post_time('c', true); ?>"><?= get_the_date() ?>
                            </time>
                            <h2 class="entry-title"><a href="<?= get_permalink(); ?>"><?= get_the_title() ?></a></h2>
                            <p class="byline author vcard">
                                <?= __('By:', 'sage'); ?> <a
                                        href="<?= get_author_posts_url(get_the_author_meta('ID')); ?>"
                                        rel="author"
                                        class="fn">
                                    <?= get_the_author(); ?>
                                </a>
                            </p>
                        </header>
                        <div class="entry-summary">
                            <?= the_excerpt(); ?>
                        </div>
                    </div>
                </div>
            </article>
            <?php
        endwhile;
        echo '</div>';
        wp_reset_postdata();
    else :
        echo 'No posts found';
    endif;

    die();
}

add_action('wp_ajax_myfilter', __NAMESPACE__ . '\\post_filter_function');
add_action('wp_ajax_nopriv_myfilter', __NAMESPACE__ . '\\post_filter_function');

The Template & Loop

This example is for sage 9 and inside resources/views/index.blade.php.

{!! App\filter_posts() !!}

<div id="blog-posts" class="list">
    <div class="row">
        @while (have_posts()) @php(the_post())
        @include ('partials.content-'.(get_post_type() === 'post' ?: get_post_type()))
        @endwhile
    </div>
</div>

The JavaScript

/**
 * AJAX filter functionality
 */
$('#categoryfilter').change(function () {
    var filter = $('#filter');
    $.ajax({
        url: filter.attr('action'),
        data: filter.serialize(), // form data
        type: filter.attr('method'), // POST
        beforeSend: function () {
            // check if all categories is selected
            if (filter.serialize().indexOf('categoryfilter=0') !== -1) {
                location.reload();
            }
        },
        success: function (data) {
            $('#blog-posts').html(data); // insert data
        },
    });
    return false;
});

 

Mike Doubintchik

Author Mike Doubintchik

More posts by Mike Doubintchik

Join the discussion 7 Comments

  • dave says:

    Thanks for the tutorial. One issue I’m having is the admin-ajax.php is returning with a console error of ” the server responded with a status of 400 (Bad Request)”

    Any idea how to fix it?

    • Mike Doubintchik says:

      That error could mean many things. It’s impossible to tell without looking at your code. If you aren’t using Sage 9, I recommend looking at the original article I mention at the top of the post.

      • dave says:

        Hi Mike, thanks for the reply. Im using Sage 9 and the same code for the Ajax function. I’ve also tried wp_localize_script to use the admin-ajax.php on ajax url.

        The other 2 PHP functions are very similar except im using a CPT Taxonomies

        • Mike Doubintchik says:

          Yeah, without seeing the code I cannot help much. This would require some troubleshooting.

          • dave says:

            Sorry Mike, thought I’d ask just incase you knew of anything top of your head, also didn’t want to just paste all the code down in the comments.

            I have pasted the functions on the below link

            https://codeshare.io/2j7dwM

            The markup for the posts are different but been scratching my head on how to fix this. Its a website I’ve inherited and first time using Sage

          • Mike Doubintchik says:

            One thing I noticed is that your ajax actions needs to match the hidden input on the filter. So change `wp_ajax_post_filter_function` to `wp_ajax_myfilter` and `wp_ajax_nopriv_post_filter_function`

            If that doesn’t solve it, I’m not sure what else could be the issue without active troubleshooting (ie. getting into the code).

          • dave says:

            Ah OK, I tried that previously and just again now but still getting the 400 bad request for admin-ajax. No worries, thanks for your time.

Leave a Reply