I have been struggling with a problem, I have a webpage running on WordPress, most of the things work as expected, except one: in the blog section page (the one that is configured in settings/reading -> Posts page), all posts are shown. I have a specific category that should be presented there, but I don't know how to alter the loop to work as expected. Here´s the code of the index page:

$class_archive  = '';
$is_grid_layout = get_theme_mod( 'thim_front_page_cate_display_layout', false );
$layout_type    = $is_grid_layout ? 'grid' : '';
if ( $layout_type == 'grid' ) {
    $class_archive = ' blog-switch-layout blog-list';
    global $post, $wp_query;
    if ( is_category() ) {
        $total = get_queried_object();
        $total = $total->count;
    } elseif ( ! empty( $_REQUEST['s'] ) ) {
        $total = $wp_query->found_posts;
    } else {
        $total = wp_count_posts( 'post' );
        $total = $total->publish;

    if ( $total == 0 ) {
        echo '<p class="message message-error">' . esc_html__( 'There are no available posts!', 'eduma' ) . '</p>';

    } elseif ( $total == 1 ) {
        $index = esc_html__( 'Showing only one result', 'eduma' );
    } else {
        $courses_per_page = absint( get_option( 'posts_per_page' ) );
        $paged            = get_query_var( 'paged' ) ? intval( get_query_var( 'paged' ) ) : 1;

        $from = 1 + ( $paged - 1 ) * $courses_per_page;
        $to   = ( $paged * $courses_per_page > $total ) ? $total : $paged * $courses_per_page;

        if ( $from == $to ) {
            $index = sprintf(
                esc_html__( 'Showing last post of %s results', 'eduma' ),
        } else {
            $index = sprintf(
                esc_html__( 'Showing %s-%s of %s results', 'eduma' ),

I've added:

$args = array(
    cat => 200
// Custom query.
$wp_query = new WP_Query( $args );

Without any success.

Thanks in advance for your help.

1 Answer 1


In WordPress, we have what is called as "main query" which points to the global $wp_query object (which is an instance of the WP_Query class), and this main query is run on page load after WordPress parses query arguments from the current URL (or the relevant query for the matching rewrite rule for that URL).

And you should never change/overwrite that variable, or even make the custom query as in your code, because doing so can break a lot of things and also affects the page performance. See query_posts() for further details (but no, do not use that function, either).

The proper way to alter the main WordPress query

.. is by using hooks like pre_get_posts. And on that hook, you can use conditional tags like is_home(), is_front_page() and is_category() to target a specific page.

So here's an example for your case (and this code would go in the theme functions file):

add_action( 'pre_get_posts', 'my_pre_get_posts' );
function my_pre_get_posts( $query ) {
    // If it's the blog page and $query points to the main WordPress query, then
    // we set "cat" to a specific category ID.
    if ( is_home() && $query->is_main_query() ) {
        $query->set( 'cat', 200 );

Further Reading

  • Thanks Sally, I didn't know about that hook, since It can be conditional loaded, this does not affect the performance of the entire website? $query variable will override the $wp_query and the general arguments therefore $wp_query will not be used on this page template? May 14, 2021 at 16:13
  • After further reading about targeting specific blog page: wordpress.stackexchange.com/questions/107141/… I use the code you just provide with the conditional tag: is_home( ) and all works just Fine. Thanks May 14, 2021 at 16:54
  • 1
    Sorry, by "performance", I was referring to something like global $wp_query; $wp_query = new WP_Query( 'cat=200' ); while ( have_posts() ) ... or worse, query_posts( 'cat=200' ); while ( have_posts() ) ..., i.e. you made the query to change the main loop (that "while" there), so that is considered duplicate query despite the query args changed, and that is bad towards performance. So instead of doing that, use pre_get_posts to modify the main query's args and then your template would only need to display the main loop without making the additional query.
    – Sally CJ
    May 14, 2021 at 20:16
  • 1
    But if for example you wanted to display a list of "featured" posts (maybe having a specific metadata or custom taxonomy term) after the main loop section, then that is not a problem - but still, do not change the global $wp_query (i.e. don't do $wp_query = new WP_Query) and instead, use another variable like $my_query and then loop the posts like so: while ( $my_query->have_posts() ) { $my_query->the_post(); ... }.
    – Sally CJ
    May 14, 2021 at 20:22
  • 1
    Thanks for your clever answer, since it can be used all site wide, without touching the default loop May 15, 2021 at 3:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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