wppaste
WordPress

get_post( int|WP_Post|null $post = null, string $output = OBJECT, string $filter = 'raw' ): WP_Post|array|null

Since
1.5.1
Source
wp-includes/post.php:1115

Fetches a single post as a WP_Post object, associative array, or numeric array from an ID, a post object, or the current global post. Falls back to the global $post inside the loop when the $post argument is empty, and returns null if a numeric ID does not match an existing post. Use sanitize_post() to see exactly what each $filter value ('raw', 'edit', 'db', 'display') does to the returned fields.

Retrieves post data given a post ID or post object.

Description

See sanitize_post() for optional $filter values. Also, the parameter $post, must be given as a variable, since it is passed by reference.

Compatibility

WordPress
since 1.5.1
PHP
7.4–8.6-dev
  • 6.7.7
  • 6.8.8
  • 6.9.7
  • 7.0.4
  • 7.1.0

Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.

Parameters

$postint|WP_Post|nulloptional
Post ID or post object. null, false, 0 and other PHP falsey values return the current global post inside the loop. A numerically valid post ID that points to a non-existent post returns null. Defaults to global $post.Default: null
$outputstringoptional
The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.Default: OBJECT
$filterstringoptional
Type of filter to apply. Accepts 'raw', 'edit', 'db', or 'display'. Default 'raw'.Default: 'raw'

Return value

WP_Post|array|null
Type corresponding to $output on success or null on failure.
When $output is OBJECT, a WP_Post instance is returned.

Code examples

Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.

Get a post by ID as an associative array

Fetch post ID 2 from the baseline fixtures and dump it as an array instead of a WP_Post object.

$post_array = get_post( 2, ARRAY_A );

if ( null === $post_array ) {
	echo esc_html( 'No post found with that ID.' );
} else {
	echo '<pre>' . esc_html( print_r( $post_array, true ) ) . '</pre>';
}

ARRAY_A returns the same fields WP_Post would expose as an object, just as a plain array with no meta included.

Get the current post inside a custom loop without passing an ID

Run a small WP_Query over the five baseline posts and call get_post() with no argument to pull whatever the_post() just set as the global post.

$query = new WP_Query( array(
	'post_type'      => 'post',
	'posts_per_page' => 5,
) );

while ( $query->have_posts() ) {
	$query->the_post();
	$current = get_post();
	echo esc_html( $current->post_title ) . '<br>';
}

wp_reset_postdata();

Calling get_post() with no argument only works reliably while a loop has set up the global $post via the_post(); outside a loop it will pick up whatever $post happens to be set globally, if anything.

Common problems and fixes · 4

Why does get_post() give me the wrong post when I call it without an ID?

Passing no argument, null, false, or 0 makes get_post() read $GLOBALS['post'] instead of looking anything up. Outside The Loop that global may be stale, unset, or point to a different post than the one you meant.

Why does get_post() return null even though the ID looks correct?

A numeric ID that does not match any row in the posts table makes WP_Post::get_instance() fail internally, and get_post() returns null rather than a WP_Post or an error.

Why do post titles or content look different depending on which function I use?

The third parameter, $filter, controls which sanitize_post() context runs on the returned fields. 'raw' (the default) skips most filtering, while 'edit', 'db', and 'display' each run different sets of filters on things like post_title and post_content.

Why didn't changing a property on the object returned by get_post() update the post?

get_post() hands back a WP_Post instance built from cached data; mutating its properties in memory has no effect on the wp_posts table.

Alternatives and related functions

get_posts
When you need a filtered list of multiple posts (by category, tag, meta, etc.) rather than a single known post.
WP_Query
When you need full control over post retrieval, pagination, or complex query arguments beyond a single ID lookup.
get_post_field
When you only need one field from a post (like post_title) and want a lighter call than building a full WP_Post object.
get_the_title
When you're already inside The Loop or have a post ID and just want an escaped, filtered title string for display.

Performance profile

How much work a call to get_post() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.

Cost class
Heavy

Reaches the database via get_post().

Scaling
Constant

No loop in the body: the same number of instructions runs whatever you pass in.

Instructions
11–42

Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 68.

Plugin surface
None

Nothing here hands control to plugin code.

Called by
50

50 places in core call this, so the cost is paid more often than your own code shows.

What it touches

  • querycontent queryget_post()this function does it

Further down the call graph this can also reach hook, option, cache, serialize and transient. Those are the worst case, several calls deep and usually down an error path, not what a normal call pays.

What one call costs · 12 distinct outcomes

One number would be a lie: the work depends on which branch runs. These are every distinct cost get_post() can have, taken from its control-flow graph on PHP 8.5.

WhenInstructionsCalls it makes
always11–25none
!($post instanceof)15–27::WP_Post()
$output === false20–34->filter(), ->to_array()
$output !== false21–35->filter()
!($post instanceof) && is_object($post) && empty($post)23–27sanitize_post()
!($post instanceof) && $output === false24–36::WP_Post(), ->filter(), ->to_array()
!($post instanceof) && $output !== false25–37::WP_Post(), ->filter()
always26–40->filter(), ->to_array(), array_values()
!($post instanceof)30–42::WP_Post(), ->filter(), ->to_array(), array_values()
!($post instanceof) && is_object($post) && empty($post) && $output === false32–36sanitize_post(), ->filter(), ->to_array()
!($post instanceof) && is_object($post) && empty($post) && $output !== false33–37sanitize_post(), ->filter()
!($post instanceof) && is_object($post) && empty($post)38–42sanitize_post(), ->filter(), ->to_array(), array_values()

Across PHP versions

PHPCompiledExecutedBranchesNotes
8.6-dev6811–429
8.56811–429
8.46811–429
8.36811–429
8.26811–429
8.16811–4292 fewer instructions than PHP 7.4
7.47011–449

An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.

Uses · 3

Used by · 50

Show all 50

Source code

function get_post( $post = null, $output = OBJECT, $filter = 'raw' ) {	if ( empty( $post ) && isset( $GLOBALS['post'] ) ) {		$post = $GLOBALS['post'];	} 	if ( $post instanceof WP_Post ) {		$_post = $post;	} elseif ( is_object( $post ) ) {		if ( empty( $post->filter ) ) {			$_post = sanitize_post( $post, 'raw' );			$_post = new WP_Post( $_post );		} elseif ( 'raw' === $post->filter ) {			$_post = new WP_Post( $post );		} else {			$_post = WP_Post::get_instance( $post->ID );		}	} else {		$_post = WP_Post::get_instance( $post );	} 	if ( ! $_post ) {		return null;	} 	$_post = $_post->filter( $filter ); 	if ( ARRAY_A === $output ) {		return $_post->to_array();	} elseif ( ARRAY_N === $output ) {		return array_values( $_post->to_array() );	} 	return $_post;}

Changelog

Introduced in 1.5.1. One change between 6.7.7 and 7.1.0.

  1. 6.7.7
  2. 6.8.8
  3. 6.9.7
  4. 7.0.4
  5. 7.1.0

Signature, return type and hooks compared across 5 parsed releases.

7.0.4
Parameter $post retyped from int|WP_Post|null to int|object|null.verified against source
1.5.1
Introduced.from the docblock

About this page

Parsed data
Generated from the wordpress-develop 6.9.7 tag, from src/wp-includes/post.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.
Corrections
Something wrong on this page? Report it and it gets fixed in the next regeneration.