Introducing Custom Queries

Every Blog post will have some related articles to it and WordPress doesn’t have a predefined function to output those related articles. But they are a very important feature for a blog post.

Also, some times, you might want to display some blog posts at the bottom portion of the Homepage to keep the visitors engaged on the site. Again, WordPress doesn’t have a predefined function to achieve this. 

Although there are no predefined WordPress functions for the above requirements, WordPress provides us something more powerful!

Custom Queries!

WordPress allows us to query the posts we need using a custom query. 

You can write a custom query for any post type. Using custom queries, you can output the content of pages, blog posts, custom post types like a book, etc., anywhere on the site.

“So, how do we write a custom query? Do we have to use MySQL and write database queries?”

Don’t worry! You don’t even have to touch the MySQL. WordPress provides with something more powerful and convenient.

Introducing the WP_Query class

One of the main responsibilities of the WP_Query class is to query the database and fetch the requested posts.

WordPress uses the WP_Query class to create the main query based on URL requested and outputs the contents of this main query with the help of the Loop we placed in our template files. 

In other words, the main query that we discussed in the previous modules is an instance of the WP_Query class.

So, to create a custom query, all we have to do is create a new instance of the WP_Query class with a bunch of arguments which determine what posts must be fetched from the database.

And this custom query is not at all different from the main query. Both are instances of WP_Query class. Both do the same thing.

The only difference is that WordPress created the main query instance by deeply analyzing the URL and we will create the custom instance based on our requirement. 

This is better shown than explained.

Common, let’s use the WP_Query class to output three blog posts at the end of our Homepage.

Open up the front-page.php file and put the following code just before the end of the Loop, that is, just before the ENDWHILE statement:

<?php 
    $blog_posts_query = new WP_Query(
        array(
            'post_type' => 'post',
            "posts_per_page" => 3
        )  
 
    );
?>

First of all, we are instantiating the WP_Query class and passing it an array of arguments which tells what posts to retrieve from the database.

In our case, we are telling WP_Query class to retrieve posts belonging to post type of “post” (blog posts) and with the help of “posts_per_page” argument, we are telling to retrieve only three posts.

The result of this WP_Query class instantiation is a WP_Query Object which contains all the information about the query and most importantly, the content of three blog posts.

And, we are storing the resulted WP_Query object inside the $blog_posts_query variable. So, this variable now contains all the information we need to output. You can see it if you var_dump the $blog_posts_query variable. 

Anyway, how do we extract and output the blog posts from the WP_Query Object a.k.a $blog_posts_query variable?

Using the Loop to output the blog posts from the custom WP_Query object

Yep! say hello to the Loop again! 

The Loop works on top of the following two WordPress functions, right?

have_posts() and the_post()

If you view their source code, for example, the source code of  have_posts(), you can tell that the have_posts() function is just a wrapper for the have_posts()method of the main  $wp_query.


$wp_query->have_posts();

This $wp_query is the main query we are talking about. And this is a WP_Query object too!

So, all along the way, we are technically using the $wp_query object inside all our template files and our template files are outputting whatever the information that the $wp_query object contains. 

For example, if we use the following Loop instead of the current Loop inside our template files, everything will still work as is.


<?php global $wp_query; ?>   
<?php if ( $wp_query->have_posts() ): ?>
    <?php while( $wp_query->have_posts() ): ?>
        <?php $wp_query->the_post(); ?>
        /* Loop Code Goes Here */
    <?php endwhile; ?>
<?php endif; ?>

The key takeaway here is, We are extracting the content from the main query ( $wp_query ) by looping through it with the help of have_posts()method belongs to the WP_Query class.

$wp_query->have_posts();
WP_Query::have_posts();

And because of the fact that our custom $blog_posts_query object is an instance of the WP_Query class, we can also loop through our $blog_posts_query with the of help have_posts()method belongs to the WP_Query class.

$blog_posts_query->have_posts();

The only difference is that WordPress created the $wp_query object by deeply analyzing the URL and we manually created the $blog_posts_query object based on our requirement. 

So, $blog_posts_query has access to all the Loop methods like have_posts() and the_post()too! 

Common, let’s test this out. 

Go ahead and put the following Loop code right after the above query and just before the end of the existing Loop:


<?php if( $blog_posts_query->have_posts() ): ?>
    <?php while( $blog_posts_query->have_posts() ): ?>
        <?php $blog_posts_query->the_post(); ?>
        <?php the_title('<h1>', '</h1>'); ?>
    <?php endwhile; ?>
    <?php wp_reset_postdata(); ?>
<?php endif;  ?>
<!-- end of custom query loop -->

If we now open up the site’s Homepage in the browser, we should see the titles of the three most recent blog posts:

See, everything works seamlessly, right?

So, the bottom line is, the main query that WordPress creates and the custom queries that we create are the same! The only difference is who creates them and what posts they contain.

Now, replace the custom Loop we just added with the following code:


<?php if( $blog_posts_query->have_posts() ): ?>
    <section class="blog-posts">
        <h2><?php _e( 'Latest Articles', 'nd_dosth' ); ?></h2>
        <?php while( $blog_posts_query->have_posts() ): ?>
            <?php $blog_posts_query->the_post(); ?>
            <?php get_template_part( 'parts/blog', 'index' ); ?>
        <?php endwhile; ?>
        <?php wp_reset_postdata(); ?>
    </section>
<?php endif;  ?>
<!-- end of custom query loop -->

Nothing complex going on. Just added some bootstrap classes for the layout purposes and using the blog-index.php template part for rendering individual blog post’s content.

“Hey! what is that wp_reset_postdata() function doing?”

Oh! Thanks for reminding! 

Do not forget to reset post data

The thing is if you notice the above code, we have placed a custom loop inside the main loop. We call this as a nested loop.

And, Just like the Main Loop, the nested Loop affects the global $post variable too. 

If you remember, for every iteration of the Loop, the_post()method overrides the global $post variable.

And if you notice, the nested custom loop is calling the the_post()method as well.

And this is a problem because of the fact that all the template tags that we use inside the Loop depend on this $post variable.

For example, before our custom nested Loop got executed, the global $post variable contains the Homepage information, right?

And because we created a Nested Loop, this original global $post variable is overridden inside the custom Loop and by the time we are done with our custom Loop, the global $post variable contains the information about the third blog post rather than the Homepage.

And there are chances that we might output some more Homepage content after displaying these blog posts too.

So, we are calling the wp_reset_postdata() function after the custom query loop to restore the global $post variable to its original state, that is, a state which contains the Homepage content.

If you did not understand, just put the above custom query Loop right underneath the the_content() function and remove the wp_reset_postdata() function and see how it breaks the content of the Homepage.

Ah! Disaster! 

WordPress is not displaying all the following sections of the Homepage at all.

If you still did not understand, just remember to put wp_reset_postdata() whenever you write a custom loop.

Anyway, here is the final front-page.php file for this lesson:


<?php
/**
 * The front page template file.
 *
 * If the user has selected a static page for their homepage, this is what will
 * appear.
 * Learn more: http://codex.wordpress.org/Template_Hierarchy
 *
 * @package Dosth App
 */
 
 get_header();
 ?> 
<?php while( have_posts() ): ?>
    <?php the_post(); ?>
    <div class="actual-content above-the-fold">
        <div class="container">
            <div class="row">
                <div class="col-sm-12">
                    <?php the_content(); ?>
                </div>
            </div>
        </div>
    </div>
    <section id="watch-dosth-in-action">
        <h2><?php echo get_post_meta(get_the_ID(), 'second_section_headline', true ); ?></h2>
        <div class="section-content">
            <?php echo get_post_meta(get_the_ID(), 'section_two_content', true ); ?>
        </div>
    </section>
    <section id="section-three">
        <h2><?php echo get_post_meta(get_the_ID(), 'section_three_title', true ); ?></h2>
        <div class="section-content">
            <?php echo get_post_meta(get_the_ID(), 'section_three_content', true ); ?>
        </div>
    </section>
    <section id="app-feature-one">
        <img src="<?php the_field('feature_one_image'); ?>" />
        <div class="section-content">
            <?php echo get_post_meta(get_the_ID(), 'app_feature_one_content', true ); ?>
        </div>
    </section>
    <section id="app-feature-two">
        <img src="<?php the_field('app_feature_two_image'); ?>" />
        <div class="section-content">
            <?php the_field('app_feature_two_content'); ?>
        </div>
    </section>
    <?php 
        $blog_posts_query = new WP_Query(
            array(
                'post_type' => 'post',
                "posts_per_page" => 3
            )   
        );
    ?>
    <?php if( $blog_posts_query->have_posts() ): ?>
        <section class="blog-posts">
            <h2><?php _e( 'Latest Articles', 'nd_dosth' ); ?></h2>
            <?php while( $blog_posts_query->have_posts() ): ?>
                <?php $blog_posts_query->the_post(); ?>
                <?php get_template_part( 'parts/blog', 'index' ); ?>
            <?php endwhile; ?>
            <?php wp_reset_postdata(); ?>
        </section>
    <?php endif;  ?>
    <!-- end of custom query loop -->
<?php endwhile; ?> 
<?php get_footer(); ?>

And here is the output in the browser:

Ouch! This doesn’t look nice at all!

The expectation is that whenever we use a template part to render a modular section on any page of the site, it should look same.

The reality is, my intention of writing modular code is half baked. 

Applying some CSS will fix the styling part! 

Note: This is just a quick fix. Not a future proof solution in any manner.

Go ahead and put the following CSS inside the style.css file:


/*-------------------------------------------------------------------------------
  19.Homepage Blog List styling
-------------------------------------------------------------------------------*/
.home .blog-posts h2{
    width:100%;
    text-align:center;
}
.home .blog-posts{
    max-width:1000px;
    margin:50px auto;
}
.home .blog-posts .blog-post h2{
    text-align:left;
}
@media only screen and (min-width: 767px){
    .home .blog-posts .blog-post {
        width: 33%;
    }
}

Here is the updated outline of style.css file:

And here is the output in the browser: