Recent posts on homepage: different thumbnail based on logged in status and post category

The question:

This works well on archive.php, but not working on the homepage. For some reason, the first statement doesn’t get applied: if a post is in Members category and user is not logged in, it’s supposed to show a default placeholder image, but instead it’s still showing the actual post thumbnail.

<?php if (!is_user_logged_in() && in_category('members')) { ?>
    <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>">
        <img src="<?php bloginfo('template_directory'); ?>/img/default-login.jpg" alt="<?php the_title(); ?>" />
    </a>
                                
<?php } 
    else if (is_user_logged_in() || !in_category('members')) { ?>                 

        <a href="<?php echo get_permalink($post_item['ID']) ?>">
            <?php echo get_the_post_thumbnail($post_item['ID'], 'news-thumb'); ?>
        </a>
                                    
    <?php } else { ?>
            <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>">
                <img src="<?php bloginfo('template_directory'); ?>/img/default.jpg" alt="<?php the_title(); ?>" />
            </a>

    <?php } ?>

I’m using:

<?php
$recent_posts = wp_get_recent_posts(array(
    'numberposts' => 6, // Number of recent posts to display
    'post_status' => 'publish' // Show only the published posts
));

foreach( $recent_posts as $post_item ) : ?>

Final version so far:

<?php
    $recent_posts = wp_get_recent_posts( array(
    'numberposts' => 6,        // Number of recent posts to display
    'post_status' => 'publish' // Show only the published posts
    ), OBJECT );  // 1. Set the second parameter to OBJECT.
                        
    global $post; // 2. Access the global $post variable.
        foreach ( $recent_posts as $post ) : // 3. Rename $post_item to $post
        setup_postdata( $post );         // 4. Set up global post data. ?>
                            
<div>
<?php if (!is_user_logged_in() && in_category('members')) { ?>
                            
    <a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>">
        <img src="<?php bloginfo('template_directory'); ?>/img/default-login.jpg" alt="<?php the_title(); ?>" />
    </a>
                                
<?php } 
    else if (is_user_logged_in() || !in_category('members')) { ?>                 
        <a href="<?php echo get_permalink($post_item['ID']) ?>">
            <?php echo get_the_post_thumbnail($post_item['ID'], 'news-thumb'); ?>
        </a>
                                    
<?php } else { ?>
        <a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>">
        <img src="<?php bloginfo('template_directory'); ?>/img/default.jpg" alt="<?php the_title(); ?>" />
         </a>
<?php } ?>
                                    
    <a rel="bookmark" href="<?php echo get_permalink($post_item['ID']) ?>" title="<?php the_title(); ?>">
    <h6><?php the_title(); ?></h6>
    </a>
    <div><time datetime="<?php echo get_the_date('c'); ?>">
        <?php echo get_the_date(); ?></time>
    </div>
    <div>
        <?php
            $content = get_the_content();
            $content = preg_replace("~(?:[/?)[^/]]+/?]~s", '', $content);  # strip shortcodes, keep shortcode content

            $trimmed_content = wp_trim_words( $content, 14, '... <br /><a href="'. get_permalink() .'">Continue reading &gt;</a>' );            
        echo $trimmed_content;
            ?>
        </div>
</div>
                            

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

If you want to use the the_ functions (e.g. the_permalink() and the_title()) and including in_category() (without specifying the second parameter) outside of The Loop (the standard one which calls the_post()), you should access the global $post variable and call setup_postdata() to set up global post data and after your foreach ends, call wp_reset_postdata() to restore the $post back to the current post in the main query.

You also must rename the $post_item variable to $post and I’d also use OBJECT as the second parameter value for wp_get_recent_posts(), although you could actually do setup_postdata( (object) $post ).

Working Example

$recent_posts = wp_get_recent_posts( array(
    'numberposts' => 6,        // Number of recent posts to display
    'post_status' => 'publish' // Show only the published posts
), OBJECT );  // 1. Set the second parameter to OBJECT.

global $post; // 2. Access the global $post variable.
foreach ( $recent_posts as $post ) : // 3. Rename $post_item to $post
    setup_postdata( $post );         // 4. Set up global post data.

    // ... your code here ..
    echo ( in_category( 'members' ) ? 'In' : '<b>Not</b> in' ) . ' Members category';
    the_title( '<h3>', '</h3>' );
endforeach;

wp_reset_postdata(); // 5. Restore the $post variable.

Remember, you need to change the $post_item in your code to $post and use the “arrow” to access the post data, e.g. $post->ID and not $post['ID']! 🙂


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment