AJAX Post Filtering In WordPress

By August 16, 2017Blog, 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

Leave a Reply