Support » Developing with WordPress » Filter CPT by category

  • Resolved courtneyjouning

    (@courtneyjouning)



    Hi,

    I can get my custom post types to display via AJAX but it is not filtering by category.

    It works for normal posts, but if I change

    $query = new WP_Query( $args );

    back to

    $query = new WP_Query( array('post_type' => 'videos' ) );

    then it just lists all posts of that post type, and no category filtering.

    Am I missing something here?

    Full function here:

    function video_filter_function(){
    
        if (!check_ajax_referer( 'my_nonce' )){
        wp_die();
        }else{
            $args = array(
            'orderby' => 'date', // we will sort posts by date
            'order' => $_POST['date'] // ASC или 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() ) :
            while( $query->have_posts() ): $query->the_post();
                echo '<h2>' . $query->post->post_title . '</h2>';
            endwhile;
            wp_reset_postdata();
        else :
            echo 'No posts found';
        endif;
     
        die();
     
        die();
        }
    
        
    }
     
     
    add_action('wp_ajax_myfilter', 'video_filter_function'); 
    add_action('wp_ajax_nopriv_myfilter', 'video_filter_function');
    • This topic was modified 4 months, 2 weeks ago by  bcworkz. Reason: code fixed

    The page I need help with: [log in to see the link]

Viewing 6 replies - 1 through 6 (of 6 total)
  • Note that the Function I have is this (instead of what is original post):

    function video_filter_function(){
    
        if (!check_ajax_referer( 'my_nonce' )){
        wp_die();
        }else{
            $args = array(
            'orderby' => 'date', // we will sort posts by date
            'order' => $_POST['date'] // ASC или DESC
        );
     
        // for taxonomies / categories
        if( isset( $_POST['categoryfilter'] ) )
            $args['tax_query'] = array(
                array(
                    'taxonomy' => 'category',
                    'field' => 'id',
                    'terms' => $_POST['categoryfilter']
                )
            );
     
        $query = new WP_Query( array( 'post_type' => 'videos' ) );
     
        if( $query->have_posts() ) :
            while( $query->have_posts() ): $query->the_post();
    
                ?>
                <div class="video-grid-item">
                    <h2> <?php the_field('video_title'); ?></h2>
                    <p> <?php the_field('video_description'); ?></p>
    
                    <iframe src="https://player.vimeo.com/video/<?php the_field('vimeo'); ?>" width="640" height="640" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
                </div>
    
    <?php  
            endwhile;
            wp_reset_postdata();
        else :
            echo 'No posts found';
        endif;
     
        die();
     
        die();
        }
    
        
    }
     
     
    add_action('wp_ajax_myfilter', 'video_filter_function'); 
    add_action('wp_ajax_nopriv_myfilter', 'video_filter_function');
    • This reply was modified 4 months, 2 weeks ago by  bcworkz. Reason: code fixed
    Moderator bcworkz

    (@bcworkz)

    Yes you are missing something 🙂

    You define an $args array to query by category, but then you never use it in favor of a new query for your CPT where the category args are not used. Add your CPT arg to the category and ordering args and pass the entire args array to the new query.

    $args = array(
       'orderby' => 'date', // we will sort posts by date
       'order' => $_POST['date'], // ASC или DESC
       'tax_query' => array(
         array(
           'taxonomy' => 'category',
           'field' => 'id',
           'terms' => $_POST['categoryfilter']
        )),
      'post_type' => 'videos',
    );
     
    $query = new WP_Query( $args );

    You also need to validate, sanitize, and escape any values from $_POST used in a query. Failure to do so opens up your site to SQL injection attacks.

    BTW, next time you post code in these forums, please delimit with backticks or use the code button. When you fail to do this, the forum’s parser will corrupt your code, making it unusable for copy/pasting and testing. I fixed your code formatting for you this time. We realize this detail is unclear on the new topic form, but now you know and you can now be a forum “insider” 🙂

    @bcworkz – thank you that works a charm!

    And apologies for the code format, noted for next time 🙂

    Do you know what I could add to have all videos, of all categories show first, until a category is selected?

    Last question, for now 🙂 as far as I was aware using the nonce would be enough to close up the site, could you point me in the direction to close up my query?

    Cheers!

    I have added thew following code to my template option dropdown to sanitize:

    echo '<option id="video-option" name="video-option" value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
    $vidoption = sanitize_text_field( $_POST['video-option'] );
    update_post_meta( $post->ID, 'video-option', $vidoption );
    Moderator bcworkz

    (@bcworkz)

    sanitize_text_field() is good. A nonce ensures your form was used to POST data and that data isn’t coming from a third party source, but it does not stop an attacker from sending malicious data using your form. You need to do both measures.

    There are a couple ways to list a specific category first and the rest by date. One is to make two queries, one of only video category, the other using the “NOT IN” operator of tax_query to exclude the video category. Use a conditional if(){} statement to only do this when a category is not selected.

    The other way is to restructure the resulting $query->posts array. Loop through the array and pluck out posts with the video category, placing them in another array and unsetting the post in the original array. After all video posts have been plucked, combine the two arrays, or just output the two arrays in sequence.

    Thanks for your help @bcworkz

Viewing 6 replies - 1 through 6 (of 6 total)
  • You must be logged in to reply to this topic.