+ * @since 4.5.0
+ *
+ * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
+ * @global WP $wp Current WordPress environment instance.
+ * @global array $_wp_post_type_features Used to remove post type features.
+ * @global array $post_type_meta_caps Used to remove meta capabilities.
+ * @global array $wp_post_types List of post types.
+ *
+ * @param string $post_type Post type to unregister.
+ * @return bool|WP_Error True on success, WP_Error on failure or if the post type doesn't exist.
+ */
+function unregister_post_type( $post_type ) {
+ if ( ! post_type_exists( $post_type ) ) {
+ return new WP_Error( 'invalid_post_type', __( 'Invalid post type' ) );
+ }
+
+ $post_type_args = get_post_type_object( $post_type );
+
+ // Do not allow unregistering internal post types.
+ if ( $post_type_args->_builtin ) {
+ return new WP_Error( 'invalid_post_type', __( 'Unregistering a built-in post type is not allowed' ) );
+ }
+
+ global $wp, $wp_rewrite, $_wp_post_type_features, $post_type_meta_caps, $wp_post_types;
+
+ // Remove query var.
+ if ( false !== $post_type_args->query_var ) {
+ $wp->remove_query_var( $post_type_args->query_var );
+ }
+
+ // Remove any rewrite rules, permastructs, and rules.
+ if ( false !== $post_type_args->rewrite ) {
+ remove_rewrite_tag( "%$post_type%" );
+ remove_permastruct( $post_type );
+ foreach ( $wp_rewrite->extra_rules_top as $regex => $query ) {
+ if ( false !== strpos( $query, "index.php?post_type=$post_type" ) ) {
+ unset( $wp_rewrite->extra_rules_top[ $regex ] );
+ }
+ }
+ }
+
+ // Remove registered custom meta capabilities.
+ foreach ( $post_type_args->cap as $cap ) {
+ unset( $post_type_meta_caps[ $cap ] );
+ }
+
+ // Remove all post type support.
+ unset( $_wp_post_type_features[ $post_type ] );
+
+ // Unregister the post type meta box if a custom callback was specified.
+ if ( $post_type_args->register_meta_box_cb ) {
+ remove_action( 'add_meta_boxes_' . $post_type, $post_type_args->register_meta_box_cb );
+ }
+
+ // Remove the post type from all taxonomies.
+ foreach ( get_object_taxonomies( $post_type ) as $taxonomy ) {
+ unregister_taxonomy_for_object_type( $taxonomy, $post_type );
+ }
+
+ // Remove the future post hook action.
+ remove_action( 'future_' . $post_type, '_future_post_hook', 5 );
+
+ // Remove the post type.
+ unset( $wp_post_types[ $post_type ] );
+
+ /**
+ * Fires after a post type was unregistered.
+ *
+ * @since 4.5.0
+ *
+ * @param string $post_type Post type key.
+ */
+ do_action( 'unregistered_post_type', $post_type );
+
+ return true;
+}
+
+/**
+ * Build an object with all post type capabilities out of a post type object
+ *
+ * Post type capabilities use the 'capability_type' argument as a base, if the
+ * capability is not set in the 'capabilities' argument array or if the
+ * 'capabilities' argument is not supplied.
+ *
+ * The capability_type argument can optionally be registered as an array, with
+ * the first value being singular and the second plural, e.g. array('story, 'stories')
+ * Otherwise, an 's' will be added to the value for the plural form. After
+ * registration, capability_type will always be a string of the singular value.
+ *
+ * By default, seven keys are accepted as part of the capabilities array:
+ *
+ * - edit_post, read_post, and delete_post are meta capabilities, which are then
+ * generally mapped to corresponding primitive capabilities depending on the
+ * context, which would be the post being edited/read/deleted and the user or
+ * role being checked. Thus these capabilities would generally not be granted
+ * directly to users or roles.
+ *
+ * - edit_posts - Controls whether objects of this post type can be edited.
+ * - edit_others_posts - Controls whether objects of this type owned by other users
+ * can be edited. If the post type does not support an author, then this will
+ * behave like edit_posts.
+ * - publish_posts - Controls publishing objects of this post type.
+ * - read_private_posts - Controls whether private objects can be read.
+ *
+ * These four primitive capabilities are checked in core in various locations.
+ * There are also seven other primitive capabilities which are not referenced
+ * directly in core, except in map_meta_cap(), which takes the three aforementioned
+ * meta capabilities and translates them into one or more primitive capabilities
+ * that must then be checked against the user or role, depending on the context.
+ *
+ * - read - Controls whether objects of this post type can be read.
+ * - delete_posts - Controls whether objects of this post type can be deleted.
+ * - delete_private_posts - Controls whether private objects can be deleted.
+ * - delete_published_posts - Controls whether published objects can be deleted.
+ * - delete_others_posts - Controls whether objects owned by other users can be
+ * can be deleted. If the post type does not support an author, then this will
+ * behave like delete_posts.
+ * - edit_private_posts - Controls whether private objects can be edited.
+ * - edit_published_posts - Controls whether published objects can be edited.
+ *
+ * These additional capabilities are only used in map_meta_cap(). Thus, they are
+ * only assigned by default if the post type is registered with the 'map_meta_cap'
+ * argument set to true (default is false).
+ *
+ * @since 3.0.0
+ *
+ * @see register_post_type()
+ * @see map_meta_cap()
+ *
+ * @param object $args Post type registration arguments.
+ * @return object object with all the capabilities as member variables.
+ */
+function get_post_type_capabilities( $args ) {
+ if ( ! is_array( $args->capability_type ) )
+ $args->capability_type = array( $args->capability_type, $args->capability_type . 's' );
+
+ // Singular base for meta capabilities, plural base for primitive capabilities.
+ list( $singular_base, $plural_base ) = $args->capability_type;
+
+ $default_capabilities = array(
+ // Meta capabilities
+ 'edit_post' => 'edit_' . $singular_base,
+ 'read_post' => 'read_' . $singular_base,
+ 'delete_post' => 'delete_' . $singular_base,
+ // Primitive capabilities used outside of map_meta_cap():
+ 'edit_posts' => 'edit_' . $plural_base,
+ 'edit_others_posts' => 'edit_others_' . $plural_base,
+ 'publish_posts' => 'publish_' . $plural_base,
+ 'read_private_posts' => 'read_private_' . $plural_base,
+ );
+
+ // Primitive capabilities used within map_meta_cap():
+ if ( $args->map_meta_cap ) {
+ $default_capabilities_for_mapping = array(
+ 'read' => 'read',
+ 'delete_posts' => 'delete_' . $plural_base,
+ 'delete_private_posts' => 'delete_private_' . $plural_base,
+ 'delete_published_posts' => 'delete_published_' . $plural_base,
+ 'delete_others_posts' => 'delete_others_' . $plural_base,
+ 'edit_private_posts' => 'edit_private_' . $plural_base,
+ 'edit_published_posts' => 'edit_published_' . $plural_base,
+ );
+ $default_capabilities = array_merge( $default_capabilities, $default_capabilities_for_mapping );
+ }
+
+ $capabilities = array_merge( $default_capabilities, $args->capabilities );
+
+ // Post creation capability simply maps to edit_posts by default:
+ if ( ! isset( $capabilities['create_posts'] ) )
+ $capabilities['create_posts'] = $capabilities['edit_posts'];
+
+ // Remember meta capabilities for future reference.
+ if ( $args->map_meta_cap )
+ _post_type_meta_capabilities( $capabilities );
+
+ return (object) $capabilities;
+}
+
+/**
+ * Store or return a list of post type meta caps for map_meta_cap().
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @global array $post_type_meta_caps Used to store meta capabilities.
+ *
+ * @param array $capabilities Post type meta capabilities.
+ */
+function _post_type_meta_capabilities( $capabilities = null ) {
+ global $post_type_meta_caps;
+
+ foreach ( $capabilities as $core => $custom ) {
+ if ( in_array( $core, array( 'read_post', 'delete_post', 'edit_post' ) ) ) {
+ $post_type_meta_caps[ $custom ] = $core;
+ }
+ }
+}
+
+/**
+ * Build an object with all post type labels out of a post type object
+ *
+ * Accepted keys of the label array in the post type object:
+ *
+ * - name - general name for the post type, usually plural. The same and overridden
+ * by $post_type_object->label. Default is Posts/Pages
+ * - singular_name - name for one object of this post type. Default is Post/Page
+ * - add_new - Default is Add New for both hierarchical and non-hierarchical types.
+ * When internationalizing this string, please use a gettext context
+ * {@link https://codex.wordpress.org/I18n_for_WordPress_Developers#Disambiguation_by_context}
+ * matching your post type. Example: `_x( 'Add New', 'product' );`.
+ * - add_new_item - Default is Add New Post/Add New Page.
+ * - edit_item - Default is Edit Post/Edit Page.
+ * - new_item - Default is New Post/New Page.
+ * - view_item - Default is View Post/View Page.
+ * - search_items - Default is Search Posts/Search Pages.
+ * - not_found - Default is No posts found/No pages found.
+ * - not_found_in_trash - Default is No posts found in Trash/No pages found in Trash.
+ * - parent_item_colon - This string isn't used on non-hierarchical types. In hierarchical
+ * ones the default is 'Parent Page:'.
+ * - all_items - String for the submenu. Default is All Posts/All Pages.
+ * - archives - String for use with archives in nav menus. Default is Post Archives/Page Archives.
+ * - insert_into_item - String for the media frame button. Default is Insert into post/Insert into page.
+ * - uploaded_to_this_item - String for the media frame filter. Default is Uploaded to this post/Uploaded to this page.
+ * - featured_image - Default is Featured Image.
+ * - set_featured_image - Default is Set featured image.
+ * - remove_featured_image - Default is Remove featured image.
+ * - use_featured_image - Default is Use as featured image.
+ * - menu_name - Default is the same as `name`.
+ * - filter_items_list - String for the table views hidden heading.
+ * - items_list_navigation - String for the table pagination hidden heading.
+ * - items_list - String for the table hidden heading.
+ *
+ * Above, the first default value is for non-hierarchical post types (like posts)
+ * and the second one is for hierarchical post types (like pages).
+ *
+ * @since 3.0.0
+ * @since 4.3.0 Added the `featured_image`, `set_featured_image`, `remove_featured_image`,
+ * and `use_featured_image` labels.
+ * @since 4.4.0 Added the `insert_into_item`, `uploaded_to_this_item`, `filter_items_list`,
+ * `items_list_navigation`, and `items_list` labels.
+ *
+ * @access private
+ *
+ * @param object $post_type_object Post type object.
+ * @return object object with all the labels as member variables.
+ */
+function get_post_type_labels( $post_type_object ) {
+ $nohier_vs_hier_defaults = array(
+ 'name' => array( _x('Posts', 'post type general name'), _x('Pages', 'post type general name') ),
+ 'singular_name' => array( _x('Post', 'post type singular name'), _x('Page', 'post type singular name') ),
+ 'add_new' => array( _x('Add New', 'post'), _x('Add New', 'page') ),
+ 'add_new_item' => array( __('Add New Post'), __('Add New Page') ),
+ 'edit_item' => array( __('Edit Post'), __('Edit Page') ),
+ 'new_item' => array( __('New Post'), __('New Page') ),
+ 'view_item' => array( __('View Post'), __('View Page') ),
+ 'search_items' => array( __('Search Posts'), __('Search Pages') ),
+ 'not_found' => array( __('No posts found.'), __('No pages found.') ),
+ 'not_found_in_trash' => array( __('No posts found in Trash.'), __('No pages found in Trash.') ),
+ 'parent_item_colon' => array( null, __('Parent Page:') ),
+ 'all_items' => array( __( 'All Posts' ), __( 'All Pages' ) ),
+ 'archives' => array( __( 'Post Archives' ), __( 'Page Archives' ) ),
+ 'insert_into_item' => array( __( 'Insert into post' ), __( 'Insert into page' ) ),
+ 'uploaded_to_this_item' => array( __( 'Uploaded to this post' ), __( 'Uploaded to this page' ) ),
+ 'featured_image' => array( __( 'Featured Image' ), __( 'Featured Image' ) ),
+ 'set_featured_image' => array( __( 'Set featured image' ), __( 'Set featured image' ) ),
+ 'remove_featured_image' => array( __( 'Remove featured image' ), __( 'Remove featured image' ) ),
+ 'use_featured_image' => array( __( 'Use as featured image' ), __( 'Use as featured image' ) ),
+ 'filter_items_list' => array( __( 'Filter posts list' ), __( 'Filter pages list' ) ),
+ 'items_list_navigation' => array( __( 'Posts list navigation' ), __( 'Pages list navigation' ) ),
+ 'items_list' => array( __( 'Posts list' ), __( 'Pages list' ) ),
+ );
+ $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
+
+ $labels = _get_custom_object_labels( $post_type_object, $nohier_vs_hier_defaults );
+
+ $post_type = $post_type_object->name;
+
+ $default_labels = clone $labels;
+
+ /**
+ * Filter the labels of a specific post type.
+ *
+ * The dynamic portion of the hook name, `$post_type`, refers to
+ * the post type slug.
+ *
+ * @since 3.5.0
+ *
+ * @see get_post_type_labels() for the full list of labels.
+ *
+ * @param object $labels Object with labels for the post type as member variables.
+ */
+ $labels = apply_filters( "post_type_labels_{$post_type}", $labels );
+
+ // Ensure that the filtered labels contain all required default values.
+ $labels = (object) array_merge( (array) $default_labels, (array) $labels );
+
+ return $labels;
+}
+
+/**
+ * Build an object with custom-something object (post type, taxonomy) labels
+ * out of a custom-something object
+ *
+ * @since 3.0.0
+ * @access private
+ *
+ * @param object $object A custom-something object.
+ * @param array $nohier_vs_hier_defaults Hierarchical vs non-hierarchical default labels.
+ * @return object Object containing labels for the given custom-something object.
+ */
+function _get_custom_object_labels( $object, $nohier_vs_hier_defaults ) {
+ $object->labels = (array) $object->labels;
+
+ if ( isset( $object->label ) && empty( $object->labels['name'] ) )
+ $object->labels['name'] = $object->label;
+
+ if ( !isset( $object->labels['singular_name'] ) && isset( $object->labels['name'] ) )
+ $object->labels['singular_name'] = $object->labels['name'];
+
+ if ( ! isset( $object->labels['name_admin_bar'] ) )
+ $object->labels['name_admin_bar'] = isset( $object->labels['singular_name'] ) ? $object->labels['singular_name'] : $object->name;
+
+ if ( !isset( $object->labels['menu_name'] ) && isset( $object->labels['name'] ) )
+ $object->labels['menu_name'] = $object->labels['name'];
+
+ if ( !isset( $object->labels['all_items'] ) && isset( $object->labels['menu_name'] ) )
+ $object->labels['all_items'] = $object->labels['menu_name'];
+
+ if ( !isset( $object->labels['archives'] ) && isset( $object->labels['all_items'] ) ) {
+ $object->labels['archives'] = $object->labels['all_items'];
+ }
+
+ $defaults = array();
+ foreach ( $nohier_vs_hier_defaults as $key => $value ) {
+ $defaults[$key] = $object->hierarchical ? $value[1] : $value[0];
+ }
+ $labels = array_merge( $defaults, $object->labels );
+ $object->labels = (object) $object->labels;
+
+ return (object) $labels;
+}
+
+/**
+ * Add submenus for post types.
+ *
+ * @access private
+ * @since 3.1.0
+ */
+function _add_post_type_submenus() {
+ foreach ( get_post_types( array( 'show_ui' => true ) ) as $ptype ) {
+ $ptype_obj = get_post_type_object( $ptype );
+ // Sub-menus only.
+ if ( ! $ptype_obj->show_in_menu || $ptype_obj->show_in_menu === true )
+ continue;
+ add_submenu_page( $ptype_obj->show_in_menu, $ptype_obj->labels->name, $ptype_obj->labels->all_items, $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype" );
+ }
+}
+
+/**
+ * Register support of certain features for a post type.
+ *
+ * All core features are directly associated with a functional area of the edit
+ * screen, such as the editor or a meta box. Features include: 'title', 'editor',
+ * 'comments', 'revisions', 'trackbacks', 'author', 'excerpt', 'page-attributes',
+ * 'thumbnail', 'custom-fields', and 'post-formats'.
+ *
+ * Additionally, the 'revisions' feature dictates whether the post type will
+ * store revisions, and the 'comments' feature dictates whether the comments
+ * count will show on the edit screen.
+ *
+ * @since 3.0.0
+ *
+ * @global array $_wp_post_type_features
+ *
+ * @param string $post_type The post type for which to add the feature.
+ * @param string|array $feature The feature being added, accepts an array of
+ * feature strings or a single string.
+ */
+function add_post_type_support( $post_type, $feature ) {
+ global $_wp_post_type_features;
+
+ $features = (array) $feature;
+ foreach ($features as $feature) {
+ if ( func_num_args() == 2 )
+ $_wp_post_type_features[$post_type][$feature] = true;
+ else
+ $_wp_post_type_features[$post_type][$feature] = array_slice( func_get_args(), 2 );
+ }
+}
+
+/**
+ * Remove support for a feature from a post type.
+ *
+ * @since 3.0.0
+ *
+ * @global array $_wp_post_type_features
+ *
+ * @param string $post_type The post type for which to remove the feature.
+ * @param string $feature The feature being removed.
+ */
+function remove_post_type_support( $post_type, $feature ) {
+ global $_wp_post_type_features;
+
+ unset( $_wp_post_type_features[ $post_type ][ $feature ] );
+}
+
+/**
+ * Get all the post type features
+ *
+ * @since 3.4.0
+ *
+ * @global array $_wp_post_type_features
+ *
+ * @param string $post_type The post type.
+ * @return array Post type supports list.
+ */
+function get_all_post_type_supports( $post_type ) {
+ global $_wp_post_type_features;
+
+ if ( isset( $_wp_post_type_features[$post_type] ) )
+ return $_wp_post_type_features[$post_type];
+
+ return array();
+}
+
+/**
+ * Check a post type's support for a given feature.
+ *
+ * @since 3.0.0
+ *
+ * @global array $_wp_post_type_features
+ *
+ * @param string $post_type The post type being checked.
+ * @param string $feature The feature being checked.
+ * @return bool Whether the post type supports the given feature.
+ */
+function post_type_supports( $post_type, $feature ) {
+ global $_wp_post_type_features;
+
+ return ( isset( $_wp_post_type_features[$post_type][$feature] ) );
+}
+
+/**
+ * Retrieves a list of post type names that support a specific feature.
+ *
+ * @since 4.5.0
+ *
+ * @global array $_wp_post_type_features Post type features
+ *
+ * @param array|string $feature Single feature or an array of features the post types should support.
+ * @param string $operator Optional. The logical operation to perform. 'or' means
+ * only one element from the array needs to match; 'and'
+ * means all elements must match; 'not' means no elements may
+ * match. Default 'and'.
+ * @return array A list of post type names.
+ */
+function get_post_types_by_support( $feature, $operator = 'and' ) {
+ global $_wp_post_type_features;
+
+ $features = array_fill_keys( (array) $feature, true );
+
+ return array_keys( wp_filter_object_list( $_wp_post_type_features, $features, $operator ) );
+}
+
+/**
+ * Update the post type for the post ID.
+ *
+ * The page or post cache will be cleaned for the post ID.
+ *
+ * @since 2.5.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int $post_id Optional. Post ID to change post type. Default 0.
+ * @param string $post_type Optional. Post type. Accepts 'post' or 'page' to
+ * name a few. Default 'post'.
+ * @return int|false Amount of rows changed. Should be 1 for success and 0 for failure.
+ */
+function set_post_type( $post_id = 0, $post_type = 'post' ) {
+ global $wpdb;
+
+ $post_type = sanitize_post_field('post_type', $post_type, $post_id, 'db');
+ $return = $wpdb->update( $wpdb->posts, array('post_type' => $post_type), array('ID' => $post_id) );
+
+ clean_post_cache( $post_id );
+
+ return $return;
+}
+
+/**
+ * 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.4.0
+ * @since 4.5.0 Added the ability to pass a post type name in addition to object.
+ *
+ * @param object $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 ( ! $post_type ) {
+ return false;
+ }
+ }
+
+ return $post_type->publicly_queryable || ( $post_type->_builtin && $post_type->public );
+}
+
+/**
+ * Retrieve list of latest posts or posts matching criteria.
+ *
+ * The defaults are as follows:
+ *
+ * @since 1.2.0
+ *
+ * @see WP_Query::parse_query()
+ *
+ * @param array $args {
+ * Optional. Arguments to retrieve posts. See WP_Query::parse_query() for all
+ * available arguments.
+ *
+ * @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 array $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 array $exclude An array of post IDs not to retrieve. Default empty array.
+ * @type bool $suppress_filters Whether to suppress filters. Default true.
+ * }
+ * @return array List of posts.
+ */
+function get_posts( $args = null ) {
+ $defaults = array(
+ 'numberposts' => 5,
+ 'category' => 0, 'orderby' => 'date',
+ 'order' => 'DESC', 'include' => array(),
+ 'exclude' => array(), 'meta_key' => '',
+ 'meta_value' =>'', 'post_type' => 'post',
+ 'suppress_filters' => true
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ if ( empty( $r['post_status'] ) )
+ $r['post_status'] = ( 'attachment' == $r['post_type'] ) ? 'inherit' : 'publish';
+ if ( ! empty($r['numberposts']) && empty($r['posts_per_page']) )
+ $r['posts_per_page'] = $r['numberposts'];
+ if ( ! empty($r['category']) )
+ $r['cat'] = $r['category'];
+ if ( ! empty($r['include']) ) {
+ $incposts = wp_parse_id_list( $r['include'] );
+ $r['posts_per_page'] = count($incposts); // only the number of posts included
+ $r['post__in'] = $incposts;
+ } elseif ( ! empty($r['exclude']) )
+ $r['post__not_in'] = wp_parse_id_list( $r['exclude'] );
+
+ $r['ignore_sticky_posts'] = true;
+ $r['no_found_rows'] = true;
+
+ $get_posts = new WP_Query;
+ return $get_posts->query($r);
+
+}
+
+//
+// Post meta functions
+//
+
+/**
+ * Add meta data field to a post.
+ *
+ * Post meta data is called "Custom Fields" on the Administration Screen.
+ *
+ * @since 1.5.0
+ *
+ * @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.
+ * Default false.
+ * @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.
+ if ( $the_post = wp_is_post_revision($post_id) )
+ $post_id = $the_post;
+
+ return add_metadata('post', $post_id, $meta_key, $meta_value, $unique);
+}
+
+/**
+ * Remove metadata matching criteria from a post.
+ *
+ * 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 key, if needed.
+ *
+ * @since 1.5.0
+ *
+ * @param int $post_id Post ID.
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Optional. Metadata 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.
+ if ( $the_post = wp_is_post_revision($post_id) )
+ $post_id = $the_post;
+
+ return delete_metadata('post', $post_id, $meta_key, $meta_value);
+}
+
+/**
+ * Retrieve post meta field for a post.
+ *
+ * @since 1.5.0
+ *
+ * @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. Default false.
+ * @return mixed Will be an array if $single is false. Will be value of meta data
+ * field if $single is true.
+ */
+function get_post_meta( $post_id, $key = '', $single = false ) {
+ return get_metadata('post', $post_id, $key, $single);
+}
+
+/**
+ * Update post meta field based on post ID.
+ *
+ * Use the $prev_value parameter to differentiate between meta fields with the
+ * same key and post ID.
+ *
+ * If the meta field for the post does not exist, it will be added.
+ *
+ * @since 1.5.0
+ *
+ * @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 removing.
+ * Default empty.
+ * @return int|bool Meta ID if the key didn't exist, true on successful update,
+ * false on failure.
+ */
+function update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' ) {
+ // Make sure meta is added to the post, not a revision.
+ if ( $the_post = wp_is_post_revision($post_id) )
+ $post_id = $the_post;
+
+ return update_metadata('post', $post_id, $meta_key, $meta_value, $prev_value);
+}
+
+/**
+ * Delete everything from post meta matching meta key.
+ *
+ * @since 2.3.0
+ *
+ * @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 );
+}
+
+/**
+ * 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.
+ *
+ * @since 1.2.0
+ *
+ * @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 );
+ if ( ! $post_id )
+ $post_id = get_the_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.
+ *
+ * @since 1.2.0
+ *
+ * @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) )
+ return;
+
+ if ( $keys = array_keys($custom) )
+ return $keys;
+}
+
+/**
+ * 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.
+ *
+ * @since 1.2.0
+ *
+ * @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 ) {
+ if ( !$key )
+ return null;
+
+ $custom = get_post_custom($post_id);
+
+ return isset($custom[$key]) ? $custom[$key] : null;
+}
+
+/**
+ * Check if 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.
+ *
+ * @since 2.7.0
+ *
+ * @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 );
+
+ if ( ! $post_id )
+ $post_id = get_the_ID();
+
+ $stickies = get_option( 'sticky_posts' );
+
+ if ( ! is_array( $stickies ) )
+ return false;
+
+ if ( in_array( $post_id, $stickies ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Sanitize every post field.
+ *
+ * If the context is 'raw', then the post object or array will get minimal
+ * sanitization of the integer fields.
+ *
+ * @since 2.3.0
+ *
+ * @see sanitize_post_field()