Banner appearing on Pages but not Posts; call it conditional confusion

Since you’ve designated a specific page to be your Post Archive ( blog ) it no longer is a standard page; meaning is_page() will likely fail. Since your blog page is now more of an archive, it is automatically being returned because of your first conditional.

  • is_singular() – Returns true when viewing a single page, post, or post type.

So what you’re saying is IF we’re NOT viewing a Singular Page then return. Since blog is no longer a singular page, instead, let’s say:

if( ! is_page() && ! is_home() )
    return;

Next, since this blog page is an archive now we cannot reply on the global $post to give us the correct ID for the blog page, thus get_the_ID() will fail. What we need to do is get the blog ID using the following:

$blog_id = get_option( 'page_for_posts' );

I’ve taken some liberties below with your function but it should work the same.

//* Add Header Images on Posts/Pages
add_image_size( 'header-img', 1600 );
add_action( 'after_header', 'site_banner', 0 );
function site_banner() {
    if( ( is_page() || is_home() ) ) {
        $post_id = ( is_home() ? get_option( 'page_for_posts' ) : get_the_ID() );

        if( has_post_thumbnail( $post_id ) ) {
            $ftbanner = wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), 'header-img' );
            $banner = $ftbanner[0];
            echo '<div id="site-banner" class="site-banner">' . "\n";
            echo '<img src="' . $banner . '">' . "\n";
            echo '</div>' . "\n";
        }
    }
}

What I’m doing differently here is right off the bat I make sure we are either viewing a page or the blog page and if we are, set the $post_id then verify that that page has a featured image set. IF it does have one set, show the banner image.