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

I’m using example code for a templating system.

Page at this address: http://project.test/my_cpt/hello-post/.

Cannot understand why is_singular( 'my_cpt' ) is true while in_the_loop() is false.

Within the page template, it seems like The Loop “works”:

if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();
        ?>
        <h2><a href="<?php the_permalink(); ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
        <?php
    } 
}

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

And when I run if ( have_posts() ) { while ( have_posts()... is that in the loop or is it creating the loop?

Update

Partly it has to do with which filter is being hooked in the function/method which performs the if && test.

The example above is being used with the template_include hook, which is getting run for pages, posts and maybe even links, menus, media, etc. So that would be why both tests are necessary.

The filter looks like:

add_filter( 'template_include', array( __CLASS__, 'my_template_include_method' ) );

or if it was not calling a class method would just be:

add_filter( 'template_include', 'my_template_include_function' );

The full method/function looks like:

public static function my_template_include_function( $original_template ) {
    if ( is_singular( 'my_cpt' ) && in_the_loop() ) {
        return wpbp_get_template_part( MMC_TEXTDOMAIN, 'content', 'my_template', false );
    }

    return $original_template;
}

The wpbp_get_template_part is from a plugin boilerplate I recently discovered called WordPress Plugin Boiler Plate.

Since I’m looking, at the moment, a singular post, I can hook into single_template like this:

add_filter( 'single_template', array( __CLASS__, 'my_single_include_function' ) );

It looks like this:

public static function my_single_include_function( $single_template ) {
    global $post;

    if ( 'my_cpt' === $post->post_type ) {
            return wpbp_get_template_part( MMC_TEXTDOMAIN, 'single', 'my_template', false );
    }

    return $single_template;
}

The templates themselves look like: templates/content-my_template and templates/single-my_template.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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;
    }
    


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x