+ * Store or return a list of post type meta caps for map_meta_cap().
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @param null|array $capabilities Post type meta capabilities.
+ */
+function _post_type_meta_capabilities( $capabilities = null ) {
+ static $meta_caps = array();
+ if ( null === $capabilities )
+ return $meta_caps;
+ foreach ( $capabilities as $core => $custom ) {
+ if ( in_array( $core, array( 'read_post', 'delete_post', 'edit_post' ) ) )
+ $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
+ * {@see http://codex.wordpress.org/I18n_for_WordPress_Developers#Disambiguation_by_context}
+ * matching your post type. Example: <code>_x('Add New', 'product');</code>.
+ * - 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.
+ * - menu_name - Default is the same as <code>name</code>.
+ *
+ * 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
+ * @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' ) )
+ );
+ $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;
+
+ /**
+ * 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 array $labels Array of labels for the given post type.
+ */
+ return apply_filters( "post_type_labels_{$post_type}", $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.
+ */
+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'];
+
+ foreach ( $nohier_vs_hier_defaults as $key => $value )
+ $defaults[$key] = $object->hierarchical ? $value[1] : $value[0];
+
+ $labels = array_merge( $defaults, $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" );
+ }
+}
+add_action( 'admin_menu', '_add_post_type_submenus' );
+
+/**
+ * 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
+ *
+ * @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
+ *
+ * @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;
+
+ if ( isset( $_wp_post_type_features[$post_type][$feature] ) )
+ unset( $_wp_post_type_features[$post_type][$feature] );
+}
+
+/**
+ * Get all the post type features
+ *
+ * @since 3.4.0
+ *
+ * @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
+ *
+ * @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] ) );
+}
+
+/**
+ * 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 access 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 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;
+}
+
+/**
+ * Retrieve list of latest posts or posts matching criteria.