Why does get_post_meta not work with the posts page?

Looking for a reason why get_post_meta() doesn’t work with home.php. From my reading I understand that it’s a template and not a post or page, per “Custom fields won’t display on my blog page”. The closest page I was able to find from searching was “get_post_meta fields don’t show up on posts page” but alas the answer doesn’t go into detail why. I have coded a custom meta box, it works, for the front_page.php and all custom post types but not within home.php. I am using a conditional is_home() and it works but it seems get_the_ID() doesn’t, the code:

if ( is_home() ) {
    // variables 
    $check_meta     = get_post_meta( get_the_ID(), 'checkbox', true );
    $header_meta    = get_post_meta( get_the_ID(), 'header', true );        
    $textarea_meta  = get_post_meta( get_the_ID(), 'textarea', true );

    // condition
    if ( ( $check_meta == 'yes' ) && !empty( $textarea_meta ) && !empty( $header_meta ) ) {
        // code
    }
}

Why does get_the_ID() appear to not work with get_post_meta() in home.php located in header.php?


Edit:

Per the comments I thought I would edit this question to help someone else in the future. I am setting the the front page and the posts page in Settings -> Reading. The below worked in my conditional for is_home():

$check_meta     = get_post_meta( get_queried_object_id(), 'checkbox', true );
$header_meta    = get_post_meta( get_queried_object_id(), 'header', true );        
$textarea_meta  = get_post_meta( get_queried_object_id(), 'textarea', true );

Solutions Collecting From Web of "Why does get_post_meta not work with the posts page?"

If your posts page is a static page selected under Settings > Reading > Front page displays, then get_queried_object_id() will return the ID for that page which you can use to fetch meta data.

$check_meta     = get_post_meta( get_queried_object_id(), 'checkbox', true );
$header_meta    = get_post_meta( get_queried_object_id(), 'header', true );        
$textarea_meta  = get_post_meta( get_queried_object_id(), 'textarea', true );

The home page (this goes for the blogpage any archive page as well) does not have a post ID as it is not a post neither a page. These are virtual pages and does not actually exist as they where not created in back end.

get_the_ID() uses get_post() which uses the $post global to return the ID of a post or a page. Inside the loop, the $post global will always be set to the current post being looped through through the_post().

Outside the loop, in the main query, before the loop, the $post global will be automatically be set and hold the post object of the first post in the query. You can check this with var_dump( $post );. The $post global will be set to the last post in the query if checked after the loop has run (because the_post() has changed the value).

On single post pages and true pages, the first post (which will always be the only post) will be the post that was queried, so the post ID will always (if you are not using query_posts, query_posts will break this stuffing you big time)correspond with the correct ID of the post or page. On any archive page, the post ID returned by get_the_ID() will always be the first or last post in the query depending on where it is used outside the loop.

Archive pages also cannot have post meta, as they are not posts or pages and they do not have ID’s.

So, in short, get_the_ID() will always return false (if $post is ever to be empty), or the ID of the first or last post in the query outside the loop on any type of archive page

In order to use get_post_meta() you need to have a post id. These are your options:

  1. Set a post id manually
  2. Run your code in the loop and get_the_ID() usually loop.php
  3. Run your code in a single page or post usually page.php or single.php

Expanding answer using TwentyFifteen theme:

  1. Open index.php
  2. Locate the loop code starting with while ( have_posts() ) : the_post();
  3. Insert your code after code in step 2, $meta = get_post_meta( get_the_ID() );