get_post( int|object|null $post = null, string $output = OBJECT, string $filter = 'raw' ): WP_Post|array|null
- Since
- 1.5.1
- Source
wp-includes/post.php:1114
Resolve a post ID, a post object, or the current global $post into a single WP_Post, an associative array, or a numeric array. The $post argument is falsey-tolerant: 0, null and false all fall back to the global post, which is why calls outside the loop return null rather than an error. Fields come back raw by default, so anything destined for a page still needs its display filters applied.
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|object|nulloptional- Post ID or post object.
null,false,0and other PHP falsey values return the current global post inside the loop. A numerically valid post ID that points to a non-existent post returnsnull. 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, aWP_Postinstance 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
Passing ARRAY_A is the quickest way to read post fields without touching WP_Post property syntax.
$post = get_post( 2, ARRAY_A );
if ( $post ) {
echo esc_html( $post['post_title'] ), "\n";
echo esc_html( $post['post_status'] ), "\n";
} else {
echo 'No post with that ID.';
}ARRAY_N returns the same fields keyed numerically, which is rarely what you want.
Read the current post without passing an ID
With no arguments the function falls back to the global $post, so template parts can stay self-contained.
// Stand in for the loop by setting the global the way a template would.
$GLOBALS['post'] = get_post( 3 );
$post = get_post();
echo $post ? esc_html( $post->post_title ) : 'No global post is set.';Outside the loop there is no global $post, so guard the return value.
Render post content with the display filters applied
get_post() returns raw database values, so content read this way is not what the front end shows.
$post = get_post( 1 );
if ( $post ) {
echo "RAW:\n", esc_html( $post->post_content ), "\n\n";
echo "FILTERED:\n", esc_html( apply_filters( 'the_content', $post->post_content ) );
}Applying 'the_content' also runs shortcodes, oEmbed and block rendering.
Common problems and fixes · 4
- Why does get_post() return null?
- Why is the post content I get back not filtered?
- What is the difference between OBJECT, ARRAY_A and ARRAY_N?
- Does calling get_post() repeatedly hit the database each time?
Why does get_post() return null?
null. A falsey $post (0, null, false, '') makes the function fall back to $GLOBALS['post'], so calling it outside the loop, in an admin screen, or in a REST or cron request returns null because no global post is set. A numeric ID that has no matching row also returns null, because WP_Post::get_instance() fails and the function returns early. Always test the return value before reading a property from it.Why is the post content I get back not filtered?
$filter defaults to 'raw', which returns the values exactly as stored. Paragraph tags, shortcodes, blocks and embeds are all applied by the the_content filter at render time, not by this function. Run apply_filters( 'the_content', $post->post_content ) when you need the rendered output, and remember that doing so executes shortcodes.What is the difference between OBJECT, ARRAY_A and ARRAY_N?
OBJECT (the default) returns a WP_Post instance with magic properties and lazy loading for fields like post_category. ARRAY_A returns the same fields as a string-keyed array and ARRAY_N as a numerically indexed one. Only the OBJECT form gives you WP_Post behavior, so array callers lose the lazy properties.Does calling get_post() repeatedly hit the database each time?
WP_Post::get_instance(), which reads from the posts object cache group and only queries when the post is not cached. Calling it several times in one request for the same ID is cheap. Passing a plain stdClass object is the expensive path, because it is sanitized and wrapped on every call.Alternatives and related functions
get_posts- When you need more than one post, or want to select by post type, status, author or meta rather than by a known ID.
WP_Query- When you need pagination, a found-rows count, or the full range of query arguments that get_posts() suppresses.
get_post_field- When you only want a single field and would rather have it filtered for a given context than handle a whole object.
get_page_by_path- When you have a slug or a hierarchical path instead of an ID.
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
- Scaling
- Constant
- Instructions
- 11–44
- Plugin surface
- None
- Called by
- 50
Reaches the database via get_post().
No loop in the body: the same number of instructions runs whatever you pass in.
Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 72.
Nothing here hands control to plugin code.
50 places in core call this, so the cost is paid more often than your own code shows.
What it touches
- querycontent query
get_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.
| When | Instructions | Calls it makes |
|---|---|---|
| always | 11–25 | none |
!($post instanceof) | 15–29 | ::WP_Post() |
$output === false | 20–34 | ->filter(), ->to_array() |
$output !== false | 21–35 | ->filter() |
!($post instanceof) && is_object($post) && empty($post) | 23–27 | sanitize_post() |
!($post instanceof) && $output === false | 24–38 | ::WP_Post(), ->filter(), ->to_array() |
!($post instanceof) && $output !== false | 25–39 | ::WP_Post(), ->filter() |
| always | 26–40 | ->filter(), ->to_array(), array_values() |
!($post instanceof) | 30–44 | ::WP_Post(), ->filter(), ->to_array(), array_values() |
!($post instanceof) && is_object($post) && empty($post) && $output === false | 32–36 | sanitize_post(), ->filter(), ->to_array() |
!($post instanceof) && is_object($post) && empty($post) && $output !== false | 33–37 | sanitize_post(), ->filter() |
!($post instanceof) && is_object($post) && empty($post) | 38–42 | sanitize_post(), ->filter(), ->to_array(), array_values() |
Across PHP versions
| PHP | Compiled | Executed | Branches | Notes |
|---|---|---|---|---|
| 8.6-dev | 72 | 11–44 | 10 | |
| 8.5 | 72 | 11–44 | 10 | |
| 8.4 | 72 | 11–44 | 10 | |
| 8.3 | 72 | 11–44 | 10 | |
| 8.2 | 72 | 11–44 | 10 | |
| 8.1 | 72 | 11–44 | 10 | 2 fewer instructions than PHP 7.4 |
| 7.4 | 74 | 11–46 | 10 |
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
- sanitize_post()Sanitizes every post field.
- WP_Post::__construct()Constructor.
- WP_Post::get_instance()Retrieve WP_Post instance.
Used by · 50
- Custom_Image_Header::create_attachment_object()Creates an attachment 'object'.
- File_Upload_Upgrader::__construct()Construct the upgrader for a form.
- TwentyTwenty_Walker_Page::start_el()Outputs the beginning of the current element in the tree.
- WP_Comment::__get()Magic getter.
- WP_Comment::__isset()Determines whether a non-public property is set.
- WP_Comments_List_Table::column_response()Outputs the response column.
- WP_Comments_List_Table::single_row()Generates content for a single row of the table.
- WP_Customize_Control::render_content()Renders the control's content.
- WP_Customize_Manager::_publish_changeset_values()Publishes the values of a changeset.
- WP_Customize_Manager::customize_pane_settings()Prints JavaScript settings for parent window.
- WP_Customize_Manager::get_changeset_post_data()Gets the data stored in a changeset post.
- WP_Customize_Manager::import_theme_starter_content()Imports theme starter content into the customized state.
Show all 50
- WP_Customize_Manager::save()Handles customize_save WP Ajax request to save/update a changeset.
- WP_Customize_Manager::save_changeset_post()Saves the post for the loaded changeset.
- WP_Customize_Manager::trash_changeset_post()Trashes or deletes a changeset post.
- WP_Customize_Nav_Menu_Item_Setting::get_original_title()Get original title.
- WP_Customize_Nav_Menu_Item_Setting::value()Get the instance data for a given nav_menu_item setting.
- WP_Customize_Nav_Menus::insert_auto_draft_post()Adds a new `auto-draft` post.
- WP_Customize_Nav_Menus::load_available_items_query()Performs the post_type and taxonomy queries for loading available menu items.
- WP_Customize_Nav_Menus::sanitize_nav_menus_created_posts()Sanitizes post IDs for posts created for nav menu items to be published.
- WP_Embed::cache_oembed()Triggers a caching of all oEmbed results.
- WP_Embed::maybe_run_ajax_cache()If a post/page was saved, then output JavaScript to make an Ajax request that will call WP_Embed::cache_oembed().
- WP_Embed::shortcode()The do_shortcode() callback function.
- WP_List_Table::comments_bubble()Displays a comment count bubble.
- WP_Media_List_Table::column_parent()Handles the parent column output.
- WP_Navigation_Block_Renderer::get_inner_blocks_from_navigation_post()Gets the inner blocks for the navigation block from the navigation post.
- WP_Navigation_Block_Renderer::get_navigation_name()Gets the name of the current navigation, if it has one.
- WP_Posts_List_Table::_page_rows()Displays the nested hierarchy of sub-pages together with paging support, based on a top level page ID.
- WP_Posts_List_Table::column_title()Handles the title column output.
- WP_Posts_List_Table::single_row()
- WP_Privacy_Policy_Content::notice()Adds a notice with a link to the guide when editing the privacy policy page.
- WP_Query::generate_postdata()Generates post data.
- WP_Query::get_posts()Retrieves an array of posts based on query variables.
- WP_Query::get_queried_object()Retrieves the currently queried object.
- WP_Query::setup_postdata()Sets up global post data.
- WP_Query::the_post()Sets up the current post.
- WP_REST_Attachments_Controller::create_item()Creates a single attachment.
- WP_REST_Attachments_Controller::edit_media_item()Applies edits to a media item and creates a new attachment record.
- WP_REST_Attachments_Controller::insert_attachment()Inserts the attachment post in the database. Does not update the attachment meta.
- WP_REST_Attachments_Controller::post_process_item()Performs post-processing on an attachment.
- WP_REST_Attachments_Controller::prepare_links()Prepares attachment links for the request.
- WP_REST_Attachments_Controller::update_item()Updates a single attachment.
- WP_REST_Autosaves_Controller::create_item()Creates, updates or deletes an autosave revision.
- WP_REST_Autosaves_Controller::create_post_autosave()Creates autosave for the specified post.
- WP_REST_Block_Renderer_Controller::get_item()Returns block output from block's registered render_callback.
- WP_REST_Block_Renderer_Controller::get_item_permissions_check()Checks if a given request has access to read blocks.
- WP_REST_Comments_Controller::check_read_permission()Checks if the comment can be read.
- WP_REST_Comments_Controller::create_item_permissions_check()Checks if a given request has access to create a comment.
- WP_REST_Comments_Controller::get_comment()Get the comment, if the ID is valid.
- WP_REST_Comments_Controller::get_item_permissions_check()Checks if a given request has access to read the comment.
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 ); } elseif ( isset( $post->ID ) ) { $_post = WP_Post::get_instance( $post->ID ); } else { $_post = null; } } 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.
Signature, return type and hooks compared across 5 parsed releases.
$post retyped from int|WP_Post|null to int|object|null.verified against sourceAbout this page
- Parsed data
- Generated from the wordpress-develop 7.0.4 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.