* Determines whether a post type is considered "viewable".
* For built-in post types such as posts and pages, the 'public' value will be evaluated.
* For all others, the 'publicly_queryable' value will be used.
* @since 4.5.0 Added the ability to pass a post type name in addition to object.
* @since 4.6.0 Converted the `$post_type` parameter to accept a `WP_Post_Type` object.
* @param string|WP_Post_Type $post_type Post type name or object.
* @return bool Whether the post type should be considered viewable.
function is_post_type_viewable( $post_type ) {
if ( is_scalar( $post_type ) ) {
$post_type = get_post_type_object( $post_type );
if ( ! is_object( $post_type ) ) {
return $post_type->publicly_queryable || ( $post_type->_builtin && $post_type->public );
* Determine whether a post status is considered "viewable".
* For built-in post statuses such as publish and private, the 'public' value will be evaluted.
* For all others, the 'publicly_queryable' value will be used.
* @param string|stdClass $post_status Post status name or object.
* @return bool Whether the post status should be considered viewable.
function is_post_status_viewable( $post_status ) {
if ( is_scalar( $post_status ) ) {
$post_status = get_post_status_object( $post_status );
! is_object( $post_status ) ||
$post_status->internal ||
return $post_status->publicly_queryable || ( $post_status->_builtin && $post_status->public );
* Determine whether a post is publicly viewable.
* Posts are considered publicly viewable if both the post status and post type
* @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
* @return bool Whether the post is publicly viewable.
function is_post_publicly_viewable( $post = null ) {
$post = get_post( $post );
$post_type = get_post_type( $post );
$post_status = get_post_status( $post );
return is_post_type_viewable( $post_type ) && is_post_status_viewable( $post_status );
* Retrieves an array of the latest posts, or posts matching the given criteria.
* For more information on the accepted arguments, see the
* {@link https://developer.wordpress.org/reference/classes/wp_query/
* WP_Query} documentation in the Developer Handbook.
* The `$ignore_sticky_posts` and `$no_found_rows` arguments are ignored by
* this function and both are set to `true`.
* The defaults are as follows:
* @see WP_Query::parse_query()
* Optional. Arguments to retrieve posts. See WP_Query::parse_query() for all
* @type int $numberposts Total number of posts to retrieve. Is an alias of `$posts_per_page`
* in WP_Query. Accepts -1 for all. Default 5.
* @type int|string $category Category ID or comma-separated list of IDs (this or any children).
* Is an alias of `$cat` in WP_Query. Default 0.
* @type int[] $include An array of post IDs to retrieve, sticky posts will be included.
* Is an alias of `$post__in` in WP_Query. Default empty array.
* @type int[] $exclude An array of post IDs not to retrieve. Default empty array.
* @type bool $suppress_filters Whether to suppress filters. Default true.
* @return WP_Post[]|int[] Array of post objects or post IDs.
function get_posts( $args = null ) {
'suppress_filters' => true,
$parsed_args = wp_parse_args( $args, $defaults );
if ( empty( $parsed_args['post_status'] ) ) {
$parsed_args['post_status'] = ( 'attachment' === $parsed_args['post_type'] ) ? 'inherit' : 'publish';
if ( ! empty( $parsed_args['numberposts'] ) && empty( $parsed_args['posts_per_page'] ) ) {
$parsed_args['posts_per_page'] = $parsed_args['numberposts'];
if ( ! empty( $parsed_args['category'] ) ) {
$parsed_args['cat'] = $parsed_args['category'];
if ( ! empty( $parsed_args['include'] ) ) {
$incposts = wp_parse_id_list( $parsed_args['include'] );
$parsed_args['posts_per_page'] = count( $incposts ); // Only the number of posts included.
$parsed_args['post__in'] = $incposts;
} elseif ( ! empty( $parsed_args['exclude'] ) ) {
$parsed_args['post__not_in'] = wp_parse_id_list( $parsed_args['exclude'] );
$parsed_args['ignore_sticky_posts'] = true;
$parsed_args['no_found_rows'] = true;
$get_posts = new WP_Query;
return $get_posts->query( $parsed_args );
* Adds a meta field to the given post.
* Post meta data is called "Custom Fields" on the Administration Screen.
* @param int $post_id Post ID.
* @param string $meta_key Metadata name.
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param bool $unique Optional. Whether the same key should not be added.
* @return int|false Meta ID on success, false on failure.
function add_post_meta( $post_id, $meta_key, $meta_value, $unique = false ) {
// Make sure meta is added to the post, not a revision.
$the_post = wp_is_post_revision( $post_id );
return add_metadata( 'post', $post_id, $meta_key, $meta_value, $unique );
* Deletes a post meta field for the given post ID.
* You can match based on the key, or key and value. Removing based on key and
* value, will keep from removing duplicate metadata with the same key. It also
* allows removing all metadata matching the key, if needed.
* @param int $post_id Post ID.
* @param string $meta_key Metadata name.
* @param mixed $meta_value Optional. Metadata value. If provided,
* rows will only be removed that match the value.
* Must be serializable if non-scalar. Default empty.
* @return bool True on success, false on failure.
function delete_post_meta( $post_id, $meta_key, $meta_value = '' ) {
// Make sure meta is added to the post, not a revision.
$the_post = wp_is_post_revision( $post_id );
return delete_metadata( 'post', $post_id, $meta_key, $meta_value );
* Retrieves a post meta field for the given post ID.
* @param int $post_id Post ID.
* @param string $key Optional. The meta key to retrieve. By default,
* returns data for all keys. Default empty.
* @param bool $single Optional. Whether to return a single value.
* This parameter has no effect if $key is not specified.
* @return mixed An array if $single is false. The value of the meta field
* if $single is true. False for an invalid $post_id.
function get_post_meta( $post_id, $key = '', $single = false ) {
return get_metadata( 'post', $post_id, $key, $single );
* Updates a post meta field based on the given post ID.
* Use the `$prev_value` parameter to differentiate between meta fields with the
* If the meta field for the post does not exist, it will be added and its ID returned.
* Can be used in place of add_post_meta().
* @param int $post_id Post ID.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param mixed $prev_value Optional. Previous value to check before updating.
* If specified, only update existing metadata entries with
* this value. Otherwise, update all entries. Default empty.
* @return int|bool Meta ID if the key didn't exist, true on successful update,
* false on failure or if the value passed to the function
* is the same as the one that is already in the database.
function update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' ) {
// Make sure meta is added to the post, not a revision.
$the_post = wp_is_post_revision( $post_id );
return update_metadata( 'post', $post_id, $meta_key, $meta_value, $prev_value );
* Deletes everything from post meta matching the given meta key.
* @param string $post_meta_key Key to search for when deleting.
* @return bool Whether the post meta key was deleted from the database.
function delete_post_meta_by_key( $post_meta_key ) {
return delete_metadata( 'post', null, $post_meta_key, '', true );
* Registers a meta key for posts.
* @param string $post_type Post type to register a meta key for. Pass an empty string
* to register the meta key across all existing post types.
* @param string $meta_key The meta key to register.
* @param array $args Data used to describe the meta key when registered. See
* {@see register_meta()} for a list of supported arguments.
* @return bool True if the meta key was successfully registered, false if not.
function register_post_meta( $post_type, $meta_key, array $args ) {
$args['object_subtype'] = $post_type;
return register_meta( 'post', $meta_key, $args );
* Unregisters a meta key for posts.
* @param string $post_type Post type the meta key is currently registered for. Pass
* an empty string if the meta key is registered across all
* @param string $meta_key The meta key to unregister.
* @return bool True on success, false if the meta key was not previously registered.
function unregister_post_meta( $post_type, $meta_key ) {
return unregister_meta_key( 'post', $meta_key, $post_type );
* Retrieve post meta fields, based on post ID.
* The post meta fields are retrieved from the cache where possible,
* so the function is optimized to be called more than once.
* @param int $post_id Optional. Post ID. Default is ID of the global $post.
* @return array Post meta for the given post.
function get_post_custom( $post_id = 0 ) {
$post_id = absint( $post_id );
return get_post_meta( $post_id );
* Retrieve meta field names for a post.
* If there are no meta fields, then nothing (null) will be returned.
* @param int $post_id Optional. Post ID. Default is ID of the global $post.
* @return array|void Array of the keys, if retrieved.
function get_post_custom_keys( $post_id = 0 ) {
$custom = get_post_custom( $post_id );
if ( ! is_array( $custom ) ) {
$keys = array_keys( $custom );
* Retrieve values for a custom post field.
* The parameters must not be considered optional. All of the post meta fields
* will be retrieved and only the meta field key values returned.
* @param string $key Optional. Meta field key. Default empty.
* @param int $post_id Optional. Post ID. Default is ID of the global $post.
* @return array|null Meta field values.
function get_post_custom_values( $key = '', $post_id = 0 ) {
$custom = get_post_custom( $post_id );
return isset( $custom[ $key ] ) ? $custom[ $key ] : null;
* Determines whether a post is sticky.
* Sticky posts should remain at the top of The Loop. If the post ID is not
* given, then The Loop ID for the current post will be used.
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
* @param int $post_id Optional. Post ID. Default is ID of the global $post.
* @return bool Whether post is sticky.
function is_sticky( $post_id = 0 ) {
$post_id = absint( $post_id );
$stickies = get_option( 'sticky_posts' );
if ( is_array( $stickies ) ) {
$stickies = array_map( 'intval', $stickies );
$is_sticky = in_array( $post_id, $stickies, true );
* Filters whether a post is sticky.
* @param bool $is_sticky Whether a post is sticky.
* @param int $post_id Post ID.
return apply_filters( 'is_sticky', $is_sticky, $post_id );
* Sanitizes every post field.
* If the context is 'raw', then the post object or array will get minimal
* sanitization of the integer fields.
* @see sanitize_post_field()
* @param object|WP_Post|array $post The post object or array
* @param string $context Optional. How to sanitize post fields.
* Accepts 'raw', 'edit', 'db', 'display',
* 'attribute', or 'js'. Default 'display'.
* @return object|WP_Post|array The now sanitized post object or array (will be the
function sanitize_post( $post, $context = 'display' ) {
if ( is_object( $post ) ) {
// Check if post already filtered for this context.
if ( isset( $post->filter ) && $context == $post->filter ) {
if ( ! isset( $post->ID ) ) {
foreach ( array_keys( get_object_vars( $post ) ) as $field ) {
$post->$field = sanitize_post_field( $field, $post->$field, $post->ID, $context );
$post->filter = $context;
} elseif ( is_array( $post ) ) {
// Check if post already filtered for this context.
if ( isset( $post['filter'] ) && $context == $post['filter'] ) {
if ( ! isset( $post['ID'] ) ) {
foreach ( array_keys( $post ) as $field ) {
$post[ $field ] = sanitize_post_field( $field, $post[ $field ], $post['ID'], $context );
$post['filter'] = $context;
* Sanitizes a post field based on context.
* Possible context values are: 'raw', 'edit', 'db', 'display', 'attribute' and
* 'js'. The 'display' context is used by default. 'attribute' and 'js' contexts
* are treated like 'display' when calling filters.
* @since 4.4.0 Like `sanitize_post()`, `$context` defaults to 'display'.
* @param string $field The Post Object field name.
* @param mixed $value The Post Object value.
* @param int $post_id Post ID.
* @param string $context Optional. How to sanitize the field. Possible values are 'raw', 'edit',
* 'db', 'display', 'attribute' and 'js'. Default 'display'.
* @return mixed Sanitized value.
function sanitize_post_field( $field, $value, $post_id, $context = 'display' ) {
$int_fields = array( 'ID', 'post_parent', 'menu_order' );
if ( in_array( $field, $int_fields, true ) ) {
// Fields which contain arrays of integers.
$array_int_fields = array( 'ancestors' );
if ( in_array( $field, $array_int_fields, true ) ) {
$value = array_map( 'absint', $value );
if ( 'raw' === $context ) {
if ( false !== strpos( $field, 'post_' ) ) {
$field_no_prefix = str_replace( 'post_', '', $field );
if ( 'edit' === $context ) {
$format_to_edit = array( 'post_content', 'post_excerpt', 'post_title', 'post_password' );