3

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.

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;
    }
    
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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