What is the proper way to get contents of a page?

A few notes before I start

  • NEVER EVER use php shortcodes, they are bad, confusing and not supported by default on some servers. IMHO, they should have never made it into PHP in the first place. WordPress Standards (which doesn’t mean much) also “prohibits” the use of shorttags. Use proper php tags and forget that shorttags even exists

  • the_content() and get_the_content() does not accept the post ID, the firts parameter for both these template tags are $more_link_text

  • get_the_content() as well as the the content retrieved from the post_content field are unfiltered content, the_content filters are a set of filters that are applied to this unfiltered content and they include filters like wpautop which apply p tags to the_content()

Popular believe is that the_content() and get_the_content() MUST be used inside the loop. That is not entirely true, although it really is not recommended to use it outside the loop. Just like get_the_ID(), get_the_content() expects global post data to be set up ($post = get_post()), so if there are postdata available outside the loop in global scope, it will return the data.

Your issue is quite strange, if we look at source codes here, both get_the_ID() and get_the_content() calls $post = get_post(), and get_post() returns $GLOBALS['post'] if no ID is passed and if $GLOBALS['post'] are set, which seems to be the case here. get_post_field() successfully returns the page content according to you which means get_the_ID() returns the correct page ID that we are one, which means that get_the_content() should have worked and should have returned unfiltered page content (the_content() should have displayed filtered page content)

Anyways, you will need to debug this why things does not want to work as expected. To answer your question as to displaying page content without the loop correctly and reliably, you can access the queried object, get the $post_content property, apply the content filters to it and display the content. Just one note, this will not work if you are using query_posts in any way as it breaks the main query object which hold the queried object. This is the main reason why do must never ever use query_posts

$current_page = get_queried_object();
$content      = apply_filters( 'the_content', $current_page->post_content );
echo $content;