Question

I have a modified theme that displays CPT posts. I am creating a slider that will cycle through all the sticky posts and display them at the top of the page. So far so good.

The problem. When I have less than 5 posts in a given category. The slider code doesn't display posts properly (they shrink in size, repeat, all kinds of weird stuff). Now before you suggest I try a different slider, please note that this one is hardcoded into the theme. I could comment it out, drop in a new code for another slider, but that's just one more plugin/theme element to maintain. I'd like to see if my logic can be fixed.

What I need. I'm looking for an if/else statement that lets me deliver 2 different loops, one where I can pass args of one type, and another to pass the second set of args (which is to pull from all other categories if that specific category has less than 5 posts).

Here is the code I was using - ALMOST SUCCESSFULLY (see below code for more).

<div class="slider">

<ul>
<?php
$term = get_term_by('slug', get_query_var('term'), get_query_var('taxonomy'));
$sticky = get_option('sticky_posts');
    $args_cat_only = array (
        'my_cat' => $term->slug,
        'posts_per_page' => -1,
        'post__in' => $sticky,
        'post_type' => MYCPT_POST_TYPE,
        'post_status' => 'publish',
        'orderby' => 'rand',
    );
$cat_only_query = new WP_Query( $args_cat_only );

if ( $cat_only_query->have_posts() ) {
    while ( $cat_only_query->have_posts() ) {
        $cat_only_query->the_post(); ?>

        <li>
        // items from category only
        </li>

   <?php  } wp_reset_postdata(); 

if( count($cat_only_query->posts) <= 4 ) { 

    $args_all_cats = array ( //Args to pull from all categories
        'orderby' => 'rand',
        'posts_per_page' => -1,
        //'my_cat' => $term->slug,
        'post__in' => $sticky,
        'post_type' => MYCPT_POST_TYPE,
        'post_status' => 'publish'
    );

    $cat_query_all = new WP_Query( $args_all_cats );

    if( $cat_query_all->have_posts() ) {
        while( $cat_query_all->have_posts() ) {
            $cat_query_all->the_post(); ?>

        <li>
        // items from ALL categories
        </li>

   <?php } wp_reset_postdata();
            }
        }
    }
?>    
</ul>

This code works to query all CPT posts, specific to the category we're in, and return sticky posts UNLESS there are less than 5 (4 or less). In that case, it grabs posts from ALL categories. The problem is that because have_posts() returns true ONLY if there ARE posts, my logic is broken when there are ZERO posts from the loop.

I could add yet another elseif/else statement and run through a scenario where there are NO posts, but I'd rather not do that (unless that's the only way). Can I modify my 2nd query somehow, so so that when it does the count check, it says "if there are less than 5, OR there are zero, do foo"?

Was it helpful?

Solution

I would start by creating an array to put your posts into, to create a counting system of some kind. Dump your list item output into that array, count it, and use the remaining count to call your second query.

<?php
$term = get_term_by('slug', get_query_var('term'), get_query_var('taxonomy'));
$sticky = get_option('sticky_posts');

// Moved the base arguments into one array
$base_args = array( 
    'posts_per_page' => 5,  // Changed to 5, because that's the amount you need
    'post_type' => MYCPT_POST_TYPE,
    'orderby' => 'rand'
    'post__in' => $sticky,
);

// Merge your base arguments and cat only arguments
$args_cat_only = array_merge( $base_args, array (
    'my_cat' => $term->slug,
) );

$cat_only_query = new WP_Query( $args_cat_only );

if ( $cat_only_query->have_posts() ) {
    while ( $cat_only_query->have_posts() ) { $cat_only_query->the_post();
        // Start an Output Buffer
        ob_start();
        ?>

        <li>
        // items from category only
        </li>

        <?php
        // Dump output into list item array
        $list_items[] = ob_get_clean();
    }
    wp_reset_postdata();
}

if ( count( $list_items ) < 5 ) {
     // Find out how many posts you need
     $post_need = 5 - count( $list_items );

     // Change base args posts_per_page to only call the amount of posts you need
     $base_args['posts_per_page'] = $post_need;

     // Run the new query based on base arguments
     $fill_in_query = new WP_Query( $base_args );

    if ( $fill_in_query->have_posts() ) {
        while ( $fill_in_query->have_posts() ) { $fill_in_query->the_post();
            // Start an Output Buffer
            ob_start();
            ?>

            <li>
            // items from category only
            </li>

            <?php
            // Dump output into list item array
            $list_items[] = ob_get_clean();
        }
        wp_reset_postdata();
    }
}
?>

<div class="slider">
<ul>
     <?php echo implode( '', $list_items ); // Print your list items ?>
</ul>
</div>

The only problem now is that your random pull in your second query could technically pull a random one from the first query.

I didn't test any of this code, please let me know if you have any questions.

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top