3

I am looking to display posts that meet certain requirements. First and foremost, the idea is to show visitors the most viewed posts. I implemented that with some help. So, I got that working with the following PHP. I got that working for me, which is nice. Now I want to add a constraint, namely: only posts with thumbnails should be eligible for the loop, but you can't just skip a post if it doesn't have a thumbnail and just come up with less posts in the actual output: I need four posts in total! So, ideally I want a way to pass an argument that says "has thumbnail" to the WP_Query. However, I also need the meta_key already present. How can I keep that meta key, and use another: I found here that you can add 'key' => '_thumbnail_id', but I'm not sure how I can add multiple keys into this query.

Keep in mind that I do need to use orderby, which orders the posts in order of most views.

For completeness sake, I will post the whole snippet, with Pieter Goosen's answer in mind. I thought the "30 day" would not make a difference, but now I realise that it might. post_date_selection is a function in functions.php that restricts the posts to the last 30 days. I got it from here.

<?php if (is_home()) : ?>
  <section class="featured-posts clear">
    <?php // restrict loop to 30 last days, see functions.php
      add_filter('posts_where', 'post_date_selection');
      global $query_string;
      query_posts($query_string);
    ?>
    <?php 
      $args = array(
        'order'             => 'DESC',
        'posts_per_page'    => 4,
        'meta_key'          => 'post_views_count',
        'orderby'           => 'meta_value_num',
        'meta_query'        => array(
          'relation'      => 'AND',
          array(
            'key' => 'post_views_count',
            'compare' => 'EXISTS'
          ),
          array(
            'key' => '_thumbnail_id',
            'compare' => 'EXISTS'
          ),
        ),
      );
      $popularPosts = new WP_Query($args);
      $counter = 1;
    ?>
    <?php while ($popularPosts->have_posts() ) : $popularPosts->the_post(); ?>
      <article class="box-<?php echo $counter++; ?>">
        <a href=" <?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_post_thumbnail(); ?><span><?php the_title(); ?></span></a>
      </article>
    <?php endwhile; ?>
    <?php wp_reset_postdata(); ?>
  </section>
<?php endif; // is_home ?>
<?php remove_filter('posts_where', 'post_date_selection'); // remove restriction from loop ?>

Most important functions in functions.php:

/*
 * Getting and setting post count
 */
// Set post count
function set_post_views($postID) {
    $count_key = 'post_views_count';
    $count = get_post_meta($postID, $count_key, true);
    if($count==''){
        $count = 0;
        delete_post_meta($postID, $count_key);
        add_post_meta($postID, $count_key, '0');
    }else{
        $count++;
        update_post_meta($postID, $count_key, $count);
    }
}
// To keep the count accurate, lets get rid of prefetching
remove_action('wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0);

// Update post count
function track_post_views ($post_id) {
    if ( !is_single() ) return;
    if ( empty ( $post_id) ) {
        global $post;
        $post_id = $post->ID;    
    }
    set_post_views($post_id);
}
add_action( 'wp_head', 'track_post_views');

// Only 30 last days, needs in content
function post_date_selection ($when = '') {
    $when .= " AND post_date > '" . date('Y-m-d', strtotime('-30 days')) . "'";
    return $when;
}

1 Answer 1

3

You can make use of the custom field parameters in WP_Query like you have, you just need to extend it a bit further

You can do your sorting by post_views_count and use meta_query to get all posts that has the highest post view count and has a post thumbnail

You can probably try something like this

$args = array(
    'order'             => 'DESC',
    'posts_per_page'    => 20,
    'meta_key'          => 'post_views_count',
    'orderby'           => 'meta_value_num',
    'meta_query'        => array(
        'relation'      => 'AND',
        array(
            'key' => 'post_views_count',
            'compare' => 'EXISTS'
        ),
        array(
            'key' => '_thumbnail_id',
            'compare' => 'EXISTS'
        ),
    ),
);
$popularPosts = new WP_Query( $args );

For a more accurate post view count, check out this post I have done on the subject. It is very accurate and does not count double views

EDIT

Just on a side note, you need to reset your custom query, and for that matter, any and all custom queries as they will be influenced and will influence other queries. Just after <?php endwhile; ?>, add <?php wp_reset_postdata(); ?>

EDIT 2

I have tested your code, and it does break my sidebar content. I have modified your code to the code below. It does work as expected, only posts from the last thirty are retrieved according to the fact that it has post thumbnails and ordered by highest post count. I am also testing this on localhost. One other thing that you need to take note of, you have to have Wordpress 3.9+ for this to work

You don't have to specify a value when using the 'EXISTS' or 'NOT EXISTS' comparisons in WordPress 3.9 and up.

<?php if (is_home()) : ?>
    <section class="featured-posts clear">
        <?php
        function filter_where($where = '') {
        //posts in the last 30 days
            $where .= " AND post_date > '" . date('Y-m-d', strtotime('-30 days')) . "'";
            return $where;
        }

        add_filter('posts_where', 'filter_where');

        $args = array(
            'order'             => 'DESC',
            'posts_per_page'    => 20,
            'meta_key'          => 'post_views_count',
            'orderby'           => 'meta_value_num',
            'meta_query'        => array(
                'relation'      => 'AND',
                array(
                    'key' => 'post_views_count',
                    'compare' => 'EXISTS'
                ),
                array(
                    'key' => '_thumbnail_id',
                    'compare' => 'EXISTS'
                ),
            ),
        );
        $popularPosts = new WP_Query( $args );

        remove_filter('posts_where', 'filter_where');

        $counter = 1; ?>

        <?php while ($popularPosts->have_posts() ) : $popularPosts->the_post(); ?>
        <article class="box-<?php echo $counter++; ?>">
            <a href=" <?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_post_thumbnail(); ?>
                <span><?php the_title(); ?></span>
            </a>
        </article>
        <?php endwhile; ?>
        <?php wp_reset_postdata(); ?>

    </section>
<?php endif; // is_home ?>

EDIT 3

You can also use the approach described in this answer by @ialocin to one of my questions to apply and remove a filter using pre_get_posts. This code can be very easily adapted to be used on your custom query. I personally think that this is a better method to use to apply and to remove your custom filter for your custom query

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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