In essence, for all technical purposes, get_post() == $post == $GLOBALS['post'] As @tosho already explained in the [linked post](https://wordpress.stackexchange.com/questions/73403/using-global-post-v-s-globalspost), `$post === $GLOBALS['post']`, so I will not go into that. What we are interested in is, how is `get_post()` the same. For this, we will need to look at the [source code](https://developer.wordpress.org/reference/functions/get_post/). As you can see, we get our answer in the first two lines of the function when we do not pass anything to `get_post()` if ( empty( $post ) && isset( $GLOBALS['post'] ) ) $post = $GLOBALS['post']; > regarding the `if ( isset( $GLOBALS['post'] ) ):` I guess this means post can be undefined. Yes, it can, and it depends on context. Also, just like any global, it can be unset as well, delibritely or unknowingly which can have disasterous effects. That is what make globals such a nasty evil thing to create and use. Unknowingly using globals as local variables is the number one reason (*IMO*) for unexpected, non debuggable code failures. The `$post` global is set by `WP_Query::the_post()`, but it can be changes by any custom code, so never rely on that, specially outside of the loop. > is it safe to assume that the widget code being executed after the loop **NEVER EVER** assume anything. That is the most dangerous thing you can ever do when coding. Simply assuming something leads to terrible bugs, security loopholes, maybe leak very personal info which can land you in jail, etc etc. Treat everything you code in such a manner to safely handle a specific thing or behavior should something fail, and alwyas code with a mindset that your code will fail and it will be hacked. Again, widgets can run before the loop or after it, and even inside the loop, so do not assume it will behave in a certain manner. If this is a true page (*created in the back end pages section*), then you can use `get_queried_object()` to get the current page object. It is much more reliable than the `$post` global. You should take your time and read through [this answer by @gmazzap](https://wordpress.stackexchange.com/a/167735/31545) to [my question here](https://wordpress.stackexchange.com/q/167706/31545) EDIT - Better alternative to `get_queried_object()` =================================================== From your comment to my answer > I understand `$post` can have been modified before I access it. But isn't that true also for `$wp_query` (modified through "custom" or "secondary" queries)? If so, shouldn't I test `is_main_query()` before relying on `get_queried_object()`? I'm assuming the main query is that based on the requested url, right? And if `is_main_query()` is false, what can I use then? Very true, the main query object is stored in the `$wp_query` global variable. Using `$wp_query` as a local variable breaks the main query object and sets it to whatever you are using the global for. Also, `query_posts` sets the main query object to the current custom query, which also breaks it. It is true that the queried object relies on the integrity of the main query object, which does make `get_queried_object()` vulnerable. In general, `get_queried_object()` is still much more reliable than `$post` because any custom query using `the_post()` or `setup_postdata( $post )` sets the `$post` global to the current post in the current loop. Forgetting to reset a custom query with `wp_reset_postdata()` will leave you with the wrong post object inside `$post`. As for `get_queried_object()`, if any one is still using `query_posts`, it is up to them if they want to suffer the consequences. I like the idea that you would really want and are really looking at more reliable alternatives to `$post` **AND** `get_queried_object()`, that is quite evident from your comment. Your comment actually sparked something I was working on a while ago and completely forgot about, I think most of all, including me, are forgetting one very important global which is never modified (*except by the filters and actions inside `WP_Query` itself*), and that global is `$GLOBALS['wp_the_query']`. `$GLOBALS['wp_the_query']` holds the actual main query object. `$GLOBALS['wp_query']` (*AKA `$wp_query`*) is only a copy of `$GLOBALS['wp_the_query']`. Lets quickly look at where this is set. In the current version (*Wordpress 4.4.2*), you will find the following code on [lines 291 - 304 in `wp-settings.php](https://github.com/WordPress/WordPress/blob/master/wp-settings.php#L291) /** * WordPress Query object * @global WP_Query $wp_the_query * @since 2.0.0 */ $GLOBALS['wp_the_query'] = new WP_Query(); /** * Holds the reference to @see $wp_the_query * Use this global for WordPress queries * @global WP_Query $wp_query * @since 1.5.0 */ $GLOBALS['wp_query'] = $GLOBALS['wp_the_query']; I did not know WordPress way back when, but this was most probably done to accommodate `query_posts`, because if you look at `wp_reset_query()` which you should use after `query_posts`, it resets `$wp_query` back to `$GLOBALS['wp_the_query']`. This all means that, even if we break the main query object (*`$wp_query`*), we still have a fully vaild copy left in `$GLOBALS['wp_the_query']`. With all of this in mind, if you really need a 99.99% reliable way to get the current queried object, it would be `$GLOBALS['wp_the_query']->get_queried_object()`. That would be the ultimate reliable way without having to rerun the main query again by yourself. Before I conclude, you also spoke about the `is_main_query()` check (*which in essence checks if the current `WP_Query` instance is equal to `$GLOBALS['wp_the_query']`*). In a case like this, it would not really work, as it simply return a boolean value. CONCLUSION - wrapping up ------------------------ To reliably get the current queried object on a single post page, or for that matter on any singular page and archive pages, use the queried object from the `$GLOBALS['wp_the_query']` global $GLOBALS['wp_the_query']->get_queried_object()