Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I am pretty new in WordPress theme development and I'm not so into PHP (I came from Java and C#) and have the following situation in this custom theme

As you can see in the homepage I first show a section (named Articoli in evidenza) containing the featured posts (I've implemented it using a specific tag) and under it there is another area (named Ultimi Articoli) that contains the latest post that are not the featured post.

To do it I use this code:

<section id="blog-posts">

<header class="header-sezione">
        <h2>Articoli in evidenza</h2>
</header>

<!--<?php query_posts('tag=featured');?>-->



<?php
    $featured = new WP_Query('tag=featured');

    if ($featured->have_posts()) : 
            while ($featured->have_posts()) : $featured->the_post();
            /*
             * Include the post format-specific template for the content. If you want to
             * use this in a child theme, then include a file called called content-___.php
             * (where ___ is the post format) and that will be used instead.
             */
            get_template_part('content', get_post_format());

        endwhile;
        wp_reset_postdata();
    else :
        // If no content, include the "No posts found" template.
        get_template_part('content', 'none');

    endif;
    ?>


<header class="header-sezione">
    <h2>Ultimi Articoli</h2>
</header>

<?
// get the term using the slug and the tag taxonomy
$term = get_term_by( 'slug', 'featured', 'post_tag' );
// pass the term_id to tag__not_in
query_posts( array( 'tag__not_in' => array ( $term->term_id )));
?>

<?php
    if (have_posts()) :
        // Start the Loop.
        while (have_posts()) : the_post();

            /*
             * Include the post format-specific template for the content. If you want to
             * use this in a child theme, then include a file called called content-___.php
             * (where ___ is the post format) and that will be used instead.
             */
            get_template_part('content', get_post_format());

        endwhile;
    else :
        // If no content, include the "No posts found" template.
        get_template_part('content', 'none');

    endif;
    ?>

</section>

It works fine but I have some doubt about the quality of this solution and how exactly it works.

To select all the featured posts, I use this line that create a new WP_Query object that define a query having the specific tag featured:

$featured = new WP_Query('tag=featured');

Then I iterate on this query result using its have_posts() method.

So, from what I have understand, this is not the WordPress main query, but it is a new query created by me. From what I understand, it is better create a new query (as done) and not use the main query when I want perform this kind of operation.

Is it true or am I missing something? If it is true can you explain me why it is better create a new custom query and not modify the Wordpress main query?

Ok, going on. I show all the posts that have not the featured tag, to do this I use this code snippet that on the contrary to modify the main query:

    <?
    // get the term using the slug and the tag taxonomy
    $term = get_term_by( 'slug', 'featured', 'post_tag' );
    // pass the term_id to tag__not_in
    query_posts( array( 'tag__not_in' => array ( $term->term_id )));
    ?>

    <?php
        if (have_posts()) :
            // Start the Loop.
            while (have_posts()) : the_post();
get_template_part('content', get_post_format());

            endwhile;
        else :
            // If no content, include the "No posts found" template.
            get_template_part('content', 'none');

        endif;
        ?>

So I think that this is pretty horrible. Is it true?

To do the same operation I found this function that I have added to functions.php

function exclude_featured_tag( $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {
        $query->set( 'tag__not_in', 'array(ID OF THE FEATURED TAG)' );
    }
}
add_action( 'pre_get_posts', 'exclude_featured_tag' );

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

So from what I have understand it take a query object as input parameter and modify it selecting all the posts excluding a specific tag (in my case the featured tag posts)

So how can I use the previous query (the one used to show the featured posts) with this function to show the not featured post in my theme? Or do I have to create a new query?

share|improve this question

1 Answer 1

up vote 5 down vote accepted

Your actual question is basically when to run a custom query and when to make use of the main query. Lets break it down in three parts

PART ONE

When to run a custom query (This is not a definitive list)

  • To create custom content sliders

  • To create a featured content area in a page

  • On page.php templates if you need to display posts

  • If you require custom content on a static front page

  • Display related, popular or informational posts

  • Any other secondary or supplementary content outside the scope of the main query

When to make use of the main query.

To display the primary content on

  • On your homepage and the page set as a blogpage in the backend

  • All archive pages which includes templates like archive.php, category.php, author.php, taxonomy.php, tag.php and date.php

PART TWO

To select all the featured posts I use this line that create a new WP_Query object that define a query having the specific tag featured:

So, from what I have understand, this is not the WordPres main query but it is a new query created by me. From what I have understand it is better create a new query (as done) and not use the main query when I want perform this kind of operations

Correct. This falls out of scope for the main query. This is secondary or supplementary content which cannot be created with the main query. You SHOULD ALWAYS use either WP_Query or get_posts to create your custom queries.

NEVER USE query_posts to create custom queries, or even any other query. My emphasis.

Note: This function isn't meant to be used by plugins or themes. As explained later, there are better, more performant options to alter the main query. query_posts() is overly simplistic and problematic way to modify main query of a page by replacing it with new instance of the query. It is inefficient (re-runs SQL queries) and will outright fail in some circumstances (especially often when dealing with posts pagination).

Moving on

Ok, going on I show all the posts that have not the featured tag, to do this I use this code snippet that on the contrary modify the main query:

query_posts( array( 'tag__not_in' => array ( $term->term_id )));

So I think that this is pretty horrible. Is it true?

That is all wrong and your statement is unfortunately true. As said before, NEVER use query_posts. It runs a complete new query, which is bad for performance, and it most cases breaks pagination which is an integral part of the main query for pagination to work correctly.

This is your primary content, so you should be using the main query with the default loop, which should look like this, and this is all you need

<?php
    if (have_posts()) :
        // Start the Loop.
        while (have_posts()) : the_post();
get_template_part('content', get_post_format());

        endwhile;
    else :
        // If no content, include the "No posts found" template.
        get_template_part('content', 'none');

    endif;
?>

You can completely get rid of this part, delete it, burn it and forget about it

<?
// get the term using the slug and the tag taxonomy
$term = get_term_by( 'slug', 'featured', 'post_tag' );
// pass the term_id to tag__not_in
query_posts( array( 'tag__not_in' => array ( $term->term_id )));
?>

OK, once you've done that, you'll see that posts from the feature tag appear in your home page using the main query and default loop.

The correct way of removing this tag from the homepage is with pre_get_posts. This is the proper way to alter the main query and the hook you should always use to make changes to your primary content loop.

So, the code with pre_get_posts is correct and this is the function that you should use. Just one thing, always do a check that you are not on an admin page because pre_get_posts alters the back end as well. So this is the proper code to use in functions.php to remove posts tagged featured from the homepage

function exclude_featured_tag( $query ) {
    if ( !is_admin() && $query->is_home() && $query->is_main_query() ) {
        $query->set( 'tag__not_in', 'array(ID OF THE FEATURED TAG)' );
    }
}
add_action( 'pre_get_posts', 'exclude_featured_tag' );

PART THREE

Extra reading material which will be helpful in future

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.