When and Why is is_singular(‘my_cpt’) true while in_the_loop() is false?

I guess my question is when are is_singular() && in_the_loop() both true?

Note that both is_singular() and in_the_loop() point to the main WordPress query set via wp() (see Query Overview on WordPress Codex) which uses the global $wp_query variable.

Secondly, we create/start a loop when we call have_posts() and the_post(), and only after that would in_the_loop() return a true. Example:

// For the main query.
if ( have_posts() ) {
    while ( have_posts() ) : the_post();
        var_dump( in_the_loop() ); // true
        ...
    endwhile;
}

Therefore the is_singular() && in_the_loop() would only return true when:

  1. You’re on a singular WordPress page like example.com/sample-page/ (a single Page; post type page) and a CPT page like in your case (example.com/my_cpt/hello-post/) where the post type is my_cpt.

  2. And that you’re in the loop for the main query.

So for example with your my_template_include_function() function, using the is_singular( 'my_cpt' ) would be sufficient and I don’t see why should you check for in_the_loop() there — single templates should display/start the loop for the main query, so by the time WordPress runs the template_include or single_template hook, that loop has not yet started or that you’re not yet in the main query’s loop.

Do correct me if I’m wrong/mistaken, though. 🙂

(Update) If your function (e.g. the my_template_include_function()) is actually being hooked to another hook which indeed runs in the main query’s loop, then yes, you can use in_the_loop() there. Example:

  1. The filter: ( if in a (child) theme, this would be placed in the functions.php file )

    function my_custom_single_template_part( $template ) {
        if ( is_singular( 'my_cpt' ) && in_the_loop() ) {
            return '/path/to/your/template-part.php';
        }
    
        return $template;
    }
    add_filter( 'my_single_template_part', 'my_custom_single_template_part' );
    
  2. The main loop:

    if ( have_posts() ) {
        while ( have_posts() ) : the_post();
            $template = apply_filters( 'my_single_template_part', 'template-parts/content' );
            get_template_part( $template );
        endwhile;
    }
    

Leave a Comment