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
-
UPDATE: Display custom content on true pages and a static front page (see Using pre_get_posts on true pages and static front pages)
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
add_action( 'pre_get_posts', 'exclude_featured_tag' );
function exclude_featured_tag( $query )
{
if ( !is_admin()
&& $query->is_home()
&& $query->is_main_query()
) {
$query->set( 'tag__not_in', [ID OF THE FEATURED TAG] );
}
}
PART THREE
Extra reading material which will be helpful in future