The Loop (Wrox Book)

The Loop

 WordPress determines what content (posts, pages, or custom content) to display on a page you are visiting. The Loop can display a single piece of content or a group of posts and pages that are selected and then displayed by looping through the content; thus, it’s called the Loop.

The Loop selects posts from the MySQL database based on a set of parameters, and those parameters are typically determined by the URL used to access your WordPress website. 

A category page, accessed via a URL such as http://example.com/category/halloween/, shows only blog posts assigned to that category, in this case, posts put into the Halloween category. An archive page shows only blog posts that are dated with that particular month and year.  

UNDERSTANDING THE LOOP

Understanding how the Loop functions will help you understand how you can control it.

To understand the Loop, it helps to break down the steps WordPress takes to generate a page’s
content:


1. The URL is matched against existing files and directories in the WordPress installation. If the
file is there, it is loaded by the web server. 


2. If the URL doesn’t load a WordPress core file, it has to be parsed to determine what content
to load. The web server starts by loading the WordPress core through
index.php to begin the
setup for the Loop.


3. The translation of URL‐to‐content‐selection magic happens inside of the parse_query()method within the WP_Query object that WordPress created early on in its processing.
WordPress parses the URL first into a set of query parameters that are described in the next
section. For example,
http://example.com/tag/bacon is the same as http://example
.com?tag=bacon
, which conveys a query string of tag with a value of bacon.


4. WordPress then converts the query specification parameters into a MySQL database query to retrieve the content. The workhorse here is the get_posts() method within the WP_Queryobject. The get_posts()method takes all of those query parameters and turns them into SQL statements.


5. Once the content is retrieved, WordPress sets all of the is_ conditional tags such as is_
home()
and is_page(). These are set as part of executing the default query based on the
URL parsing, and you’ll consider cases where you may need to reset these tags.


6. WordPress picks a template from your theme based on the type of query and the number of
posts returned—for example, a single post or a category‐only query—and the output of the
the query is passed to this default invocation of the Loop.


From Query Parameters to SQL 

 The basic format of a SQL query is SELECT fields FROM table WHERE conditions. “Fields” are
the columns of the database that you want to be returned; you usually don’t need to modify this part
of the query. The “conditions” specified in the
WHERE clause change the ordering, grouping, and a number of posts returned. 

“Table” is not simply the “posts” table in the MySQL database that contains all post data; it
may also refer to an SQL JOIN of two or more tables where you need to select posts based on
hierarchical metadata.


WordPress data model uses multiple tables to manage these complex relationships, but that makes queries such as “find all posts tagged bacon” more difficult to execute. For example, to select the posts tagged bacon, an SQL JOIN is needed to first find bacon in the metadata taxonomy, build an intermediate, in‐memory table of posts that have been tagged with bacon, and then select posts whose IDs appear both in the intermediate table and the main WordPress content table.

If you want to explore the core for the gory details of SQL generation, most of the query‐to‐request parsing is done in wp‐includes/query.php, and the bulk of the JOIN work is set up in wp‐includes/taxonomy.php.  

WordPress will insert a LIKE modifier into the WHERE clause that contains the post name.
For example, if a user supplies the URL
http://example.com/2015/lecter, but you have no
posts with the title “Lecter,” the
LIKE clause will match any posts that start with “Lecter,” such as
“Lecter Fish IPA Review.” Canonical URLs and “like name” matching are part of the complex maze
of URL rewriting and intent parsing that try to generate a pleasant user experience, rather than an
annoying 404 error


Putting the Loop in Context  

The Loop is the heart of a theme, which is what controls how your content is displayed. It is the
functional connection between the MySQL database data and the HTML that is rendered in the
visitor’s browser.
 

The Loop, by default, is used in your WordPress theme template files. Custom Loops can be
created anywhere in your theme template files.

Multiple Loops can be used throughout your theme template files. Custom Loops can be created in your header, sidebars, footer, and main content areas of your website. There is no limit to the number of Loops that can be displayed on your website. 

The flow of the Loop 

The Loop uses some standard programming conditional statements to determine what and how to display. The first statement in the Loop is an if statement that checks whether any posts exist because you might not have any posts with the specified category or tag. If content exists, the while statement is used to initiate the Loop and cycle through all posts or pages that need to be displayed. Finally, the _ post() function is called to build the post data, making it accessible to other WordPress functions. Once the post data has been built, Loop content can be displayed in whatever format you like.
Following is a minimal Loop example. This example features the only required elements for the
Loop to function properly:<?php
if ( have_posts() ) :
while ( have_posts() ) :
the_post();
//loop content (template tags, html, etc)
endwhile;
endif;
?>

If you’re wondering how the output from the database query got handed to this simple Loop when there are no variables passed as parameters, the answer lies in the global variable $wp _ query, which is an instance of WP _ Query that is referenced by the functions in the simple Loop. It is, in effect, the default query for the Loop. Note that by the time this default Loop is called, WordPress has already called the get _ posts() method within the default query object to build the list of appropriate content for the URL being viewed.

Some very minimal requirements exist for the Loop to work in WordPress. Let’s break down this
example to look at the different parts of the Loop:

if ( have_posts() ) :

This line checks if any posts or pages are going to be displayed on the current page you are viewing.
If posts or pages exist, the next line will execute:

while ( have_posts() ) :

The preceding while statement starts the Loop, essentially looping through all posts and pages to
be displayed on the page until there are no more. The Loop will continue while content exists to
be displayed. Once all content has been displayed, the
while loop will end. The have _ posts()the function simply checks to see if the list of posts being processed is exhausted, or had no entries to
begin with.

the_post();

Next, the the_ post() function is called to load all of the post data. This function must be called
inside your loop for the post data to be set correctly. Calling
the _ post() in turn calls the setup _
postdata()
function to set up the per‐post metadata such as the author and tags of the content you
are displaying in the Loop, as well as the content of the post itself.
  

This is where all Loop template tags are placed and any additional code you want to be displayed inside the Loop. This is covered in more detail later in this chapter.

endwhile;
endif;

The endwhile and endif calls end the Loop. Any code placed after these two lines will show at
the bottom of your page, after all posts have been displayed. You could also place an
else clause to
display a message if there is no content to display in the Loop.
  
else :
// If no content, include the "No posts found" template.
get_template_part( 'content', 'none' );
endif;
  

TEMPLATE TAGS

PHP functions used in your WordPress theme templates to display Loop content are called template
tags
. These tags are used to display specific pieces of data about your website and content. This
allows you to customize how and where content is displayed on your website.
For example, the
the _ title() template tag displays the title of your post or page inside the Loop.
The major benefit of using template tags is that you don’t need to know PHP code to use them.
 

Commonly Used Template TagsThere is no shortage of template tags, but typically you will use only a handful of tags in your
Loops. Following are the most commonly used template tags available in the Loop. These template
tags will return and display the post data listed.

the_permalink()—Displays the URL of your post.the_title()—Displays the title of the post.


the_ID()—Displays the unique ID of your post.the_content()—Displays the full content of your post.the_excerpt()—Displays the excerpt of your post. If the Excerpt f eld is filled out on the Post edit screen, that will be used. If not, WordPress will auto‐generate a short excerpt from your post content.the_time()—Displays the date/time your post was published.the_author()—Displays the author of the post.the_tags()—Displays the tags attached to the post.the_category()—Displays the categories assigned to the post.edit_post_link()—Displays an edit link that is shown only if you are logged in and allowed to edit the post.comment_form()—Displays a complete commenting form for your post.

<?php
if ( have_posts() ) :
while ( have_posts() ) :
the_post();
?>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
<br />
<?php
the_content();
endwhile;
endif;
?>


Commonly Used Template Tags


There is no shortage of template tags, but typically you will use only a handful of tags in your Loops. Following are the most commonly used template tags available in the Loop. These template tags will return and display the post data listed.


➤ the_permalink()—Displays the URL of your post.
➤ the_title()—Displays the title of the post.
➤ the_ID()—Displays the unique ID of your post.
➤ the_content()—Displays the full content of your post.
➤ the_excerpt()—Displays the excerpt of your post. If the Excerpt f eld is filed out on the Post edit screen, that will be used. If not, WordPress will auto‐generate a short excerpt from your post content.
➤ the_time()—Displays the date/time your post was published.
➤ the_author()—Displays the author of the post.
➤ the_tags()—Displays the tags attached to the post.
➤ the_category()—Displays the categories assigned to the post.
➤ edit_post_link()—Displays an edit link that is shown only if you are logged in and allowed to edit the post.

➤ comment_form()—Displays a complete commenting form for your post.

Tag Parameters

Most template tags have parameters that can be added to modify the value returned. For example, the the _content() template tag has two parameters. The first parameter allows you to set the more link text like so:

<?php the_content( 'Read more', false ); ?>

Your post content will be displayed as normal, but when the <!––more––> tag is found in your post, WordPress will automatically add the text Read more, which would link to the entire blog post. The second parameter determines whether to display the teaser paragraph again when viewing the full
post. The default value is false so the teaser will be displayed in both places.

You can also send multiple parameters to any template tag that supports it. For example, the template tag the _ title() accepts three parameters: $before, $after, and $echo. The following code sets the the _ title() tags $before and $after parameters to wrap the post title with h1 tags:

<?php the_title( '<h1>', '</h1>' ); ?>

CUSTOMIZING THE LOOP  

Both query _ posts() and get _ posts() use the WP _Query class to retrieve content. The final method you’ll examine is the pre _ get _ posts hook. This
hook is called after the query variable object is created but before the actual query is run.


WP _ Query is a class defined in WordPress that makes it easy to create your own custom Loops.Both query _ posts() and get _ posts() use the WP _ Query class to retrieve the WordPress content. When you’re using query _ posts(), the global variable $wp _ query is used as an instance of WP _ Query, making $wp _ query the default data store for several operations. Custom Loops can be used anywhere in your theme template files to display different types of content; they must build on separate instances of a WP _ Query variable.

The following is an example of a custom Loop displaying the fve most recent posts on your website:

<?php
$myPosts = new WP_Query( 'posts_per_page=5' );while ( $myPosts-
>have_posts() )
: $myPosts->the_post();
?>
<!–– do something ––>


<?php endwhile; ?>
 


Rather than using the simpler have _ posts() and the _ post() calls that you saw in the basic Loop, this custom loop calls the methods of the newly created WP_Query object $myPosts. The explicit invocation is shown here and the default have _ posts() call are functionally equivalent; have _ posts(),
for example, is merely calling
$wp _ query‐>have _ posts() using the global query variable for the default query—that is, the one generated from parsing the URL handed to WordPress by the web server

Building a Custom Query  

Post Parameters 

➤ p=2—Loads an individual post by ID.
➤name=my‐slug—Loads posts based on post slug (permalink tail).
➤ post_status=pending—Loads posts by post status. For example, if you choose to see only drafts, use post_status=draft.
➤ ignore_sticky_posts—Excludes sticky posts from being returned first. A sticky post is one that always sorts to the top of the list of posts, independent of the other parameters set for the query. You can have multiple sticky posts, making them useful for calling attention to news announcements, highlighting changes, or otherwise grabbing the reader’s attention, and this parameter lets you drop them from their priority slot at the top of the list.
➤post_type=post—Loads posts based on type. If you only want to look at pages, not posts, post_type=page will retrieve them.
➤ posts_per_page=5—Number of posts to load per page. This is the default. To show all posts, set this parameter to –1.
➤ offset=1—Number of posts to skip before loading.


Page Parameters

➤page_id=5—Loads an individual page by ID. Like post IDs and user IDs, page IDs can be found in the dashboard by hovering over a page and looking at the URL displayed at the bottom on your browser.
➤ pagename=Contact—Loads a page by name, in this case the Contact page.
➤ pagename=parent/child—Loads a child page by slug, or hierarchy of slugs (that is, its path).


Category, Tag, and Author Parameters


➤ cat=3,4,5—Loads posts based on category ID.
➤ category_name=About Us—Loads posts based on category name.
➤ tag=writing—Loads posts based on tag name.
➤ tag_id=34—Loads posts based on tag ID.
➤ author=1—Loads posts based on user ID.
➤ author_name=brad—Loads posts based on author’s name.
➤ author__in & author__not_in—Loads posts based on user ID.

Date and Time Parameters

➤monthnum=6—Loads posts created in June.
➤ day=9—Loads posts created on the ninth day of the month.
➤ year=2015—Loads posts created in 2015.

Ordering and Custom Field Parameters

You can also change the sort parameter and the sort order. If you’re building an online index, and want to show an alphabetical post listing, you’ll set the parameters for querying posts by month and author, but order the results by title. Custom field parameters allow you to query posts based on post metadata.
➤ orderby=title—Field to order posts by.
➤order=ASC—Defines ascending or descending order of orderby.
➤meta_key=color—Loads posts by custom field name.
➤meta_value=blue—Loads posts by custom field value. Must be used in conjunction with the meta_key parameter.
➤meta_query—Used for more advanced custom f eld (metadata) queries.

examples using parameters  

Display post based on post ID:

$myPosts = new WP_Query( 'p=1' );

Display the fve latest posts, skipping the frst post:

$myPosts = new WP_Query( 'posts_per_page=5&offset=1' ); 

Display all posts from today:

// display all posts from the current date
$today = getdate(); // get todays date
$myPosts = new WP_Query('year=' .$today["year"].'&monthnum=' .$today["mon"] .'&day=' .$today["mday"] );


Display all posts from October 31, 2015:

$myPosts = new WP_Query( 'monthnum=10&day=31&year=2015' ); 

Display all posts from category ID 5 with the bacon tag:

$myPosts = new WP_Query( 'cat=5&tag=bacon' );

Display all posts with the bacon tag, excluding posts in category ID 5:

$myPosts = new WP_Query( 'cat=-5&tag=bacon' );

Display all posts with the tag writing or reading:

$myPosts = new WP_Query( 'tag=writing,reading' );

Display all posts with the tags writing and reading and tv:

$myPosts = new WP_Query( 'tag=writing+reading+tv' );

Display all posts with a custom feld named color with a value of blue:


$myPosts = new WP_Query( 'meta_key=color&meta_value=blue' );

Adding Paging to a Loop  

If your custom Loop requires paging (navigation links), you will need to take a few extra steps. Paging is currently designed to work only with the $wp _ query global variable; that is, it works within the default Loop and requires some sleight of hand to make it work in custom Loops. You need to trick WordPress into thinking your custom query is actually $wp _ query in order for paging to work.

 <?php
$temp = $wp_query;
$wp_query= null;
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$wp_query = new WP_Query( 'posts_per_page=5&paged='.$paged );
while ( $wp_query->have_posts() ) : $wp_query->the_post();
?>
<h2>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</h2>
<?php the_excerpt(); ?>
<?php endwhile; ?>

First, you have to store the original $wp _ query variable into the temporary variable $temp. Next, you set $wp _ query to null to completely flush it clean. This is one of the few times it’s acceptable to overwrite a global variable value in WordPress. Now set your new WP _ Query object into the $wp _ query variable and execute it by calling the object’s query() function to select posts for your custom Loop. Notice the $paged variable added to the end of the query. This stores the current page, using the get _ query _ var() function, so WordPress knows how to display the navigation links. Now display your navigation links for paging:

<div class="navigation">
<div class="alignleft"><?php previous_posts_link( '« Previous' );
?></div>
<div class="alignright"><?php next_posts_link( 'More »' ); ?></div>
</div>

<?php
$wp_query = null;
$wp_query = $temp;
?>



Using the pre_get_posts Hook

The pre_get_posts hook allows you to modify any Loop query on your WordPress website. In short, this hook makes it very easy to modify a WordPress Loop prior to making a call to the database to retrieve the content. When using the pre _ get _ posts hook, you’ll generally place the code in your theme’s functions .php fle. Let’s look at an example of pre _ get _ posts in action:

function prowp_exclude_category( $query ) {
if ( $query->is_home() && $query->is_main_query() && ! is_admin() ) {
$query->set( 'category_name', 'halloween' );
}
}
add_action( 'pre_get_posts', 'prowp_exclude_category' );

In the preceding example, you are modifying the main WordPress Loop to only show posts in the halloween category on the home page. As you can see, the example uses conditionals to verify that the query is only modifed on the home page, is the main query, and is not the admin dashboard.

By default, WordPress search includes posts and pages. Let’s assume you want only posts returned in your search results:

function prowp_search_filter( $query ) {
if ( ! is_admin() && $query->is_main_query() && $query->is_search() ) {
$query->set( 'post_type', 'post' );
}
}
add_action( 'pre_get_posts', 'prowp_search_filter' );

The pre _ get _ posts hook flters a WP _ Query object, which means anything you can do with WP _ Query you can also do with pre _ get _ posts using the set() function.



Using query_posts( )

The query _ posts() function is used to easily modify the content returned for the default WordPress Loop. Specifically, you can modify the content returned in $wp _ query after the default database query has executed, fine‐tune the query parameters, and re‐execute the query using query _ posts(). The downside to calling query _ posts() in this fashion is that the previously cached results from the default query are discarded, so you’re incurring a database performance hit to use this shortcut. The query _ posts() function should be placed directly above the start of the Loop:

query_posts( 'posts_per_page=5&paged='.$paged );
if ( have_posts() ) :
while ( have_posts() ) : the_post();
//loop content (template tags, html, etc)
endwhile;
endif;

This example tells WordPress to display only five posts.

Explicitly calling query _ posts() overwrites the original post content extracted for the Loop. This means any content you were expecting to be returned before using query _ posts() will not be returned.

To avoid losing your original Loop content, you can save the parsed query parameters by using the

$query _ string global variable:
// initialize the global query_string variable
global $query_string;
// keep original Loop content and change the sort order
query_posts( $query_string . "&orderby=title&order=ASC" );

In the preceding example, you would still see all of your zombie category posts, but they would be ordered alphabetically by ascending title. This technique is used to modify the original Loop content without losing that original content. You can also pack all of your query _ posts() parameters in an array, making it easier to manage.

side effects or cautions:

➤ query_posts() modif es the global variable $wp_query and has other side effects. It should not be called more than once and shouldn’t be used inside the Loop. Calling query_posts() more than once, or inside the Loop itself, can result in your main Loop being incorrect and displaying unintended content.
➤query_posts() unsets the global $wp_query object, and in doing so, may invalidate the values of conditional tags such as is_page() or is_home().

➤ Calling query_posts() executes another database query, invalidating all of the cached results from the first, default query.

Using get_posts( )

Like query _ posts(), there’s an alternative, simpler access function called get _ posts() that retrieves raw post data. You’ll see get _ posts() used in administration pages to generate a list of pages of a particular type, or it may be used within a plugin to grab all raw data for a set of posts and
examine it for patterns such as common terms, tags, or external links, with the intent of discarding the content after a quick digestion. It’s not intended for user‐facing content display because it turns off much of query processing and filtering that is done within the more general WP _ Query approach.

What get _ posts() lacks, specifcally, is the ability to set up all of the global data needed to make template tags reflect the current post data. One main issue is that not all template tags are available to get _ posts() by default. To fx this defciency, you need to call the setup _ postdata()
function to populate the template tags for use in your Loop. The following example shows how to retrieve a single random post using get _ posts():

<?php
$randompost = get_posts( 'numberposts=1&orderby=rand' );
foreach( $randompost as $post ) :
setup_postdata( $post );
?>
<h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
<?php the_content(); ?>
<?php endforeach; ?>

You’ll notice another major difference using get _ posts()—the value returned is an array. The foreach loop code is used to cycle through the array values. This example returns only one post, but if more than one were returned, this would cycle through each. Then the setup _ postdata() function is called to populate the data for your template tags.

Remember that you can also set up your get _ posts() parameter using an array:

<?php
$args = array(
'numberposts' => 1,
'orderby' => rand
);
$randompost = get_posts( $args );



When working with Loops in WordPress, it’s important to understand what Loop method to use and when. The pre _ get _ posts hook should be used when altering the main query on the page. The WP _ Query object should be used for all secondary Loops in your theme templates and plugins.


Resetting a Query


When customizing the main Loop, or creating custom Loops, it’s a good idea to reset the Loop data after you are done. WordPress features two different functions to handle this: wp _ reset _postdata() and wp _ reset _ query().

The first method for resetting post data is wp _ reset _ data(). This function actually restores the global $post variable to the current post in the main query. This is the preferred method when using WP _ Query to create custom Loops.

For example, assume you have the following custom Loop in your theme’s header.php fle:

<?php
$myPosts = new WP_Query( 'posts_per_page=1&orderby=rand' );
// The Loop
while ( $myPosts->have_posts() ) : $myPosts->the_post();
?><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a><br
/><?php
endwhile;
?>

This will display a random post in the header of your theme. This code will also change the main query object for other Loops on the page. The original query data will not be available, which could produce unexpected results on the main posts’ Loop for your theme.
To fx the problem, place a call to wp _ reset _ postdata() directly after your custom Loop like so:

$myPosts = new WP_Query( 'posts_per_page=1&orderby=rand' );
// The Loop
while ( $myPosts->have_posts() ) : $myPosts->the_post();
?><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a><br
/><?php
endwhile;
// Reset Post Data
wp_reset_postdata();


Calling this function will restore the $post variable to the current post in the query. This will eliminate any strangeness in the main query for the page you are viewing.

The second method available for resetting post data is the wp _ reset _ query() function. From time to time, you may run into problems with page‐level conditional tags being used after a custom Loop has been created. Conditional tags allow you to run different code on different pages in WordPress—
for example, using the conditional tag is _ home() to determine if you are viewing the main blog page. This problem is caused, as indicated in the “Using query_posts( )” section, by potentially changing the output of a database query after setting the conditional tags based on its original set of
values. To fx this issue, you need to call wp _ reset _ query(). This function will properly restore
the original query, including the conditional tags set up early in the URL parsing process.
Consider the following example:

<?php query_posts( 'posts_per_page=5' ); ?>
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a><br />
<?php endwhile; endif; ?>
<?php
if( is_home() && !is_paged() ):
wp_list_bookmarks( 'title_li=&categorize=0' );
endif;
?>

Executing this code will return the latest five posts followed by the links saved in your WordPress link manager. The problem you will run into is that the is _ home() conditional tag will not be interpreted correctly, meaning your links will show on every page, not just the homepage. To fx this
issue, you need to include wp _ reset _ query() directly below your Loop:

<?php query_posts( 'posts_per_page=5' ); ?>
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a><br />
<?php endwhile; endif; ?>
<?php wp_reset_query(); ?>
<?php
if( is_home() && !is_paged() ):
wp_list_bookmarks( 'title_li=&categorize=0' );
endif;
?>


Now that you have properly restored your Loop’s instance of the WP _ Query object, the conditional tag is _ home() will be followed and your links will now display only on the homepage of your website.

More Than One Loop

The Loop can be used multiple times throughout your theme and plugins. This makes it easy to display different types of content in multiple places throughout your WordPress website. 

Nested Loops

Nested Loops can be created inside your theme templates using a combination of the main Loop and separate WP _ Query instances. For example, you can create a nested Loop to display related posts based on post tags. The following is an example of creating a nested Loop inside the main Loop to
display related posts based on tags:

<?php
if ( have_posts() ) :
while ( have_posts() ) :
the_post();
//loop content (template tags, html, etc)
?>
<h1><a href="<?php the_permalink(); ?>"><?php the_title();
?></a></h1>
<?php
the_content();
$tags = wp_get_post_terms( get_the_ID() );Customizing the Loop ❘ 99
if ( $tags ) {
echo 'Related Posts';
$tagcount = count( $tags );
for ( $i = 0; $i < $tagcount; $i++ ) {
$tagIDs[$i] = $tags[$i]->term_id;
}$
args=array(
'tag__in' => $tagIDs,
'post__not_in' => array( $post->ID ),
'posts_per_page' => 5,
'ignore_sticky_posts' => 1
);
$relatedPosts = new WP_Query( $args );
if( $relatedPosts->have_posts() ) {
//loop through related posts based on the tag
while ( $relatedPosts->have_posts() ) :
$relatedPosts->the_post(); ?>
<p><a href="<?php the_permalink(); ?>">
<?php the_title(); ?></a></p>
<?php
endwhile;
}
}
endwhile;
endif;
?>

This code will display all of your posts as normal. Inside the main Loop, you check if any other posts contain any of the same tags as your main post. If so, you display the latest fve posts that match as related posts. If no posts match, the related posts section will not be displayed.

Multi‐Pass Loops

The rewind _ posts() function is used to reset the post query and loop counter, allowing you to do another Loop using the same content as the frst Loop. Place this function call directly after you fnish your frst Loop. Here’s an example that processes the main Loop content twice:

<?php while ( have_posts() ) : the_post(); ?>
<!–– content. ––>
<?php endwhile; ?>
<?php rewind_posts(); ?>
<?php while ( have_posts() ) : the_post(); ?>
<!–– content ––>
<?php endwhile; ?>






Comments