I have a loop within a loop.
I figured out how to show all or X number of custom posts after Y number of normal posts.
I also figured out how to show 1 custom post after every Y normal posts.
How do I show X custom posts after EVERY Y number of normal posts.
In simple terms.
How do I show 2 book (custom post type) posts after every 4 blog posts?
How does one fetch more than 1 post at a time from the loop?
this is the logic of the x custom posts after y normal posts.
how do i get x custom posts after EVERY y normal posts?
main query // normal query
$k=0 // setting iterator
while have posts, the post
---post markup---
if($k == 4 or $k % 4 == 0) { // whether after x number or after every x number
second query // using WP_Query
while second query has posts, the posts
---custom post type markup // I NEED TO SHOW MORE THAN ONE HERE IF IT IS AFTER EVERY X blogposts
endwhile; //second query ends
}
$k++;
endwhile // main query
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Here’s an idea:
Definitions:
- Posts per page:
PPP - Custom post type:
Y - Main query post type:
X - How many
Yposts to inject each time:y - How many
Xposts to display before injecting theYposts:x
Formula:
We will use:
PPP(Y) = y * floor( ( PPP(X) -1 ) / x )
where PPP(X), x and y are positive.
Examples:
Setup 1:
PPP(X)=1, x=3, y=2, PPP(Y) = 2 * floor( (1-1)/3 ) = 2 * 0 = 0 Loop: X
Setup 2:
PPP(X)=3, x=3, y=2, PPP(Y) = 2 * floor( (3-1)/3 ) = 2 * 0 = 0 Loop: XXX
Setup 3:
PPP(X)=4, x=3, y=2, PPP(Y) = 2 * floor( (4-1)/3 ) = 2 * 1 = 2 Loop: XXX YY X
Setup 4:
PPP(X)=11, x=3, y=2, PPP(Y) = 2 * floor( (11-1)/3 ) = 2 * 3 = 6 Loop: XXX YY XXX YY XXX YY XX
Setup 5:
PPP(X)=12, x=3, y=2, PPP(Y) = 2 * floor( (12-1)/3 ) = 2 * 3 = 6 Loop: XXX YY XXX YY XXX YY XXX
Setup 6:
PPP(X)=13, x=3, y=2, PPP(Y) = 2 * floor( (13-1)/3 ) = 2 * 4 = 8 Loop: XXX YY XXX YY XXX YY XXX YY X
Strategy:
Let’s try to find a way to inject the Y posts into the loop of X posts, without modifying the template files directly.
We want to hook into the loop_start action for the main query of post type X, and fetch PPP(Y) posts of type Y.
Then we want to use the the_post hook to display:
get_template_part( 'content', 'y' );
We can use the for example the current_post and posts_per_page properties of the main $wp_query object to control the injection logic.
I think it’s easier to call WP_Query() for each injection, but let’s constrain ourselves to call it only once before the main loop.
Implementation:
Create a template part file in your active theme’s directory, for example content-page.php, containing:
<article>
<header class="entry-header">
<h2 class="entry-title"><?php the_title(); ?></h2>
</header>
<div class="entry-content">
<?php the_content(); ?>
</div>
</article>
Then you can try the following:
add_action( 'wp', function(){
// We want the injection only on the home page:
if( ! is_home() ) return;
// Start the injection:
$inject = new WPSE_Inject( array(
'items_before_each_inject' => 3,
'cpt_items_per_inject' => 2,
'cpt' => 'page',
'template_part' => 'content-page',
'paged' => ( $pgd = get_query_var( 'paged' ) ) ? $pgd : 1,
) );
$inject->init();
});
and modify it to your needs.
The WPSE_Inject class is defined as:
/**
* class WPSE_Inject
*
* Inject custom posts into the main loop, through hooks,
* with only a single WP_Query() call
*
* @link http://wordpress.stackexchange.com/a/141612/26350
*
* Definitions:
* Posts per page: PPP
* Custom post type: Y
* Main query post type: X
* How many Y posts to inject: y
* How many X posts to display before injecting the Y posts: x
*
* Formula:
* PPP(Y) = y * floor( ( PPP(X) -1 ) / x )
* where PPP(X), x and y are positive
*/
class WPSE_Inject
{
protected $results = NULL;
protected $query = NULL;
protected $nr = 0;
protected $inject_mode = FALSE;
protected $args = array();
public function __construct( $args = array() )
{
$defaults = array(
'items_before_each_inject' => 5,
'cpt_items_per_inject' => 1,
'cpt' => 'post',
'paged' => 1,
'template_part' => 'content-post'
);
$this->args = wp_parse_args( $args, $defaults );
}
public function init()
{
add_action( 'loop_start', array( $this, 'loop_start' ) );
add_action( 'loop_end', array( $this, 'loop_end' ) );
}
public function cpt_items_on_this_page( WP_Query $query )
{
$count = $this->args['cpt_items_per_inject'] * floor( ( $query->get( 'posts_per_page' ) -1 ) / $this->args['items_before_each_inject'] );
return ( $count > 0 ) ? $count : 1;
}
public function loop_start( WP_Query $query )
{
$this->query = $query;
if( $query->is_main_query() )
{
$args = array(
'post_type' => $this->args['cpt'],
'posts_per_page' => $this->cpt_items_on_this_page( $query ),
'paged' => $this->args['paged'],
'suppress_filters' => TRUE,
);
$this->results = new WP_Query( $args );
add_action( 'the_post', array( $this, 'the_post' ) );
}
}
public function loop_end( WP_Query $query )
{
if( $query->is_main_query() )
remove_action( 'the_post', array( $this, 'the_post' ) );
}
public function the_post()
{
if( ! $this->inject_mode
&& 0 < $this->nr
&& 0 === $this->nr % $this->args['items_before_each_inject'] )
{
$this->inject_mode = TRUE;
$this->results->rewind_posts();
$this->results->current_post = ( absint( $this->nr / $this->args['items_before_each_inject'] ) -1 ) * $this->args['cpt_items_per_inject'] - 1;
$j = 1;
if ( $this->results->have_posts() ) :
while ( $this->results->have_posts() ) :
$this->results->the_post();
get_template_part( $this->args['template_part'] );
if( $this->args['cpt_items_per_inject'] < ++$j )
break;
endwhile;
wp_reset_postdata();
endif;
$this->inject_mode = FALSE;
}
if( ! $this->inject_mode )
$this->nr++;
}
}
I tested this on the default theme, where I injected page content into the main post loop. The pagination seemed to work as well.
This can be refined more, but hopefully this is a starting point for you.
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