I need a reliable way to get the post ID outside of the loop to use get_post_meta() in the pre_get_posts hook.

So far I found out that

  • get_queried_object_id() works for all pages except the frontpage or blogpage
  • get_option( 'page_on_front' ) gives the frontpage ID
  • get_option( 'page_for_posts' ) gives the blogpage ID
  • global $post; echo $post->ID; seems not to work with pre_get_posts (no idea why)

I tried to check the ID conditionally with different functions:

function show_id ( $wp_query ) {

if ( is_front_page() && is_home() ) {
    // Default homepage
    $id = get_option( 'page_on_front' );
} elseif ( is_front_page() ) {
    // static homepage
    $id = get_option( 'page_on_front' );
} elseif ( is_home() ) {
    // blog page
    $id = get_option( 'page_for_posts' );
} else {
    //everything else
    $id = get_queried_object_id();  
// Debug
echo $id;
add_action ( 'pre_get_posts', 'show_id' );

It works for the blogpage and other pages but not for the static frontpage. I get these error notifications:

Notice: Trying to get property of non-object in ...\wp-includes\query.php on line 4520

Notice: Trying to get property of non-object in ...\wp-includes\query.php on line 4522

Notice: Trying to get property of non-object in ...\wp-includes\query.php on line 4524

Can you help?


What I want to achive is to call get_post_meta() at pre_get_posts which will return an array of post IDs. Then I want to modify the main query with something like $query->set ('post__in', array($myIDs)); to get the posts based on the IDs in the metadata of the queried post.

  • What kind of post meta do you need in a pre_get_posts hook? Why not save it as an option? Your errors probably relate to this bug in which get_queried_object() has the possibility of returning NULL to one of the normal conditionals. Have you tried $wp_query->is_front_page() instead? – Howdy_McGee May 20 '16 at 18:05
  • The meta value will contain an array of post IDs. I want to get these IDs and use $query->set ('post__in', array($myIDs)); to alter the main query. – matjaeck May 20 '16 at 18:12
  • Do you set this on a post by post basis? If not it would be easier and probably better suited as an option then you could just use get_option() and be done with the whole thing. – Howdy_McGee May 20 '16 at 18:13
  • The metadata wil be applied to a CPT without any requirements to page or post attributes. If I modify the question, can you give an example? – matjaeck May 20 '16 at 18:20
  • How are you saving the postmeta? via plugin or by the save_post hook or custom fields or...? – Howdy_McGee May 20 '16 at 18:22

Per the wordpress codex pre_get_posts() does not work everywhere.

is_font_page() will not work but is_home() will. So your condition is_front_page() && is_home() will fail every time. However 'is_home()' alone should work.

It might be helpful to others to know what exactly you are trying to do. Usually pre_get_posts is used to alter a query but from the snippet of code you have shared. All I can tell you are trying to do is get a post id of for a page that has a list of posts on it?

One more thing. I loaded your function within a theme I am working on and the function fired about 5 times in various places where new queries are made like the nav menu and sidebar. So you also need to be aware of what query you are in. You should probably use this to ensure you are in the main query.

if ( $wp_query->is_main_query() ) {
    //check if home or else where here

I see you have added more info in the comments of your question which I am unable to comment in since my reputation is too low at this point.

If I were you I would target the homepage a different way. Maybe a custom template file and then set your query for that page with query_posts($args) and build your own loop.

Added Working Function Accepted in Chat:

function show_id ( $wp_query ) {
// lets make sure we are in the main query
if ( $wp_query->is_main_query() ) {
    if (  is_home() ) {
        // Default homepage or blog Archive
        $id = $id = get_option( 'page_for_posts' );;
    } elseif ( !is_single() && !empty($wp_query->query_vars['page_id'])) {
        // static homepage aka front page
        $id = $wp_query->query_vars['page_id'];
    } else {
        //everything else
        $id = get_queried_object_id();  
// Debug
echo '<pre>';
echo '</pre>';
add_action ( 'pre_get_posts', 'show_id' );
  • For the moment I just wanted to know how to securely get post IDs so I can use them for get_post_meta, which will be used to alter the query within pre_get_posts. I agree with you I should clarify what I want to do in the question. – matjaeck May 20 '16 at 18:36
  • So this works on single pages but not on Home/Front page or Blog Archives? BTW I have edited my answer a little. – stoi2m1 May 20 '16 at 18:39
  • The IDs show independant of the used template for all pages except the one for the frontpage. Didnt test it but generic archiv pages dont have an ID as far as I know. – matjaeck May 20 '16 at 18:44
  • Thats correct, the archives page is used to display paged based on searches and a archives of terms. So it seems you just need to resolve this for home and for blog? – stoi2m1 May 20 '16 at 18:46
  • I need a reliable function so no matter in what context the page is it will return the post ID. – matjaeck May 20 '16 at 18:48

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.