1

I created a loop for my Custom Posts Type workshop with the lists of two custom taxonomies group and teacher on the same page. What I'm trying to do is create an Ajax filter with both taxonomies. The user can select one taxonomy or both to display a selection of posts.

The issues are when the user selects both taxonomies it only displays one post. And when he selects only one taxonomy the result displays "No posts found."

Same thing for the button .filter-reset. I created it to reset the selection and display all the posts. Same issue, the result is "No posts found."

Here is PHP code for the filter and the loop:

<form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php" method="POST" id="filter" class="form-filter">
  <div class="container">
  <?php

  if( $terms = get_terms( 'group', 'orderby=name&exclude=-1' ) ) :
    echo '<div class="filter-tax filter--group">';
    foreach ( $terms as $term ) :
      echo '<input class="btn-radio" type="radio" name="categoryfilter1" value="' . $term->term_id . '"><label>' . $term->name . '</label>';
    endforeach;
    echo '</div>';
   endif;

   if( $terms = get_terms( 'teacher', 'orderby=name&exclude=-1' ) ) :
     echo '<div class="filter-tax filter--teacher">';
     foreach ( $terms as $term ) :
       echo '<input class="btn-radio" type="radio" name="categoryfilter2" value="' . $term->term_id . '"><label>' . $term->name . '</label>';
     endforeach;
     echo '</div>';
    endif;

  ?>

  <a href="#" class="filter-reset">View all</a>
  <input type="hidden" name="action" value="myfilter">

  </div>
</form>


<?php
$query_args = array(
    'post_type' => 'workshop',
    'posts_per_page' => -1,
    'orderby' => 'date'
);

$the_query = new WP_Query( $query_args );

if ( $the_query->have_posts() ) :
?>
<div class="wrapper-loop">
    <?php
        while ( $the_query->have_posts() ) :
            $the_query->the_post();

            get_template_part( 'template-parts/content-archive' );

        endwhile;
    ?>
</div><!-- .wrapper-loop -->

<?php

else :

get_template_part( 'template-parts/content', 'none' );

endif;
?>

The PHP code for the AJAX function to filter the posts:

<?php

add_action('wp_ajax_myfilter', 'site_filter_function');
add_action('wp_ajax_nopriv_myfilter', 'site_filter_function');

function site_filter_function(){
    $args = array(
        'orderby' => 'date',
        'posts_per_page' => -1
    );

    if( isset( $_POST['categoryfilter1'] ) && isset ($_POST['categoryfilter2'])  ) {
        $args['tax_query'] = array(

        'relation' => 'AND',

            array(
                'taxonomy' => 'group',
                'field' => 'id',
                'terms' => $_POST['categoryfilter1']
            ),
            array(
                'taxonomy' => 'teacher',
                'field' => 'id',
                'terms' => $_POST['categoryfilter2']
            ),
        );


    } else {

    if( isset( $_POST['categoryfilter1']) && !empty( $_POST['categoryfilter2'] ) )
        $args['tax_query'] = array(
                'taxonomy' => 'group',
                'field' => 'id',
                'terms' => $_POST['categoryfilter1']
        );

    if( isset( $_POST['categoryfilter2']) && !empty( $_POST['categoryfilter1'] ) )
        $args['tax_query'] =
            array(
                'taxonomy' => 'teacher',
                'field' => 'id',
                'terms' => $_POST['categoryfilter2']
        );

    }

    $query = new WP_Query( $args );

    if( $query->have_posts() ) :
        while( $query->have_posts() ): $query->the_post();
            get_template_part( 'template-parts/content-archive' );
        endwhile;
        wp_reset_postdata();
    else :
        echo 'No posts found';
    endif;

    die();
}

?>

The JS code the AJAX:

( function($) {

    $('.btn-radio').change(function(){
    var filter = $('#filter');
    $.ajax({
        url:filter.attr('action'),
        data:filter.serialize(),
        type:filter.attr('method'),
        beforeSend:function(xhr){
            //filter.find('button').text('Processing...');
        },
        success:function(data){
            //filter.find('button').text('Filter');
            $('.loop-archive-workshop').html(data);
        }
    });
    return false;
});

$(".filter-reset").click(function() {
    document.getElementById('filter').reset();
    $('.loop-archive-workshop').append();

    var filter = $('#filter');

    $.ajax({
        url:filter.attr('action'),
        type:filter.attr('method'),
        data:filter.serialize(),
        success:function(data){
            $('.wrapper-loop').html(data);
        }
    });
    return false;
});


} )(jQuery);

I'm struggling with this issue for days. Any help would be much appreciated!

EDIT

This is the content from the log.txt when using the fitler:

Array
(
    [categoryfilter1] => 7
    [action] => myfilter
)


Array
(
    [categoryfilter1] => 5
    [action] => myfilter
)


Array
(
    [categoryfilter1] => 4
    [action] => myfilter
)


Array
(
    [categoryfilter1] => 7
    [action] => myfilter
)


Array
(
    [categoryfilter1] => 7
    [categoryfilter2] => 14
    [action] => myfilter
)


Array
(
    [categoryfilter1] => 7
    [categoryfilter2] => 8
    [action] => myfilter
)


Array
(
    [categoryfilter1] => 7
    [categoryfilter2] => 16
    [action] => myfilter
)
2
  • I think your !empty( are supposed to be empty(. Otherwise your 3 conditions are exactly the same. Feb 19 at 11:09
  • Thank you @JacobPeattie. I just tried your suggestion and unfortunately the issues are still the same. Feb 19 at 11:14
2

The problem seems to be in the checks you are performing in the php function that handles the ajax reguest.

The first if condition checks if both categoryfilter1 and categoryfilter2 properties are set the the $_POST, and then you have else.

Your code will never enter else because, from what I can see, you will always have at least one categoryfilter set at a given time.

I suggest using the following if conditions

    if ((isset($_POST['categoryfilter1']) && !empty($_POST['categoryfilter1'])) && (isset($_POST['categoryfilter2']) && !empty($_POST['categoryfilter2']))) {
        // both properties are set and have value (not empty)
    } elseif ((isset($_POST['categoryfilter1']) && !empty($_POST['categoryfilter1'])) && (!isset($_POST['categoryfilter2']) || empty($_POST['categoryfilter2']))) {
        // only categoryfilter1 is set and has value and categoryfilter2 is either not set or set but has no value
    } elseif ((!isset($_POST['categoryfilter1']) || empty($_POST['categoryfilter1'])) && (isset($_POST['categoryfilter2']) && !empty($_POST['categoryfilter2']))) {
        // only categoryfilter2 is set and has value and categoryfilter1 is either not set or set but has no value
    }

This checks should handle all your possible outcomes

EDIT

To see the content of $_POST you can use PHP error_log, I use it all the time in development, it helps with displaying the content that you usually can't output to the screen.

When using filters or ajax requests this can help because this are processes that happen on the backend.

error_log(print_r($_POST, true), 3, __DIR__ . '/log.txt');
error_log("\r\n\r\n", 3, __DIR__ . '/log.txt');

This code will create a new file named log.txt and will contain the content of $_POST.

If your ajax code is located in functions.php, the log.txt file will be in the same directory as functions.php.

After you are done remove the file, if you can't, delete all content inside of it.

EDIT, after seeing log

The conditions can be even simpler looking at the content of $_POST, try this

if (isset($_POST['categoryfilter1']) && isset($_POST['categoryfilter2'])) {
    // both are set
} elseif (isset($_POST['categoryfilter1']) && !isset($_POST['categoryfilter2'])) {
    // only categoryfilter1 is set
} elseif (!isset($_POST['categoryfilter1']) && isset($_POST['categoryfilter2'])) {
    // only categoryfilter2 is set
}

ALSO

Just noticed that for a single tax_query you use

$args['tax_query'] = array(
    'taxonomy' => 'group',
    'field' => 'id',
    'terms' => $_POST['categoryfilter1']
);

This is incorrect, it should be like this

$args['tax_query'] = array(
    array(
        'taxonomy' => 'group',
        'field' => 'id',
        'terms' => $_POST['categoryfilter1']
    )
);

tax_query expects an array, in that array you need to pass each taxonomy as its own array

11
  • Thanks you very much @Buttered_Toast, you're right I think I have a mistake with the conditionals. I tried your code but unfortunately it doesn't work. Feb 19 at 11:28
  • Could you provide us with the content of $_POST. I can modify my conditions based on the content. Without it im going by guessing the content. edit you code to show $_POST when filtering with both and with single categoryfilter Feb 19 at 11:30
  • My PHP level is quite basic, sorry for that! I'm not really sure how to provide you the content of $_POST. How should I proceed? Thanks Feb 19 at 11:40
  • Updated my answer to include some code that will help you "see" the content of $_POST Feb 19 at 12:05
  • Should I insert the code directly in functions.php or in the PHP Ajax filter? Thank you. Feb 19 at 12:39

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.