How To Get WordPress To Display What You Want

Depending on the URL of the page you’re visiting, WordPress creates a Query.

This is how WordPress talks to the database to get the information that gets displayed on the page.

For instance, if you’re on the blog page, WordPress creates a query that asks the database for the ten latest posts. Again, if you click a link to a single post page, WordPress queries the database for the requested post.

This query is also known as the main query, that is, the default query that WordPress creates to retrieve data according to the requested page.

Let’s say, however, that we’d like to customize what WordPress retrieves as it accesses the Blog page, or the Archives page. This is the case if, for example, we want three post excerpts only from the Sticky category but not from other categories on the home page.

This calls for changing the default WordPress query. Here are the three recommended ways on how to do this.

The Loop

The heart of WordPress functionality is what’s known as The Loop. In WordPress.org’s words:

The Loop is PHP code used by WordPress to display posts. Using The Loop, WordPress processes each post to be displayed on the current page, and formats it according to how it matches specified criteria within The Loop tags.

In other words, The Loop is the block of PHP code WordPress uses to display posts returned by the query to the database , one by one, and it runs repeatedly until it reaches the number of posts set in the Reading Settings of the WordPress admin panel.

There are 3 parts to The Loop

  1. Start The Loop
  2. Do something with each post/page found by The Loop
  3. Close The Loop

Here’s a snippet of the (very famous) default Loop taken from the WordPress Codex page:

<!-- If there are any posts, and while there are any -->
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
  
  <!-- Display post structure and content -->
  
<!-- Stop The Loop (but note the "else:" - see next line). -->
<?php endwhile; else: ?>

<!-- The very first "if" tested to see if there were any Posts to -->
<!-- display.  This "else" part tells what do if there weren't any. -->
  <p>Sorry, no posts matched your criteria.</p>


<!-- REALLY stop The Loop. -->
<?php endif; ?>

How To Customize Our Blog Posts Display

For my examples, I’ve used the Landscape free WordPress theme by Blank Themes. First of all, I’ve created a child theme, where all tests are carried out.

There are 3 recommended ways to customize the WordPress default query:

Let’s examine them one by one.

pre_get_posts

If we want to modify the main query, the best option is to use pre_get_posts. Why? Because, in the words of the WordPress Codex:

This hook is called after the query variable object is created, but before the actual query is run.

This is quite handy in that it allows us to modify the query before results are printed on the screen.

Since this hook involves other queries besides the main query, the most important thing to keep in mind when using pre_get_posts is to make sure the code is targeting the main query.

To follow along with the examples, you need a child theme for testing. Also, add a functions.php file to your child theme. This is a PHP file where your theme’s functionality is stored. Open this file and add an opening php tag at the very top:

<?php

Here’s a quick example.

Exclude Categories With ID 2 And ID 3

First of all, if you have pretty permalinks set up in your WP install, to know the ID of the categories you want to exclude do the following:

  • Go to the Posts > Categories admin panel
  • With your mouse cursor, hover on each category link
  • The category ID will appear in the browser’s status bar.

In functions.php, below the opening php tag, let’s add this function:

function exclude_category( $query ) {
  if ( $query->is_home() && $query->is_main_query() ) {
    $query->set( 'cat', '-2,-3' );
  }
}
add_action( 'pre_get_posts', 'exclude_category' );

The code above does the following:

  • The function takes the query as parameter and checks if we’re on the home page.
  • Then it also makes sure that the query we’re manipulating is the main query. As we have seen above, this is crucial to avoid messing up other queries that WP might be running.
  • After performing the two checks above, categories with IDs 2 and 3 are excluded from the query (The – minus sign excludes the piece of data from the results returned by the database).
  • Finally, our exclude_category function is hooked to the pre_get_posts action.

Now, let’s open index.php and have a look at the existing Loop. This doesn’t need to be touched, however, when it runs, our exclude_category function will work its magic and you’ll see that the designated categories will not be displayed on the page.

For more examples, visit the WP Codex pre_get_posts page.

get_posts Function

If we don’t need to modify the main query, and our target is a secondary query, then get_posts() is our friend.

Here’s how to use it.

Display 5 Random Posts In The Footer Area

Let’s leave the main loop in index.php alone and add a list of 5 random posts in the footer area. First of all, we copy over footer.php from the parent to the child theme and open it in the code editor.

Next, we need to add a function to our functions.php file. We could write this code straight into the footer template file, but I prefer working with functions and leave the template as clean as possible.

Here it is.

function my_random_posts() {
  //create arguments 
  $args = array( 'posts_per_page' => 5, 'orderby' => 'rand' );
  //return the customized list of posts
  return get_posts( $args );
}

The my_random_posts function prepares a list of criteria ($args) and returns a list of posts that meets with the specified criteria.

Finally, we need to call this function and display its results. We do this in footer.php. Let’s find a suitable spot in the footer area and add this snippet of code.

<?php
//call our my_random_posts() function
$rand_posts = my_random_posts();

//if the function returns any posts
if ($rand_posts) : ?>
  <div class="random-posts">
    <h3>Random Posts</h3>
    <ul>
	
<?php
  //loop over each one and display it 
  foreach ( $rand_posts as $post ) : setup_postdata( $post ); ?>
    <li><a href="<?php the_permalink() ?>"><?php the_title() ?></a></li>
  <?php endforeach; ?>
	
<?php
  //restore original post data
  wp_reset_postdata(); ?>
	
  </ul>
</div>

<?php endif;  ?>

The code snippet above calls the my_random_posts function and stores the list of returned posts in the $rand_posts variable. Next, it loops over each post and displays their linked title in a list.

Notice the use of setup_postdata( $post ) and of wp_reset_postdata(). The first allows us to use WordPress template tags, in our case the_permalink() and the_title().

The second is crucial to reset the data. In fact, when get_posts is used, the main post data from the default query is overwritten. By resetting the data, functions we may want to use later on that relate to the main query don’t get caught up with the leftover data from our modified query.

Let’s save our work and preview the result in the browser. I can see a list of 5 random posts at the bottom of the Landscape Child theme.

get_posts WordPress function
get_posts WordPress function

More detailed information about get_posts can be found on the WP Codex page, including an exhaustive list of arguments that can be used with this handy WP function.

WP_Query Class

The WP_Query class allows us to manipulate the WP Loop in any way we like – it’s amazingly powerful. Also, it’s the recommended method to use when we need to call multiple loops on a page.

Let’s show an example.

Display A List Of Posts Only If They Belong To Two Given Categories

Let’s say we’d like to display a short list (2 titles) of posts that belong to two given categories. Not to one or the other, but to both. Below this short list, we’d like to display all other posts, except those displayed above.

In my WordPress set up, I have 3 posts belonging to the category Featured, but only two of them, i.e., Links Post and Ul and Ol Post, belong both to the Featured and Uncategorized categories. Let’s display just these two posts using WP_Query.

I already know that Uncategorized has a category ID of 1 and that Featured has a category ID of 5. Let’s use index.php in our child theme.

Here’s the code for the first Loop, the one we customize using WP_Query. I added this Loop after a check to make sure I was on the blog page or the front page of the site.

<?php
  //prepare arguments to customize the query 
  $args = array ('category__and' => array( 1, 5 ) );
					
  //create an instance of the WP_Query class 
  $uncat_featured_posts = new WP_Query( $args );

  // array to store the posts IDs for the first loop
  $do_not_duplicate = array(); 
?> 

<?php 
  //first loop
  if ( $uncat_featured_posts->have_posts() ) :  
?>

<?php /* Start the Loop */ ?>
<?php 
    while ( $uncat_featured_posts->have_posts() ) : 
	  $uncat_featured_posts->the_post(); 
?>

<?php
      // save posts ID's in loop so that these posts will not be displayed in the second loop 
      $do_not_duplicate[] = $post->ID; 
?>
    <h3>
	  <a href="<?php the_permalink() ?>"><?php the_title() ?></a>
    </h3>
	
   <?php endwhile; ?>
	
  <?php wp_reset_postdata(); //reset post data ?>
	
 <?php endif; ?>

After saving index.php, only the two posts in categories 1 AND 5 will be displayed on the page.

Result returned using WP_Query
Result returned using WP_Query

Using the WP_Query class involves these steps.

  • Set out the criteria for your query and save them in a variable
  • Create an instance of the WP_Query class
  • Loop using the instance of the WP_Query class:
    while ( $uncat_featured_posts->have_posts() ) : 
      $uncat_featured_posts->the_post(); 
    
  • Reset the post data soon after the while loop:
    wp_reset_postdata();

Just below this customized first loop, we’re free to run the regular loop, making sure this is not going to spit out duplicate posts. For this, we use the do_not_duplicate array where the IDs of the previous posts have been stored.

<?php if ( have_posts() ) : //regular loop ?>

  <?php while ( have_posts() ) : the_post(); ?>
  
  <?php
        //display posts only if they are not in the do_not_duplicate array 
        if ( ! in_array( $post->ID, $do_not_duplicate ) ) :
  ?>
       //Display post here 
	   
    <?php endif; ?>
  <?php endwhile; ?>
<?php endif; ?>

After saving index.php, here’s the final result.

Result using WP_Query and a regular Loop
Result using WP_Query and a regular Loop

To know more about all the plethora of possibilities offered by the WP_Query class, the WP Codex page is the first port of call.

To Sum Up

This has been a long, code-intensive post. If you’re new to WordPress coding and made it this far, congratulations!

All this goes to show that WordPress is so much more than a simple posts spitting platform, and that you can extract content in just about any way you like.

Pretty powerful, hey! But with great power comes great responsibility. There will be times when you’ll want to use the techniques shown in this post, but really a lot of customization can be done with CSS alone.

Let me know your experience of manipulating the default WordPress Loop. I look forward to hearing from you in the comments below.
Advertisements

Have your Say

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s