The problem is the loop:
foreach ( $hadices as $post ) : setup_postdata( $post );
if ( have_posts()) : while (have_posts()) : the_post();
setup_postdata( $post ); ?>
<h2><a href="https://wordpress.stackexchange.com/questions/302904/<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<?php the_content(); ?>
<?php endwhile;
endif;
endforeach;
wp_reset_postdata();
If we fix the indenting and format it properly we get:
foreach ( $hadices as $post ) {
setup_postdata( $post );
if ( have_posts()) {
while (have_posts()) {
the_post();
setup_postdata( $post );
?>
<h2>
<a href="https://wordpress.stackexchange.com/questions/302904/<?php the_permalink(); ?>">
<?php the_title(); ?>
</a>
</h2>
<?php
the_content();
}
}
}
wp_reset_postdata();
Now lets write it out as pseudocode/plain english:
for each hadices post
Set the current post
if the main query has posts
for each post in the main query
Set the current post as the post from the main query
Set the current post as the current post
output the post
After the loop, reset the post data
We can see that for some reason there’s 2 post loops, and the current post is set 3 times. On top of that, the code uses $post which is the name of a global variable.
So instead, lets rewrite this as a standard WP_Query loop:
$q = new WP_Query([
'post_type' => 'hadices',
'orderby' => 'rand',
'posts_per_page' => 1,
]);
if ( $q->have_posts() ) {
while( $q->have_posts() ) {
$q->the_post();
// output the post
}
wp_reset_postdata();
} else {
echo '<p>None were found</p>';
}
Notes:
the_postcallssetup_postdatainternally, you don’t have to call it againget_postscallsWP_Queryinternally, cut out the middle man and go straight forWP_QueryWP_Querymakes use of caching mechanisms, making it a little fasterposts_per_pageexpects a number, you don’t have to wrap it in quotes,1will do, it doesn’t have to be"1"- Indent Indent indent! Your editor should be indenting for you, so ti should be effortless. Use an editor such as SublimeText or Atom if you want a free program, or opt for a more advanced IDE such as PHPStorm. All 3 have packages that can reformat entire files at the press of a button
- Don’t use
<?php ?>spam, this:echo '<br/>';is the same as?><?php echo '<br/>';?><?phpbut easier to read - Your original code never checked if any posts were found
- You should put the
wp_reset_postdatacall inside the if statement - Your post type is named as a plural,
hadices, but technically it should behadice, or I presumehadith, you can change the URL used when registering the post type via therewriteoption
Improving Performance
rand isn’t just slow, it’s one of the slowest things you can ask a server to do. Some implementations will create a brand new table with the same data randomly ordered, then perform a query on the new table and destroy it afterwards, which becomes extremely slow with large numbers of posts.
So instead, lets do the random part in PHP, the plan:
- Ask for a single post from the database
- Figure out which post to pick from PHP
First, lets figure out how many hadices posts there are using wp_count_posts:
$counts = wp_count_posts( 'hadices', false );
Then, lets generate a number between 0 and the maximum number of posts:
$counts = wp_count_posts( 'hadices', false );
$offset = mt_rand( 1, $counts->publish );
Then, lets tell it to use the number we generated as an offset, so if the offset is 12, then we want the 12th hadices post, if the number is 212, we want the 212th hadices post.
So lets plug that into our improved query, by using the offset to request the page, and having 1 post per page:
$q = new WP_Query([
'post_type' => 'hadices',
'posts_per_page' => 1,
'page' => $offset,
]);