2019-11-02 10:38:58 +01:00
< ? php
/**
* Core Post API
*
* @ package WordPress
* @ subpackage Post
*/
//
2020-05-06 17:23:38 +02:00
// Post Type registration.
2019-11-02 10:38:58 +01:00
//
/**
* Creates the initial post types when 'init' action is fired .
*
* See { @ see 'init' } .
*
* @ since 2.9 . 0
*/
function create_initial_post_types () {
2022-06-16 14:03:35 +02:00
WP_Post_Type :: reset_default_labels ();
2019-11-02 10:38:58 +01:00
register_post_type (
'post' ,
array (
'labels' => array (
'name_admin_bar' => _x ( 'Post' , 'add new from admin bar' ),
),
'public' => true ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'_edit_link' => 'post.php?post=%d' , /* internal use only. don't use this when registering your own post type. */
'capability_type' => 'post' ,
'map_meta_cap' => true ,
'menu_position' => 5 ,
2020-05-06 17:23:38 +02:00
'menu_icon' => 'dashicons-admin-post' ,
2019-11-02 10:38:58 +01:00
'hierarchical' => false ,
'rewrite' => false ,
'query_var' => false ,
'delete_with_user' => true ,
'supports' => array ( 'title' , 'editor' , 'author' , 'thumbnail' , 'excerpt' , 'trackbacks' , 'custom-fields' , 'comments' , 'revisions' , 'post-formats' ),
'show_in_rest' => true ,
'rest_base' => 'posts' ,
'rest_controller_class' => 'WP_REST_Posts_Controller' ,
)
);
register_post_type (
'page' ,
array (
'labels' => array (
'name_admin_bar' => _x ( 'Page' , 'add new from admin bar' ),
),
'public' => true ,
'publicly_queryable' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'_edit_link' => 'post.php?post=%d' , /* internal use only. don't use this when registering your own post type. */
'capability_type' => 'page' ,
'map_meta_cap' => true ,
'menu_position' => 20 ,
2020-05-06 17:23:38 +02:00
'menu_icon' => 'dashicons-admin-page' ,
2019-11-02 10:38:58 +01:00
'hierarchical' => true ,
'rewrite' => false ,
'query_var' => false ,
'delete_with_user' => true ,
'supports' => array ( 'title' , 'editor' , 'author' , 'thumbnail' , 'page-attributes' , 'custom-fields' , 'comments' , 'revisions' ),
'show_in_rest' => true ,
'rest_base' => 'pages' ,
'rest_controller_class' => 'WP_REST_Posts_Controller' ,
)
);
register_post_type (
'attachment' ,
array (
'labels' => array (
'name' => _x ( 'Media' , 'post type general name' ),
'name_admin_bar' => _x ( 'Media' , 'add new from admin bar' ),
2022-12-15 17:47:31 +01:00
'add_new' => _x ( 'Add New' , 'file' ),
2019-11-02 10:38:58 +01:00
'edit_item' => __ ( 'Edit Media' ),
'view_item' => __ ( 'View Attachment Page' ),
'attributes' => __ ( 'Attachment Attributes' ),
),
'public' => true ,
'show_ui' => true ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'_edit_link' => 'post.php?post=%d' , /* internal use only. don't use this when registering your own post type. */
'capability_type' => 'post' ,
'capabilities' => array (
'create_posts' => 'upload_files' ,
),
'map_meta_cap' => true ,
2020-05-06 17:23:38 +02:00
'menu_icon' => 'dashicons-admin-media' ,
2019-11-02 10:38:58 +01:00
'hierarchical' => false ,
'rewrite' => false ,
'query_var' => false ,
'show_in_nav_menus' => false ,
'delete_with_user' => true ,
'supports' => array ( 'title' , 'author' , 'comments' ),
'show_in_rest' => true ,
'rest_base' => 'media' ,
'rest_controller_class' => 'WP_REST_Attachments_Controller' ,
)
);
add_post_type_support ( 'attachment:audio' , 'thumbnail' );
add_post_type_support ( 'attachment:video' , 'thumbnail' );
register_post_type (
'revision' ,
array (
'labels' => array (
'name' => __ ( 'Revisions' ),
'singular_name' => __ ( 'Revision' ),
),
'public' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'_edit_link' => 'revision.php?revision=%d' , /* internal use only. don't use this when registering your own post type. */
'capability_type' => 'post' ,
'map_meta_cap' => true ,
'hierarchical' => false ,
'rewrite' => false ,
'query_var' => false ,
'can_export' => false ,
'delete_with_user' => true ,
'supports' => array ( 'author' ),
)
);
register_post_type (
'nav_menu_item' ,
array (
2022-04-02 10:26:41 +02:00
'labels' => array (
2019-11-02 10:38:58 +01:00
'name' => __ ( 'Navigation Menu Items' ),
'singular_name' => __ ( 'Navigation Menu Item' ),
),
2022-04-02 10:26:41 +02:00
'public' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'hierarchical' => false ,
'rewrite' => false ,
'delete_with_user' => false ,
'query_var' => false ,
'map_meta_cap' => true ,
'capability_type' => array ( 'edit_theme_options' , 'edit_theme_options' ),
'capabilities' => array (
// Meta Capabilities.
'edit_post' => 'edit_post' ,
'read_post' => 'read_post' ,
'delete_post' => 'delete_post' ,
// Primitive Capabilities.
'edit_posts' => 'edit_theme_options' ,
'edit_others_posts' => 'edit_theme_options' ,
'delete_posts' => 'edit_theme_options' ,
'publish_posts' => 'edit_theme_options' ,
'read_private_posts' => 'edit_theme_options' ,
'read' => 'read' ,
'delete_private_posts' => 'edit_theme_options' ,
'delete_published_posts' => 'edit_theme_options' ,
'delete_others_posts' => 'edit_theme_options' ,
'edit_private_posts' => 'edit_theme_options' ,
'edit_published_posts' => 'edit_theme_options' ,
),
'show_in_rest' => true ,
'rest_base' => 'menu-items' ,
'rest_controller_class' => 'WP_REST_Menu_Items_Controller' ,
2019-11-02 10:38:58 +01:00
)
);
register_post_type (
'custom_css' ,
array (
'labels' => array (
'name' => __ ( 'Custom CSS' ),
'singular_name' => __ ( 'Custom CSS' ),
),
'public' => false ,
'hierarchical' => false ,
'rewrite' => false ,
'query_var' => false ,
'delete_with_user' => false ,
'can_export' => true ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'supports' => array ( 'title' , 'revisions' ),
'capabilities' => array (
'delete_posts' => 'edit_theme_options' ,
'delete_post' => 'edit_theme_options' ,
'delete_published_posts' => 'edit_theme_options' ,
'delete_private_posts' => 'edit_theme_options' ,
'delete_others_posts' => 'edit_theme_options' ,
'edit_post' => 'edit_css' ,
'edit_posts' => 'edit_css' ,
'edit_others_posts' => 'edit_css' ,
'edit_published_posts' => 'edit_css' ,
'read_post' => 'read' ,
'read_private_posts' => 'read' ,
'publish_posts' => 'edit_theme_options' ,
),
)
);
register_post_type (
'customize_changeset' ,
array (
'labels' => array (
'name' => _x ( 'Changesets' , 'post type general name' ),
'singular_name' => _x ( 'Changeset' , 'post type singular name' ),
'add_new' => _x ( 'Add New' , 'Customize Changeset' ),
'add_new_item' => __ ( 'Add New Changeset' ),
'new_item' => __ ( 'New Changeset' ),
'edit_item' => __ ( 'Edit Changeset' ),
'view_item' => __ ( 'View Changeset' ),
'all_items' => __ ( 'All Changesets' ),
'search_items' => __ ( 'Search Changesets' ),
'not_found' => __ ( 'No changesets found.' ),
'not_found_in_trash' => __ ( 'No changesets found in Trash.' ),
),
'public' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'map_meta_cap' => true ,
'hierarchical' => false ,
'rewrite' => false ,
'query_var' => false ,
'can_export' => false ,
'delete_with_user' => false ,
'supports' => array ( 'title' , 'author' ),
'capability_type' => 'customize_changeset' ,
'capabilities' => array (
'create_posts' => 'customize' ,
'delete_others_posts' => 'customize' ,
'delete_post' => 'customize' ,
'delete_posts' => 'customize' ,
'delete_private_posts' => 'customize' ,
'delete_published_posts' => 'customize' ,
'edit_others_posts' => 'customize' ,
'edit_post' => 'customize' ,
'edit_posts' => 'customize' ,
'edit_private_posts' => 'customize' ,
'edit_published_posts' => 'do_not_allow' ,
'publish_posts' => 'customize' ,
'read' => 'read' ,
'read_post' => 'customize' ,
'read_private_posts' => 'customize' ,
),
)
);
register_post_type (
'oembed_cache' ,
array (
'labels' => array (
'name' => __ ( 'oEmbed Responses' ),
'singular_name' => __ ( 'oEmbed Response' ),
),
'public' => false ,
'hierarchical' => false ,
'rewrite' => false ,
'query_var' => false ,
'delete_with_user' => false ,
'can_export' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'supports' => array (),
)
);
register_post_type (
'user_request' ,
array (
'labels' => array (
'name' => __ ( 'User Requests' ),
'singular_name' => __ ( 'User Request' ),
),
'public' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'hierarchical' => false ,
'rewrite' => false ,
'query_var' => false ,
'can_export' => false ,
'delete_with_user' => false ,
'supports' => array (),
)
);
register_post_type (
'wp_block' ,
array (
'labels' => array (
2021-07-23 11:58:50 +02:00
'name' => _x ( 'Reusable blocks' , 'post type general name' ),
'singular_name' => _x ( 'Reusable block' , 'post type singular name' ),
'add_new' => _x ( 'Add New' , 'Reusable block' ),
'add_new_item' => __ ( 'Add new Reusable block' ),
'new_item' => __ ( 'New Reusable block' ),
'edit_item' => __ ( 'Edit Reusable block' ),
'view_item' => __ ( 'View Reusable block' ),
'all_items' => __ ( 'All Reusable blocks' ),
'search_items' => __ ( 'Search Reusable blocks' ),
2020-12-10 14:06:04 +01:00
'not_found' => __ ( 'No reusable blocks found.' ),
'not_found_in_trash' => __ ( 'No reusable blocks found in Trash.' ),
'filter_items_list' => __ ( 'Filter reusable blocks list' ),
2021-07-23 11:58:50 +02:00
'items_list_navigation' => __ ( 'Reusable blocks list navigation' ),
'items_list' => __ ( 'Reusable blocks list' ),
'item_published' => __ ( 'Reusable block published.' ),
'item_published_privately' => __ ( 'Reusable block published privately.' ),
'item_reverted_to_draft' => __ ( 'Reusable block reverted to draft.' ),
'item_scheduled' => __ ( 'Reusable block scheduled.' ),
'item_updated' => __ ( 'Reusable block updated.' ),
2019-11-02 10:38:58 +01:00
),
'public' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'show_ui' => true ,
'show_in_menu' => false ,
'rewrite' => false ,
'show_in_rest' => true ,
'rest_base' => 'blocks' ,
'rest_controller_class' => 'WP_REST_Blocks_Controller' ,
'capability_type' => 'block' ,
'capabilities' => array (
// You need to be able to edit posts, in order to read blocks in their raw form.
'read' => 'edit_posts' ,
// You need to be able to publish posts, in order to create blocks.
'create_posts' => 'publish_posts' ,
'edit_posts' => 'edit_posts' ,
'edit_published_posts' => 'edit_published_posts' ,
'delete_published_posts' => 'delete_published_posts' ,
'edit_others_posts' => 'edit_others_posts' ,
'delete_others_posts' => 'delete_others_posts' ,
),
'map_meta_cap' => true ,
'supports' => array (
'title' ,
'editor' ,
2021-07-23 11:58:50 +02:00
'revisions' ,
),
)
);
register_post_type (
'wp_template' ,
array (
'labels' => array (
2022-04-02 10:26:41 +02:00
'name' => _x ( 'Templates' , 'post type general name' ),
'singular_name' => _x ( 'Template' , 'post type singular name' ),
2021-07-23 11:58:50 +02:00
'add_new' => _x ( 'Add New' , 'Template' ),
'add_new_item' => __ ( 'Add New Template' ),
'new_item' => __ ( 'New Template' ),
'edit_item' => __ ( 'Edit Template' ),
'view_item' => __ ( 'View Template' ),
2022-04-02 10:26:41 +02:00
'all_items' => __ ( 'Templates' ),
2021-07-23 11:58:50 +02:00
'search_items' => __ ( 'Search Templates' ),
'parent_item_colon' => __ ( 'Parent Template:' ),
'not_found' => __ ( 'No templates found.' ),
'not_found_in_trash' => __ ( 'No templates found in Trash.' ),
'archives' => __ ( 'Template archives' ),
'insert_into_item' => __ ( 'Insert into template' ),
'uploaded_to_this_item' => __ ( 'Uploaded to this template' ),
'filter_items_list' => __ ( 'Filter templates list' ),
'items_list_navigation' => __ ( 'Templates list navigation' ),
'items_list' => __ ( 'Templates list' ),
),
'description' => __ ( 'Templates to include in your theme.' ),
'public' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'has_archive' => false ,
'show_ui' => false ,
'show_in_menu' => false ,
'show_in_rest' => true ,
'rewrite' => false ,
'rest_base' => 'templates' ,
'rest_controller_class' => 'WP_REST_Templates_Controller' ,
'capability_type' => array ( 'template' , 'templates' ),
'capabilities' => array (
'create_posts' => 'edit_theme_options' ,
'delete_posts' => 'edit_theme_options' ,
'delete_others_posts' => 'edit_theme_options' ,
'delete_private_posts' => 'edit_theme_options' ,
'delete_published_posts' => 'edit_theme_options' ,
'edit_posts' => 'edit_theme_options' ,
'edit_others_posts' => 'edit_theme_options' ,
'edit_private_posts' => 'edit_theme_options' ,
'edit_published_posts' => 'edit_theme_options' ,
'publish_posts' => 'edit_theme_options' ,
'read' => 'edit_theme_options' ,
'read_private_posts' => 'edit_theme_options' ,
),
'map_meta_cap' => true ,
'supports' => array (
'title' ,
'slug' ,
'excerpt' ,
'editor' ,
'revisions' ,
2022-04-02 10:26:41 +02:00
'author' ,
),
)
);
register_post_type (
'wp_template_part' ,
array (
'labels' => array (
'name' => _x ( 'Template Parts' , 'post type general name' ),
'singular_name' => _x ( 'Template Part' , 'post type singular name' ),
'add_new' => _x ( 'Add New' , 'Template Part' ),
'add_new_item' => __ ( 'Add New Template Part' ),
'new_item' => __ ( 'New Template Part' ),
'edit_item' => __ ( 'Edit Template Part' ),
'view_item' => __ ( 'View Template Part' ),
'all_items' => __ ( 'Template Parts' ),
'search_items' => __ ( 'Search Template Parts' ),
'parent_item_colon' => __ ( 'Parent Template Part:' ),
'not_found' => __ ( 'No template parts found.' ),
'not_found_in_trash' => __ ( 'No template parts found in Trash.' ),
'archives' => __ ( 'Template part archives' ),
'insert_into_item' => __ ( 'Insert into template part' ),
'uploaded_to_this_item' => __ ( 'Uploaded to this template part' ),
'filter_items_list' => __ ( 'Filter template parts list' ),
'items_list_navigation' => __ ( 'Template parts list navigation' ),
'items_list' => __ ( 'Template parts list' ),
),
'description' => __ ( 'Template parts to include in your templates.' ),
'public' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'has_archive' => false ,
'show_ui' => false ,
'show_in_menu' => false ,
'show_in_rest' => true ,
'rewrite' => false ,
'rest_base' => 'template-parts' ,
'rest_controller_class' => 'WP_REST_Templates_Controller' ,
'map_meta_cap' => true ,
'capabilities' => array (
'create_posts' => 'edit_theme_options' ,
'delete_posts' => 'edit_theme_options' ,
'delete_others_posts' => 'edit_theme_options' ,
'delete_private_posts' => 'edit_theme_options' ,
'delete_published_posts' => 'edit_theme_options' ,
'edit_posts' => 'edit_theme_options' ,
'edit_others_posts' => 'edit_theme_options' ,
'edit_private_posts' => 'edit_theme_options' ,
'edit_published_posts' => 'edit_theme_options' ,
'publish_posts' => 'edit_theme_options' ,
'read' => 'edit_theme_options' ,
'read_private_posts' => 'edit_theme_options' ,
),
'supports' => array (
'title' ,
'slug' ,
'excerpt' ,
'editor' ,
'revisions' ,
'author' ,
),
)
);
register_post_type (
'wp_global_styles' ,
array (
'label' => _x ( 'Global Styles' , 'post type general name' ),
'description' => __ ( 'Global styles to include in themes.' ),
'public' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'show_ui' => false ,
'show_in_rest' => false ,
'rewrite' => false ,
'capabilities' => array (
'read' => 'edit_theme_options' ,
'create_posts' => 'edit_theme_options' ,
'edit_posts' => 'edit_theme_options' ,
'edit_published_posts' => 'edit_theme_options' ,
'delete_published_posts' => 'edit_theme_options' ,
'edit_others_posts' => 'edit_theme_options' ,
'delete_others_posts' => 'edit_theme_options' ,
),
'map_meta_cap' => true ,
'supports' => array (
'title' ,
'editor' ,
'revisions' ,
),
)
);
register_post_type (
'wp_navigation' ,
array (
'labels' => array (
'name' => _x ( 'Navigation Menus' , 'post type general name' ),
'singular_name' => _x ( 'Navigation Menu' , 'post type singular name' ),
'add_new' => _x ( 'Add New' , 'Navigation Menu' ),
'add_new_item' => __ ( 'Add New Navigation Menu' ),
'new_item' => __ ( 'New Navigation Menu' ),
'edit_item' => __ ( 'Edit Navigation Menu' ),
'view_item' => __ ( 'View Navigation Menu' ),
'all_items' => __ ( 'Navigation Menus' ),
'search_items' => __ ( 'Search Navigation Menus' ),
'parent_item_colon' => __ ( 'Parent Navigation Menu:' ),
'not_found' => __ ( 'No Navigation Menu found.' ),
'not_found_in_trash' => __ ( 'No Navigation Menu found in Trash.' ),
'archives' => __ ( 'Navigation Menu archives' ),
'insert_into_item' => __ ( 'Insert into Navigation Menu' ),
'uploaded_to_this_item' => __ ( 'Uploaded to this Navigation Menu' ),
'filter_items_list' => __ ( 'Filter Navigation Menu list' ),
'items_list_navigation' => __ ( 'Navigation Menus list navigation' ),
'items_list' => __ ( 'Navigation Menus list' ),
),
'description' => __ ( 'Navigation menus that can be inserted into your site.' ),
'public' => false ,
'_builtin' => true , /* internal use only. don't use this when registering your own post type. */
'has_archive' => false ,
'show_ui' => true ,
'show_in_menu' => false ,
'show_in_admin_bar' => false ,
'show_in_rest' => true ,
'rewrite' => false ,
'map_meta_cap' => true ,
'capabilities' => array (
'edit_others_posts' => 'edit_theme_options' ,
'delete_posts' => 'edit_theme_options' ,
'publish_posts' => 'edit_theme_options' ,
'create_posts' => 'edit_theme_options' ,
'read_private_posts' => 'edit_theme_options' ,
'delete_private_posts' => 'edit_theme_options' ,
'delete_published_posts' => 'edit_theme_options' ,
'delete_others_posts' => 'edit_theme_options' ,
'edit_private_posts' => 'edit_theme_options' ,
'edit_published_posts' => 'edit_theme_options' ,
'edit_posts' => 'edit_theme_options' ,
),
'rest_base' => 'navigation' ,
'rest_controller_class' => 'WP_REST_Posts_Controller' ,
'supports' => array (
'title' ,
'editor' ,
'revisions' ,
2019-11-02 10:38:58 +01:00
),
)
);
register_post_status (
'publish' ,
array (
'label' => _x ( 'Published' , 'post status' ),
'public' => true ,
'_builtin' => true , /* internal use only. */
2019-11-15 22:59:44 +01:00
/* translators: %s: Number of published posts. */
'label_count' => _n_noop (
'Published <span class="count">(%s)</span>' ,
'Published <span class="count">(%s)</span>'
),
2019-11-02 10:38:58 +01:00
)
);
register_post_status (
'future' ,
array (
'label' => _x ( 'Scheduled' , 'post status' ),
'protected' => true ,
'_builtin' => true , /* internal use only. */
2019-11-15 22:59:44 +01:00
/* translators: %s: Number of scheduled posts. */
'label_count' => _n_noop (
'Scheduled <span class="count">(%s)</span>' ,
'Scheduled <span class="count">(%s)</span>'
),
2019-11-02 10:38:58 +01:00
)
);
register_post_status (
'draft' ,
array (
2019-11-15 22:59:44 +01:00
'label' => _x ( 'Draft' , 'post status' ),
'protected' => true ,
'_builtin' => true , /* internal use only. */
/* translators: %s: Number of draft posts. */
'label_count' => _n_noop (
'Draft <span class="count">(%s)</span>' ,
'Drafts <span class="count">(%s)</span>'
),
'date_floating' => true ,
2019-11-02 10:38:58 +01:00
)
);
register_post_status (
'pending' ,
array (
2019-11-15 22:59:44 +01:00
'label' => _x ( 'Pending' , 'post status' ),
'protected' => true ,
'_builtin' => true , /* internal use only. */
/* translators: %s: Number of pending posts. */
'label_count' => _n_noop (
'Pending <span class="count">(%s)</span>' ,
'Pending <span class="count">(%s)</span>'
),
'date_floating' => true ,
2019-11-02 10:38:58 +01:00
)
);
register_post_status (
'private' ,
array (
'label' => _x ( 'Private' , 'post status' ),
'private' => true ,
'_builtin' => true , /* internal use only. */
2019-11-15 22:59:44 +01:00
/* translators: %s: Number of private posts. */
'label_count' => _n_noop (
'Private <span class="count">(%s)</span>' ,
'Private <span class="count">(%s)</span>'
),
2019-11-02 10:38:58 +01:00
)
);
register_post_status (
'trash' ,
array (
'label' => _x ( 'Trash' , 'post status' ),
'internal' => true ,
'_builtin' => true , /* internal use only. */
2019-11-15 22:59:44 +01:00
/* translators: %s: Number of trashed posts. */
'label_count' => _n_noop (
'Trash <span class="count">(%s)</span>' ,
'Trash <span class="count">(%s)</span>'
),
2019-11-02 10:38:58 +01:00
'show_in_admin_status_list' => true ,
)
);
register_post_status (
'auto-draft' ,
array (
2019-11-15 22:59:44 +01:00
'label' => 'auto-draft' ,
'internal' => true ,
'_builtin' => true , /* internal use only. */
'date_floating' => true ,
2019-11-02 10:38:58 +01:00
)
);
register_post_status (
'inherit' ,
array (
'label' => 'inherit' ,
'internal' => true ,
'_builtin' => true , /* internal use only. */
'exclude_from_search' => false ,
)
);
register_post_status (
'request-pending' ,
array (
'label' => _x ( 'Pending' , 'request status' ),
'internal' => true ,
'_builtin' => true , /* internal use only. */
2019-11-15 22:59:44 +01:00
/* translators: %s: Number of pending requests. */
'label_count' => _n_noop (
'Pending <span class="count">(%s)</span>' ,
'Pending <span class="count">(%s)</span>'
),
2019-11-02 10:38:58 +01:00
'exclude_from_search' => false ,
)
);
register_post_status (
'request-confirmed' ,
array (
'label' => _x ( 'Confirmed' , 'request status' ),
'internal' => true ,
'_builtin' => true , /* internal use only. */
2019-11-15 22:59:44 +01:00
/* translators: %s: Number of confirmed requests. */
'label_count' => _n_noop (
'Confirmed <span class="count">(%s)</span>' ,
'Confirmed <span class="count">(%s)</span>'
),
2019-11-02 10:38:58 +01:00
'exclude_from_search' => false ,
)
);
register_post_status (
'request-failed' ,
array (
'label' => _x ( 'Failed' , 'request status' ),
'internal' => true ,
'_builtin' => true , /* internal use only. */
2019-11-15 22:59:44 +01:00
/* translators: %s: Number of failed requests. */
'label_count' => _n_noop (
'Failed <span class="count">(%s)</span>' ,
'Failed <span class="count">(%s)</span>'
),
2019-11-02 10:38:58 +01:00
'exclude_from_search' => false ,
)
);
register_post_status (
'request-completed' ,
array (
'label' => _x ( 'Completed' , 'request status' ),
'internal' => true ,
'_builtin' => true , /* internal use only. */
2019-11-15 22:59:44 +01:00
/* translators: %s: Number of completed requests. */
'label_count' => _n_noop (
'Completed <span class="count">(%s)</span>' ,
'Completed <span class="count">(%s)</span>'
),
2019-11-02 10:38:58 +01:00
'exclude_from_search' => false ,
)
);
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves attached file path based on attachment ID .
2019-11-02 10:38:58 +01:00
*
2023-04-26 17:39:43 +02:00
* By default the path will go through the { @ see 'get_attached_file' } filter , but
* passing `true` to the `$unfiltered` argument will return the file path unfiltered .
2019-11-02 10:38:58 +01:00
*
2023-04-26 17:39:43 +02:00
* The function works by retrieving the `_wp_attached_file` post meta value .
* This is a convenience function to prevent looking up the meta name and provide
* a mechanism for sending the attached filename through a filter .
2019-11-02 10:38:58 +01:00
*
* @ since 2.0 . 0
*
* @ param int $attachment_id Attachment ID .
2023-04-26 17:39:43 +02:00
* @ param bool $unfiltered Optional . Whether to skip the { @ see 'get_attached_file' } filter .
* Default false .
2019-11-02 10:38:58 +01:00
* @ return string | false The file path to where the attached file should be , false otherwise .
*/
function get_attached_file ( $attachment_id , $unfiltered = false ) {
$file = get_post_meta ( $attachment_id , '_wp_attached_file' , true );
// If the file is relative, prepend upload dir.
2019-11-15 22:59:44 +01:00
if ( $file && 0 !== strpos ( $file , '/' ) && ! preg_match ( '|^.:\\\|' , $file ) ) {
$uploads = wp_get_upload_dir ();
if ( false === $uploads [ 'error' ] ) {
$file = $uploads [ 'basedir' ] . " / $file " ;
}
2019-11-02 10:38:58 +01:00
}
if ( $unfiltered ) {
return $file ;
}
/**
* Filters the attached file based on the given ID .
*
* @ since 2.1 . 0
*
2020-09-15 14:29:22 +02:00
* @ param string | false $file The file path to where the attached file should be , false otherwise .
* @ param int $attachment_id Attachment ID .
2019-11-02 10:38:58 +01:00
*/
return apply_filters ( 'get_attached_file' , $file , $attachment_id );
}
/**
2022-12-15 17:47:31 +01:00
* Updates attachment file path based on attachment ID .
2019-11-02 10:38:58 +01:00
*
* Used to update the file path of the attachment , which uses post meta name
* '_wp_attached_file' to store the path of the attachment .
*
* @ since 2.1 . 0
*
* @ param int $attachment_id Attachment ID .
* @ param string $file File path for the attachment .
* @ return bool True on success , false on failure .
*/
function update_attached_file ( $attachment_id , $file ) {
if ( ! get_post ( $attachment_id ) ) {
return false ;
}
/**
* Filters the path to the attached file to update .
*
* @ since 2.1 . 0
*
* @ param string $file Path to the attached file to update .
* @ param int $attachment_id Attachment ID .
*/
$file = apply_filters ( 'update_attached_file' , $file , $attachment_id );
2019-11-15 22:59:44 +01:00
$file = _wp_relative_upload_path ( $file );
if ( $file ) {
2019-11-02 10:38:58 +01:00
return update_post_meta ( $attachment_id , '_wp_attached_file' , $file );
} else {
return delete_post_meta ( $attachment_id , '_wp_attached_file' );
}
}
/**
2022-12-15 17:47:31 +01:00
* Returns relative path to an uploaded file .
2019-11-02 10:38:58 +01:00
*
* The path is relative to the current upload dir .
*
* @ since 2.9 . 0
* @ access private
*
* @ param string $path Full path to the file .
* @ return string Relative path on success , unchanged path on failure .
*/
function _wp_relative_upload_path ( $path ) {
$new_path = $path ;
$uploads = wp_get_upload_dir ();
if ( 0 === strpos ( $new_path , $uploads [ 'basedir' ] ) ) {
$new_path = str_replace ( $uploads [ 'basedir' ], '' , $new_path );
$new_path = ltrim ( $new_path , '/' );
}
/**
* Filters the relative path to an uploaded file .
*
* @ since 2.9 . 0
*
* @ param string $new_path Relative path to the file .
* @ param string $path Full path to the file .
*/
return apply_filters ( '_wp_relative_upload_path' , $new_path , $path );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves all children of the post parent ID .
2019-11-02 10:38:58 +01:00
*
* Normally , without any enhancements , the children would apply to pages . In the
* context of the inner workings of WordPress , pages , posts , and attachments
* share the same table , so therefore the functionality could apply to any one
* of them . It is then noted that while this function does not work on posts , it
* does not mean that it won ' t work on posts . It is recommended that you know
* what context you wish to retrieve the children of .
*
* Attachments may also be made the child of a post , so if that is an accurate
* statement ( which needs to be verified ), it would then be possible to get
* all of the attachments for a post . Attachments have since changed since
* version 2.5 , so this is most likely inaccurate , but serves generally as an
* example of what is possible .
*
* The arguments listed as defaults are for this function and also of the
* get_posts () function . The arguments are combined with the get_children defaults
* and are then passed to the get_posts () function , which accepts additional arguments .
* You can replace the defaults in this function , listed below and the additional
* arguments listed in the get_posts () function .
*
* The 'post_parent' is the most important argument and important attention
* needs to be paid to the $args parameter . If you pass either an object or an
* integer ( number ), then just the 'post_parent' is grabbed and everything else
* is lost . If you don ' t specify any arguments , then it is assumed that you are
* in The Loop and the post parent will be grabbed for from the current post .
*
* The 'post_parent' argument is the ID to get the children . The 'numberposts'
* is the amount of posts to retrieve that has a default of '-1' , which is
* used to get all of the posts . Giving a number higher than 0 will only
* retrieve that amount of posts .
*
* The 'post_type' and 'post_status' arguments can be used to choose what
* criteria of posts to retrieve . The 'post_type' can be anything , but WordPress
* post types are 'post' , 'pages' , and 'attachments' . The 'post_status'
* argument will accept any post status within the write administration panels .
*
* @ since 2.0 . 0
*
* @ see get_posts ()
* @ todo Check validity of description .
*
2019-11-15 22:59:44 +01:00
* @ global WP_Post $post Global post object .
2019-11-02 10:38:58 +01:00
*
* @ param mixed $args Optional . User defined arguments for replacing the defaults . Default empty .
2020-09-15 14:29:22 +02:00
* @ param string $output Optional . 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 .
2022-12-15 17:47:31 +01:00
* @ return WP_Post [] | array [] | int [] Array of post objects , arrays , or IDs , depending on `$output` .
2019-11-02 10:38:58 +01:00
*/
function get_children ( $args = '' , $output = OBJECT ) {
$kids = array ();
if ( empty ( $args ) ) {
if ( isset ( $GLOBALS [ 'post' ] ) ) {
$args = array ( 'post_parent' => ( int ) $GLOBALS [ 'post' ] -> post_parent );
} else {
return $kids ;
}
} elseif ( is_object ( $args ) ) {
$args = array ( 'post_parent' => ( int ) $args -> post_parent );
} elseif ( is_numeric ( $args ) ) {
$args = array ( 'post_parent' => ( int ) $args );
}
$defaults = array (
'numberposts' => - 1 ,
'post_type' => 'any' ,
'post_status' => 'any' ,
'post_parent' => 0 ,
);
2019-11-15 22:59:44 +01:00
$parsed_args = wp_parse_args ( $args , $defaults );
2019-11-02 10:38:58 +01:00
2019-11-15 22:59:44 +01:00
$children = get_posts ( $parsed_args );
2019-11-02 10:38:58 +01:00
if ( ! $children ) {
return $kids ;
}
2019-11-15 22:59:44 +01:00
if ( ! empty ( $parsed_args [ 'fields' ] ) ) {
2019-11-02 10:38:58 +01:00
return $children ;
}
update_post_cache ( $children );
foreach ( $children as $key => $child ) {
$kids [ $child -> ID ] = $children [ $key ];
}
2021-07-23 11:58:50 +02:00
if ( OBJECT === $output ) {
2019-11-02 10:38:58 +01:00
return $kids ;
2021-07-23 11:58:50 +02:00
} elseif ( ARRAY_A === $output ) {
2019-11-02 10:38:58 +01:00
$weeuns = array ();
foreach ( ( array ) $kids as $kid ) {
$weeuns [ $kid -> ID ] = get_object_vars ( $kids [ $kid -> ID ] );
}
return $weeuns ;
2021-07-23 11:58:50 +02:00
} elseif ( ARRAY_N === $output ) {
2019-11-02 10:38:58 +01:00
$babes = array ();
foreach ( ( array ) $kids as $kid ) {
$babes [ $kid -> ID ] = array_values ( get_object_vars ( $kids [ $kid -> ID ] ) );
}
return $babes ;
} else {
return $kids ;
}
}
/**
2022-12-15 17:47:31 +01:00
* Gets extended entry info ( <!-- more --> ) .
2019-11-02 10:38:58 +01:00
*
* There should not be any space after the second dash and before the word
* 'more' . There can be text or space ( s ) after the word 'more' , but won ' t be
* referenced .
*
* The returned array has 'main' , 'extended' , and 'more_text' keys . Main has the text before
* the `<!--more-->` . The 'extended' key has the content after the
* `<!--more-->` comment . The 'more_text' key has the custom " Read More " text .
*
* @ since 1.0 . 0
*
* @ param string $post Post content .
2020-05-06 17:23:38 +02:00
* @ return string [] {
* Extended entry info .
*
* @ type string $main Content before the more tag .
* @ type string $extended Content after the more tag .
* @ type string $more_text Custom read more text , or empty string .
* }
2019-11-02 10:38:58 +01:00
*/
function get_extended ( $post ) {
2020-05-06 17:23:38 +02:00
// Match the new style more links.
2019-11-02 10:38:58 +01:00
if ( preg_match ( '/<!--more(.*?)?-->/' , $post , $matches ) ) {
list ( $main , $extended ) = explode ( $matches [ 0 ], $post , 2 );
$more_text = $matches [ 1 ];
} else {
$main = $post ;
$extended = '' ;
$more_text = '' ;
}
2020-05-06 17:23:38 +02:00
// Leading and trailing whitespace.
2019-11-02 10:38:58 +01:00
$main = preg_replace ( '/^[\s]*(.*)[\s]*$/' , '\\1' , $main );
$extended = preg_replace ( '/^[\s]*(.*)[\s]*$/' , '\\1' , $extended );
$more_text = preg_replace ( '/^[\s]*(.*)[\s]*$/' , '\\1' , $more_text );
return array (
'main' => $main ,
'extended' => $extended ,
'more_text' => $more_text ,
);
}
/**
* Retrieves post data given a post ID or post object .
*
* See sanitize_post () for optional $filter values . Also , the parameter
* `$post` , must be given as a variable , since it is passed by reference .
*
* @ since 1.5 . 1
*
2019-11-15 22:59:44 +01:00
* @ global WP_Post $post Global post object .
2019-11-02 10:38:58 +01:00
*
2022-04-02 10:26:41 +02:00
* @ param int | WP_Post | null $post Optional . 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 .
2020-09-15 14:29:22 +02:00
* @ param string $output Optional . 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 .
2019-11-02 10:38:58 +01:00
* @ param string $filter Optional . Type of filter to apply . Accepts 'raw' , 'edit' , 'db' ,
* or 'display' . Default 'raw' .
* @ return WP_Post | array | null Type corresponding to $output on success or null on failure .
* When $output is OBJECT , a `WP_Post` instance is returned .
*/
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 );
2020-09-15 14:29:22 +02:00
} elseif ( 'raw' === $post -> filter ) {
2019-11-02 10:38:58 +01:00
$_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 );
2021-07-23 11:58:50 +02:00
if ( ARRAY_A === $output ) {
2019-11-02 10:38:58 +01:00
return $_post -> to_array ();
2021-07-23 11:58:50 +02:00
} elseif ( ARRAY_N === $output ) {
2019-11-02 10:38:58 +01:00
return array_values ( $_post -> to_array () );
}
return $_post ;
}
/**
2020-12-10 14:06:04 +01:00
* Retrieves the IDs of the ancestors of a post .
2019-11-02 10:38:58 +01:00
*
* @ since 2.5 . 0
*
* @ param int | WP_Post $post Post ID or post object .
2020-12-10 14:06:04 +01:00
* @ return int [] Array of ancestor IDs or empty array if there are none .
2019-11-02 10:38:58 +01:00
*/
function get_post_ancestors ( $post ) {
$post = get_post ( $post );
if ( ! $post || empty ( $post -> post_parent ) || $post -> post_parent == $post -> ID ) {
return array ();
}
$ancestors = array ();
2019-11-15 22:59:44 +01:00
$id = $post -> post_parent ;
$ancestors [] = $id ;
2019-11-02 10:38:58 +01:00
while ( $ancestor = get_post ( $id ) ) {
// Loop detection: If the ancestor has been seen before, break.
2020-09-15 14:29:22 +02:00
if ( empty ( $ancestor -> post_parent ) || ( $ancestor -> post_parent == $post -> ID ) || in_array ( $ancestor -> post_parent , $ancestors , true ) ) {
2019-11-02 10:38:58 +01:00
break ;
}
2019-11-15 22:59:44 +01:00
$id = $ancestor -> post_parent ;
$ancestors [] = $id ;
2019-11-02 10:38:58 +01:00
}
return $ancestors ;
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves data from a post field based on Post ID .
2019-11-02 10:38:58 +01:00
*
* Examples of the post field will be , 'post_type' , 'post_status' , 'post_content' ,
* etc and based off of the post object property or key names .
*
* The context values are based off of the taxonomy filter functions and
* supported values are found within those functions .
*
* @ since 2.3 . 0
* @ since 4.5 . 0 The `$post` parameter was made optional .
*
* @ see sanitize_post_field ()
*
* @ param string $field Post field name .
* @ param int | WP_Post $post Optional . Post ID or post object . Defaults to global $post .
* @ param string $context Optional . How to filter the field . Accepts 'raw' , 'edit' , 'db' ,
* or 'display' . Default 'display' .
* @ return string The value of the post field on success , empty string on failure .
*/
function get_post_field ( $field , $post = null , $context = 'display' ) {
$post = get_post ( $post );
if ( ! $post ) {
return '' ;
}
if ( ! isset ( $post -> $field ) ) {
return '' ;
}
return sanitize_post_field ( $field , $post -> $field , $post -> ID , $context );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves the mime type of an attachment based on the ID .
2019-11-02 10:38:58 +01:00
*
* This function can be used with any post type , but it makes more sense with
* attachments .
*
* @ since 2.0 . 0
*
* @ param int | WP_Post $post Optional . Post ID or post object . Defaults to global $post .
* @ return string | false The mime type on success , false on failure .
*/
function get_post_mime_type ( $post = null ) {
$post = get_post ( $post );
if ( is_object ( $post ) ) {
return $post -> post_mime_type ;
}
return false ;
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves the post status based on the post ID .
2019-11-02 10:38:58 +01:00
*
* If the post ID is of an attachment , then the parent post status will be given
* instead .
*
* @ since 2.0 . 0
*
2022-04-02 10:26:41 +02:00
* @ param int | WP_Post $post Optional . Post ID or post object . Defaults to global $post .
2019-11-02 10:38:58 +01:00
* @ return string | false Post status on success , false on failure .
*/
function get_post_status ( $post = null ) {
$post = get_post ( $post );
if ( ! is_object ( $post ) ) {
return false ;
}
2021-04-27 08:32:47 +02:00
$post_status = $post -> post_status ;
2019-11-02 10:38:58 +01:00
2021-04-27 08:32:47 +02:00
if (
'attachment' === $post -> post_type &&
'inherit' === $post_status
) {
if (
0 === $post -> post_parent ||
! get_post ( $post -> post_parent ) ||
$post -> ID === $post -> post_parent
) {
// Unattached attachments with inherit status are assumed to be published.
$post_status = 'publish' ;
} elseif ( 'trash' === get_post_status ( $post -> post_parent ) ) {
// Get parent status prior to trashing.
$post_status = get_post_meta ( $post -> post_parent , '_wp_trash_meta_status' , true );
2022-12-15 17:47:31 +01:00
2021-04-27 08:32:47 +02:00
if ( ! $post_status ) {
// Assume publish as above.
$post_status = 'publish' ;
2019-11-02 10:38:58 +01:00
}
2021-04-27 08:32:47 +02:00
} else {
$post_status = get_post_status ( $post -> post_parent );
2019-11-02 10:38:58 +01:00
}
2021-04-27 08:32:47 +02:00
} elseif (
'attachment' === $post -> post_type &&
! in_array ( $post_status , array ( 'private' , 'trash' , 'auto-draft' ), true )
) {
/*
* Ensure uninherited attachments have a permitted status either 'private' , 'trash' , 'auto-draft' .
* This is to match the logic in wp_insert_post () .
*
* Note : 'inherit' is excluded from this check as it is resolved to the parent post ' s
* status in the logic block above .
*/
$post_status = 'publish' ;
2019-11-02 10:38:58 +01:00
}
/**
* Filters the post status .
*
* @ since 4.4 . 0
2021-04-27 08:32:47 +02:00
* @ since 5.7 . 0 The attachment post type is now passed through this filter .
2019-11-02 10:38:58 +01:00
*
* @ param string $post_status The post status .
* @ param WP_Post $post The post object .
*/
2021-04-27 08:32:47 +02:00
return apply_filters ( 'get_post_status' , $post_status , $post );
2019-11-02 10:38:58 +01:00
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves all of the WordPress supported post statuses .
2019-11-02 10:38:58 +01:00
*
* Posts have a limited set of valid status values , this provides the
* post_status values and descriptions .
*
* @ since 2.5 . 0
*
2020-05-06 17:23:38 +02:00
* @ return string [] Array of post status labels keyed by their status .
2019-11-02 10:38:58 +01:00
*/
function get_post_statuses () {
$status = array (
'draft' => __ ( 'Draft' ),
'pending' => __ ( 'Pending Review' ),
'private' => __ ( 'Private' ),
'publish' => __ ( 'Published' ),
);
return $status ;
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves all of the WordPress support page statuses .
2019-11-02 10:38:58 +01:00
*
* Pages have a limited set of valid status values , this provides the
* post_status values and descriptions .
*
* @ since 2.5 . 0
*
2020-05-06 17:23:38 +02:00
* @ return string [] Array of page status labels keyed by their status .
2019-11-02 10:38:58 +01:00
*/
function get_page_statuses () {
$status = array (
'draft' => __ ( 'Draft' ),
'private' => __ ( 'Private' ),
'publish' => __ ( 'Published' ),
);
return $status ;
}
/**
2022-12-15 17:47:31 +01:00
* Returns statuses for privacy requests .
2019-11-02 10:38:58 +01:00
*
* @ since 4.9 . 6
* @ access private
*
* @ return array
*/
function _wp_privacy_statuses () {
return array (
2020-09-15 14:29:22 +02:00
'request-pending' => _x ( 'Pending' , 'request status' ), // Pending confirmation from user.
'request-confirmed' => _x ( 'Confirmed' , 'request status' ), // User has confirmed the action.
'request-failed' => _x ( 'Failed' , 'request status' ), // User failed to confirm the action.
'request-completed' => _x ( 'Completed' , 'request status' ), // Admin has handled the request.
2019-11-02 10:38:58 +01:00
);
}
/**
2022-12-15 17:47:31 +01:00
* Registers a post status . Do not use before init .
2019-11-02 10:38:58 +01:00
*
* A simple function for creating or modifying a post status based on the
* parameters given . The function will accept an array ( second optional
* parameter ), along with a string for the post status name .
*
* Arguments prefixed with an _underscore shouldn ' t be used by plugins and themes .
*
* @ since 3.0 . 0
2020-09-15 14:29:22 +02:00
*
2022-04-02 10:26:41 +02:00
* @ global stdClass [] $wp_post_statuses Inserts new post status object into the list
2019-11-02 10:38:58 +01:00
*
2020-09-15 14:29:22 +02:00
* @ param string $post_status Name of the post status .
2019-11-02 10:38:58 +01:00
* @ param array | string $args {
* Optional . Array or string of post status arguments .
*
* @ type bool | string $label A descriptive name for the post status marked
* for translation . Defaults to value of $post_status .
2022-12-15 17:47:31 +01:00
* @ type array | false $label_count Nooped plural text from _n_noop () to provide the singular
* and plural forms of the label for counts . Default false
* which means the `$label` argument will be used for both
* the singular and plural forms of this label .
2019-11-02 10:38:58 +01:00
* @ type bool $exclude_from_search Whether to exclude posts with this post status
* from search results . Default is value of $internal .
* @ type bool $_builtin Whether the status is built - in . Core - use only .
* Default false .
* @ type bool $public Whether posts of this status should be shown
* in the front end of the site . Default false .
* @ type bool $internal Whether the status is for internal use only .
* Default false .
* @ type bool $protected Whether posts with this status should be protected .
* Default false .
* @ type bool $private Whether posts with this status should be private .
* Default false .
* @ type bool $publicly_queryable Whether posts with this status should be publicly -
* queryable . Default is value of $public .
* @ type bool $show_in_admin_all_list Whether to include posts in the edit listing for
2020-05-06 17:23:38 +02:00
* their post type . Default is the opposite value
* of $internal .
2019-11-02 10:38:58 +01:00
* @ type bool $show_in_admin_status_list Show in the list of statuses with post counts at
* the top of the edit listings ,
* e . g . All ( 12 ) | Published ( 9 ) | My Custom Status ( 2 )
2020-05-06 17:23:38 +02:00
* Default is the opposite value of $internal .
2019-11-15 22:59:44 +01:00
* @ type bool $date_floating Whether the post has a floating creation date .
* Default to false .
2019-11-02 10:38:58 +01:00
* }
* @ return object
*/
function register_post_status ( $post_status , $args = array () ) {
global $wp_post_statuses ;
if ( ! is_array ( $wp_post_statuses ) ) {
$wp_post_statuses = array ();
}
// Args prefixed with an underscore are reserved for internal use.
$defaults = array (
'label' => false ,
'label_count' => false ,
'exclude_from_search' => null ,
'_builtin' => false ,
'public' => null ,
'internal' => null ,
'protected' => null ,
'private' => null ,
'publicly_queryable' => null ,
'show_in_admin_status_list' => null ,
'show_in_admin_all_list' => null ,
2019-11-15 22:59:44 +01:00
'date_floating' => null ,
2019-11-02 10:38:58 +01:00
);
$args = wp_parse_args ( $args , $defaults );
$args = ( object ) $args ;
$post_status = sanitize_key ( $post_status );
$args -> name = $post_status ;
// Set various defaults.
if ( null === $args -> public && null === $args -> internal && null === $args -> protected && null === $args -> private ) {
$args -> internal = true ;
}
if ( null === $args -> public ) {
$args -> public = false ;
}
if ( null === $args -> private ) {
$args -> private = false ;
}
if ( null === $args -> protected ) {
$args -> protected = false ;
}
if ( null === $args -> internal ) {
$args -> internal = false ;
}
if ( null === $args -> publicly_queryable ) {
$args -> publicly_queryable = $args -> public ;
}
if ( null === $args -> exclude_from_search ) {
$args -> exclude_from_search = $args -> internal ;
}
if ( null === $args -> show_in_admin_all_list ) {
$args -> show_in_admin_all_list = ! $args -> internal ;
}
if ( null === $args -> show_in_admin_status_list ) {
$args -> show_in_admin_status_list = ! $args -> internal ;
}
2019-11-15 22:59:44 +01:00
if ( null === $args -> date_floating ) {
$args -> date_floating = false ;
}
2019-11-02 10:38:58 +01:00
if ( false === $args -> label ) {
$args -> label = $post_status ;
}
if ( false === $args -> label_count ) {
// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralSingle,WordPress.WP.I18n.NonSingularStringLiteralPlural
$args -> label_count = _n_noop ( $args -> label , $args -> label );
}
$wp_post_statuses [ $post_status ] = $args ;
return $args ;
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves a post status object by name .
2019-11-02 10:38:58 +01:00
*
* @ since 3.0 . 0
*
2022-04-02 10:26:41 +02:00
* @ global stdClass [] $wp_post_statuses List of post statuses .
2019-11-02 10:38:58 +01:00
*
* @ see register_post_status ()
*
* @ param string $post_status The name of a registered post status .
2022-04-02 10:26:41 +02:00
* @ return stdClass | null A post status object .
2019-11-02 10:38:58 +01:00
*/
function get_post_status_object ( $post_status ) {
global $wp_post_statuses ;
if ( empty ( $wp_post_statuses [ $post_status ] ) ) {
return null ;
}
return $wp_post_statuses [ $post_status ];
}
/**
2022-12-15 17:47:31 +01:00
* Gets a list of post statuses .
2019-11-02 10:38:58 +01:00
*
* @ since 3.0 . 0
*
2022-04-02 10:26:41 +02:00
* @ global stdClass [] $wp_post_statuses List of post statuses .
2019-11-02 10:38:58 +01:00
*
* @ see register_post_status ()
*
* @ param array | string $args Optional . Array or string of post status arguments to compare against
* properties of the global `$wp_post_statuses objects` . Default empty array .
* @ param string $output Optional . The type of output to return , either 'names' or 'objects' . Default 'names' .
* @ 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 .
* Default 'and' .
2022-04-02 10:26:41 +02:00
* @ return string [] | stdClass [] A list of post status names or objects .
2019-11-02 10:38:58 +01:00
*/
function get_post_stati ( $args = array (), $output = 'names' , $operator = 'and' ) {
global $wp_post_statuses ;
2020-09-15 14:29:22 +02:00
$field = ( 'names' === $output ) ? 'name' : false ;
2019-11-02 10:38:58 +01:00
return wp_filter_object_list ( $wp_post_statuses , $args , $operator , $field );
}
/**
2022-12-15 17:47:31 +01:00
* Determines whether the post type is hierarchical .
2019-11-02 10:38:58 +01:00
*
* A false return value might also mean that the post type does not exist .
*
* @ since 3.0 . 0
*
* @ see get_post_type_object ()
*
* @ param string $post_type Post type name
* @ return bool Whether post type is hierarchical .
*/
function is_post_type_hierarchical ( $post_type ) {
if ( ! post_type_exists ( $post_type ) ) {
return false ;
}
$post_type = get_post_type_object ( $post_type );
return $post_type -> hierarchical ;
}
/**
* Determines whether a post type is registered .
*
* 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 .
*
* @ since 3.0 . 0
*
* @ see get_post_type_object ()
*
* @ param string $post_type Post type name .
* @ return bool Whether post type is registered .
*/
function post_type_exists ( $post_type ) {
return ( bool ) get_post_type_object ( $post_type );
}
/**
* Retrieves the post type of the current post or of a given post .
*
* @ since 2.1 . 0
*
* @ param int | WP_Post | null $post Optional . Post ID or post object . Default is global $post .
* @ return string | false Post type on success , false on failure .
*/
function get_post_type ( $post = null ) {
2019-11-15 22:59:44 +01:00
$post = get_post ( $post );
if ( $post ) {
2019-11-02 10:38:58 +01:00
return $post -> post_type ;
}
return false ;
}
/**
* Retrieves a post type object by name .
*
* @ since 3.0 . 0
* @ since 4.6 . 0 Object returned is now an instance of `WP_Post_Type` .
*
* @ global array $wp_post_types List of post types .
*
* @ see register_post_type ()
*
* @ param string $post_type The name of a registered post type .
* @ return WP_Post_Type | null WP_Post_Type object if it exists , null otherwise .
*/
function get_post_type_object ( $post_type ) {
global $wp_post_types ;
if ( ! is_scalar ( $post_type ) || empty ( $wp_post_types [ $post_type ] ) ) {
return null ;
}
return $wp_post_types [ $post_type ];
}
/**
2022-12-15 17:47:31 +01:00
* Gets a list of all registered post type objects .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
*
* @ global array $wp_post_types List of post types .
*
* @ see register_post_type () for accepted arguments .
*
* @ param array | string $args Optional . An array of key => value arguments to match against
* the post type objects . Default empty array .
* @ param string $output Optional . The type of output to return . Accepts post type 'names'
* or 'objects' . Default 'names' .
* @ 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 string [] | WP_Post_Type [] An array of post type names or objects .
*/
function get_post_types ( $args = array (), $output = 'names' , $operator = 'and' ) {
global $wp_post_types ;
2020-09-15 14:29:22 +02:00
$field = ( 'names' === $output ) ? 'name' : false ;
2019-11-02 10:38:58 +01:00
return wp_filter_object_list ( $wp_post_types , $args , $operator , $field );
}
/**
* Registers a post type .
*
* Note : Post type registrations should not be hooked before the
* { @ see 'init' } action . Also , any taxonomy connections should be
* registered via the `$taxonomies` argument to ensure consistency
* when hooks such as { @ see 'parse_query' } or { @ see 'pre_get_posts' }
* are used .
*
* Post types can support any number of built - in core features such
* as meta boxes , custom fields , post thumbnails , post statuses ,
* comments , and more . See the `$supports` argument for a complete
* list of supported features .
*
* @ since 2.9 . 0
* @ since 3.0 . 0 The `show_ui` argument is now enforced on the new post screen .
* @ since 4.4 . 0 The `show_ui` argument is now enforced on the post type listing
* screen and post editing screen .
* @ since 4.6 . 0 Post type object returned is now an instance of `WP_Post_Type` .
* @ since 4.7 . 0 Introduced `show_in_rest` , `rest_base` and `rest_controller_class`
* arguments to register the post type in REST API .
2020-12-10 14:06:04 +01:00
* @ since 5.0 . 0 The `template` and `template_lock` arguments were added .
2019-11-15 22:59:44 +01:00
* @ since 5.3 . 0 The `supports` argument will now accept an array of arguments for a feature .
2022-04-02 10:26:41 +02:00
* @ since 5.9 . 0 The `rest_namespace` argument was added .
2020-12-10 14:06:04 +01:00
*
2019-11-02 10:38:58 +01:00
* @ global array $wp_post_types List of post types .
*
2023-04-26 17:39:43 +02:00
* @ param string $post_type Post type key . Must not exceed 20 characters and may only contain
* lowercase alphanumeric characters , dashes , and underscores . See sanitize_key () .
2019-11-02 10:38:58 +01:00
* @ param array | string $args {
* Array or string of arguments for registering a post type .
*
2020-12-10 14:06:04 +01:00
* @ type string $label Name of the post type shown in the menu . Usually plural .
* Default is value of $labels [ 'name' ] .
2021-04-27 08:32:47 +02:00
* @ type string [] $labels An array of labels for this post type . If not set , post
2020-12-10 14:06:04 +01:00
* labels are inherited for non - hierarchical types and page
* labels for hierarchical ones . See get_post_type_labels () for a full
* list of supported labels .
* @ type string $description A short descriptive summary of what the post type is .
* Default empty .
* @ type bool $public Whether a post type is intended for use publicly either via
* the admin interface or by front - end users . While the default
* settings of $exclude_from_search , $publicly_queryable , $show_ui ,
2022-04-02 10:26:41 +02:00
* and $show_in_nav_menus are inherited from $public , each does not
2020-12-10 14:06:04 +01:00
* rely on this relationship and controls a very specific intention .
* Default false .
* @ type bool $hierarchical Whether the post type is hierarchical ( e . g . page ) . Default false .
* @ type bool $exclude_from_search Whether to exclude posts with this post type from front end search
* results . Default is the opposite value of $public .
* @ type bool $publicly_queryable Whether queries can be performed on the front end for the post type
* as part of parse_request () . Endpoints would include :
* * ? post_type = { post_type_key }
* * ? { post_type_key } = { single_post_slug }
* * ? { post_type_query_var } = { single_post_slug }
* If not set , the default is inherited from $public .
* @ type bool $show_ui Whether to generate and allow a UI for managing this post type in the
* admin . Default is value of $public .
* @ type bool | string $show_in_menu Where to show the post type in the admin menu . To work , $show_ui
* must be true . If true , the post type is shown in its own top level
* menu . If false , no menu is shown . If a string of an existing top
2022-04-02 10:26:41 +02:00
* level menu ( 'tools.php' or 'edit.php?post_type=page' , for example ), the
* post type will be placed as a sub - menu of that .
2020-12-10 14:06:04 +01:00
* Default is value of $show_ui .
* @ type bool $show_in_nav_menus Makes this post type available for selection in navigation menus .
* Default is value of $public .
* @ type bool $show_in_admin_bar Makes this post type available via the admin bar . Default is value
* of $show_in_menu .
* @ type bool $show_in_rest Whether to include the post type in the REST API . Set this to true
* for the post type to be available in the block editor .
2022-04-02 10:26:41 +02:00
* @ type string $rest_base To change the base URL of REST API route . Default is $post_type .
* @ type string $rest_namespace To change the namespace URL of REST API route . Default is wp / v2 .
* @ type string $rest_controller_class REST API controller class name . Default is 'WP_REST_Posts_Controller' .
2020-12-10 14:06:04 +01:00
* @ type int $menu_position The position in the menu order the post type should appear . To work ,
* $show_in_menu must be true . Default null ( at the bottom ) .
2022-04-02 10:26:41 +02:00
* @ type string $menu_icon The URL to the icon to be used for this menu . Pass a base64 - encoded
2020-12-10 14:06:04 +01:00
* SVG using a data URI , which will be colored to match the color scheme
* -- this should begin with 'data:image/svg+xml;base64,' . Pass the name
* of a Dashicons helper class to use a font icon , e . g .
* 'dashicons-chart-pie' . Pass 'none' to leave div . wp - menu - image empty
* so an icon can be added via CSS . Defaults to use the posts icon .
2022-04-02 10:26:41 +02:00
* @ type string | array $capability_type The string to use to build the read , edit , and delete capabilities .
2020-12-10 14:06:04 +01:00
* May be passed as an array to allow for alternative plurals when using
* this argument as a base to construct the capabilities , e . g .
* array ( 'story' , 'stories' ) . Default 'post' .
2021-04-27 08:32:47 +02:00
* @ type string [] $capabilities Array of capabilities for this post type . $capability_type is used
2020-12-10 14:06:04 +01:00
* as a base to construct capabilities by default .
* See get_post_type_capabilities () .
* @ type bool $map_meta_cap Whether to use the internal default meta capability handling .
* Default false .
* @ type array $supports Core feature ( s ) the post type supports . Serves as an alias for calling
* add_post_type_support () directly . Core 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 . A feature can also be
* specified as an array of arguments to provide additional information
* about supporting that feature .
* Example : `array( 'my_feature', array( 'field' => 'value' ) )` .
* Default is an array containing 'title' and 'editor' .
* @ type callable $register_meta_box_cb Provide a callback function that sets up the meta boxes for the
* edit form . Do remove_meta_box () and add_meta_box () calls in the
* callback . Default null .
2021-04-27 08:32:47 +02:00
* @ type string [] $taxonomies An array of taxonomy identifiers that will be registered for the
2020-12-10 14:06:04 +01:00
* post type . Taxonomies can be registered later with register_taxonomy ()
* or register_taxonomy_for_object_type () .
* Default empty array .
* @ type bool | string $has_archive Whether there should be post type archives , or if a string , the
* archive slug to use . Will generate the proper rewrite rules if
* $rewrite is enabled . Default false .
* @ type bool | array $rewrite {
2019-11-02 10:38:58 +01:00
* Triggers the handling of rewrites for this post type . To prevent rewrite , set to false .
* Defaults to true , using $post_type as slug . To specify rewrite rules , an array can be
* passed with any of these keys :
*
* @ type string $slug Customize the permastruct slug . Defaults to $post_type key .
* @ type bool $with_front Whether the permastruct should be prepended with WP_Rewrite :: $front .
* Default true .
* @ type bool $feeds Whether the feed permastruct should be built for this post type .
* Default is value of $has_archive .
* @ type bool $pages Whether the permastruct should provide for pagination . Default true .
2021-04-27 08:32:47 +02:00
* @ type int $ep_mask Endpoint mask to assign . If not specified and permalink_epmask is set ,
2019-11-02 10:38:58 +01:00
* inherits from $permalink_epmask . If not specified and permalink_epmask
* is not set , defaults to EP_PERMALINK .
* }
2020-12-10 14:06:04 +01:00
* @ type string | bool $query_var Sets the query_var key for this post type . Defaults to $post_type
* key . If false , a post type cannot be loaded at
* ? { query_var } = { post_slug } . If specified as a string , the query
* ? { query_var_string } = { post_slug } will be valid .
* @ type bool $can_export Whether to allow this post type to be exported . Default true .
* @ type bool $delete_with_user Whether to delete posts of this type when deleting a user .
2021-07-23 11:58:50 +02:00
* * If true , posts of this type belonging to the user will be moved
2020-12-10 14:06:04 +01:00
* to Trash when the user is deleted .
2021-07-23 11:58:50 +02:00
* * If false , posts of this type belonging to the user will * not *
2020-12-10 14:06:04 +01:00
* be trashed or deleted .
2021-07-23 11:58:50 +02:00
* * If not set ( the default ), posts are trashed if post type supports
2020-12-10 14:06:04 +01:00
* the 'author' feature . Otherwise posts are not trashed or deleted .
* Default null .
* @ type array $template Array of blocks to use as the default initial state for an editor
* session . Each item should be an array containing block name and
* optional attributes . Default empty array .
* @ type string | false $template_lock Whether the block template should be locked if $template is set .
2021-07-23 11:58:50 +02:00
* * If set to 'all' , the user is unable to insert new blocks ,
2020-12-10 14:06:04 +01:00
* move existing blocks and delete blocks .
2021-07-23 11:58:50 +02:00
* * If set to 'insert' , the user is able to move existing blocks
2020-12-10 14:06:04 +01:00
* but is unable to insert new blocks and delete blocks .
* Default false .
* @ type bool $_builtin FOR INTERNAL USE ONLY ! True if this post type is a native or
* " built-in " post_type . Default false .
* @ type string $_edit_link FOR INTERNAL USE ONLY ! URL segment to use for edit link of
* this post type . Default 'post.php?post=%d' .
2019-11-02 10:38:58 +01:00
* }
2020-05-06 17:23:38 +02:00
* @ return WP_Post_Type | WP_Error The registered post type object on success ,
* WP_Error object on failure .
2019-11-02 10:38:58 +01:00
*/
function register_post_type ( $post_type , $args = array () ) {
global $wp_post_types ;
if ( ! is_array ( $wp_post_types ) ) {
$wp_post_types = array ();
}
2020-05-06 17:23:38 +02:00
// Sanitize post type name.
2019-11-02 10:38:58 +01:00
$post_type = sanitize_key ( $post_type );
if ( empty ( $post_type ) || strlen ( $post_type ) > 20 ) {
_doing_it_wrong ( __FUNCTION__ , __ ( 'Post type names must be between 1 and 20 characters in length.' ), '4.2.0' );
return new WP_Error ( 'post_type_length_invalid' , __ ( 'Post type names must be between 1 and 20 characters in length.' ) );
}
$post_type_object = new WP_Post_Type ( $post_type , $args );
$post_type_object -> add_supports ();
$post_type_object -> add_rewrite_rules ();
$post_type_object -> register_meta_boxes ();
$wp_post_types [ $post_type ] = $post_type_object ;
$post_type_object -> add_hooks ();
$post_type_object -> register_taxonomies ();
/**
* Fires after a post type is registered .
*
* @ since 3.3 . 0
* @ since 4.6 . 0 Converted the `$post_type` parameter to accept a `WP_Post_Type` object .
*
* @ param string $post_type Post type .
* @ param WP_Post_Type $post_type_object Arguments used to register the post type .
*/
do_action ( 'registered_post_type' , $post_type , $post_type_object );
2022-06-16 14:03:35 +02:00
/**
* Fires after a specific post type is registered .
*
* The dynamic portion of the filter name , `$post_type` , refers to the post type key .
*
* Possible hook names include :
*
* - `registered_post_type_post`
* - `registered_post_type_page`
*
* @ since 6.0 . 0
*
* @ param string $post_type Post type .
* @ param WP_Post_Type $post_type_object Arguments used to register the post type .
*/
do_action ( " registered_post_type_ { $post_type } " , $post_type , $post_type_object );
2019-11-02 10:38:58 +01:00
return $post_type_object ;
}
/**
* Unregisters a post type .
*
2022-06-16 14:03:35 +02:00
* Cannot be used to unregister built - in post types .
2019-11-02 10:38:58 +01:00
*
* @ since 4.5 . 0
*
* @ global array $wp_post_types List of post types .
*
* @ param string $post_type Post type to unregister .
2021-04-27 08:32:47 +02:00
* @ return true | WP_Error True on success , WP_Error on failure or if the post type doesn ' t exist .
2019-11-02 10:38:58 +01:00
*/
function unregister_post_type ( $post_type ) {
global $wp_post_types ;
if ( ! post_type_exists ( $post_type ) ) {
return new WP_Error ( 'invalid_post_type' , __ ( 'Invalid post type.' ) );
}
$post_type_object = get_post_type_object ( $post_type );
// Do not allow unregistering internal post types.
if ( $post_type_object -> _builtin ) {
return new WP_Error ( 'invalid_post_type' , __ ( 'Unregistering a built-in post type is not allowed' ) );
}
$post_type_object -> remove_supports ();
$post_type_object -> remove_rewrite_rules ();
$post_type_object -> unregister_meta_boxes ();
$post_type_object -> remove_hooks ();
$post_type_object -> unregister_taxonomies ();
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 ;
}
/**
2022-12-15 17:47:31 +01:00
* Builds an object with all post type capabilities out of a post type object
2019-11-02 10:38:58 +01:00
*
* 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 .
*
2020-05-06 17:23:38 +02:00
* By default , eight keys are accepted as part of the capabilities array :
2019-11-02 10:38:58 +01:00
*
* - 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 .
2020-05-06 17:23:38 +02:00
* - delete_posts - Controls whether objects of this post type can be deleted .
2019-11-02 10:38:58 +01:00
* - publish_posts - Controls publishing objects of this post type .
* - read_private_posts - Controls whether private objects can be read .
*
2020-05-06 17:23:38 +02:00
* These five primitive capabilities are checked in core in various locations .
* There are also six other primitive capabilities which are not referenced
2019-11-02 10:38:58 +01:00
* 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_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
2020-05-06 17:23:38 +02:00
* @ since 5.4 . 0 'delete_posts' is included in default capabilities .
2019-11-02 10:38:58 +01:00
*
* @ 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 (
2020-05-06 17:23:38 +02:00
// Meta capabilities.
2019-11-02 10:38:58 +01:00
'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 ,
2020-05-06 17:23:38 +02:00
'delete_posts' => 'delete_' . $plural_base ,
2019-11-02 10:38:58 +01:00
'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_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 ;
}
/**
2022-12-15 17:47:31 +01:00
* Stores or returns a list of post type meta caps for map_meta_cap () .
2019-11-02 10:38:58 +01:00
*
* @ since 3.1 . 0
* @ access private
*
* @ global array $post_type_meta_caps Used to store meta capabilities .
*
2020-05-06 17:23:38 +02:00
* @ param string [] $capabilities Post type meta capabilities .
2019-11-02 10:38:58 +01:00
*/
function _post_type_meta_capabilities ( $capabilities = null ) {
global $post_type_meta_caps ;
foreach ( $capabilities as $core => $custom ) {
2020-09-15 14:29:22 +02:00
if ( in_array ( $core , array ( 'read_post' , 'delete_post' , 'edit_post' ), true ) ) {
2019-11-02 10:38:58 +01:00
$post_type_meta_caps [ $custom ] = $core ;
}
}
}
/**
* Builds 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 .
2019-11-15 22:59:44 +01:00
* When internationalizing this string , please use a { @ link https :// developer . wordpress . org / plugins / internationalization / how - to - internationalize - your - plugin / #disambiguation-by-context gettext context}
2019-11-02 10:38:58 +01:00
* matching your post type . Example : `_x( 'Add New', 'product', 'textdomain' );` .
* - `add_new_item` - Label for adding a new singular item . Default is 'Add New Post' / 'Add New Page' .
* - `edit_item` - Label for editing a singular item . Default is 'Edit Post' / 'Edit Page' .
* - `new_item` - Label for the new item page title . Default is 'New Post' / 'New Page' .
* - `view_item` - Label for viewing a singular item . Default is 'View Post' / 'View Page' .
* - `view_items` - Label for viewing post type archives . Default is 'View Posts' / 'View Pages' .
* - `search_items` - Label for searching plural items . Default is 'Search Posts' / 'Search Pages' .
* - `not_found` - Label used when no items are found . Default is 'No posts found' / 'No pages found' .
2020-05-06 17:23:38 +02:00
* - `not_found_in_trash` - Label used when no items are in the Trash . Default is 'No posts found in Trash' /
2019-11-02 10:38:58 +01:00
* 'No pages found in Trash' .
* - `parent_item_colon` - Label used to prefix parents of hierarchical items . Not used on non - hierarchical
* post types . Default is 'Parent Page:' .
* - `all_items` - Label to signify all items in a submenu link . Default is 'All Posts' / 'All Pages' .
* - `archives` - Label for archives in nav menus . Default is 'Post Archives' / 'Page Archives' .
* - `attributes` - Label for the attributes meta box . Default is 'Post Attributes' / 'Page Attributes' .
* - `insert_into_item` - Label for the media frame button . Default is 'Insert into post' / 'Insert into page' .
* - `uploaded_to_this_item` - Label for the media frame filter . Default is 'Uploaded to this post' /
* 'Uploaded to this page' .
2020-05-06 17:23:38 +02:00
* - `featured_image` - Label for the featured image meta box title . Default is 'Featured image' .
2019-11-02 10:38:58 +01:00
* - `set_featured_image` - Label for setting the featured image . Default is 'Set featured image' .
* - `remove_featured_image` - Label for removing the featured image . Default is 'Remove featured image' .
* - `use_featured_image` - Label in the media frame for using a featured image . Default is 'Use as featured image' .
* - `menu_name` - Label for the menu name . Default is the same as `name` .
* - `filter_items_list` - Label for the table views hidden heading . Default is 'Filter posts list' /
* 'Filter pages list' .
2021-04-27 08:32:47 +02:00
* - `filter_by_date` - Label for the date filter in list tables . Default is 'Filter by date' .
2019-11-02 10:38:58 +01:00
* - `items_list_navigation` - Label for the table pagination hidden heading . Default is 'Posts list navigation' /
* 'Pages list navigation' .
* - `items_list` - Label for the table hidden heading . Default is 'Posts list' / 'Pages list' .
* - `item_published` - Label used when an item is published . Default is 'Post published.' / 'Page published.'
* - `item_published_privately` - Label used when an item is published with private visibility .
* Default is 'Post published privately.' / 'Page published privately.'
* - `item_reverted_to_draft` - Label used when an item is switched to a draft .
* Default is 'Post reverted to draft.' / 'Page reverted to draft.'
* - `item_scheduled` - Label used when an item is scheduled for publishing . Default is 'Post scheduled.' /
* 'Page scheduled.'
* - `item_updated` - Label used when an item is updated . Default is 'Post updated.' / 'Page updated.'
2021-07-23 11:58:50 +02:00
* - `item_link` - Title for a navigation link block variation . Default is 'Post Link' / 'Page Link' .
* - `item_link_description` - Description for a navigation link block variation . Default is 'A link to a post.' /
* 'A link to a page.'
2019-11-02 10:38:58 +01:00
*
* Above , the first default value is for non - hierarchical post types ( like posts )
* and the second one is for hierarchical post types ( like pages ) .
*
* Note : To set labels used in post type admin notices , see the { @ see 'post_updated_messages' } filter .
*
* @ 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 `archives` , `insert_into_item` , `uploaded_to_this_item` , `filter_items_list` ,
* `items_list_navigation` , and `items_list` labels .
* @ since 4.6 . 0 Converted the `$post_type` parameter to accept a `WP_Post_Type` object .
* @ since 4.7 . 0 Added the `view_items` and `attributes` labels .
* @ since 5.0 . 0 Added the `item_published` , `item_published_privately` , `item_reverted_to_draft` ,
* `item_scheduled` , and `item_updated` labels .
2021-04-27 08:32:47 +02:00
* @ since 5.7 . 0 Added the `filter_by_date` label .
2021-07-23 11:58:50 +02:00
* @ since 5.8 . 0 Added the `item_link` and `item_link_description` labels .
2019-11-02 10:38:58 +01:00
*
* @ access private
*
* @ param object | WP_Post_Type $post_type_object Post type object .
* @ return object Object with all the labels as member variables .
*/
function get_post_type_labels ( $post_type_object ) {
2022-06-16 14:03:35 +02:00
$nohier_vs_hier_defaults = WP_Post_Type :: get_default_labels ();
2021-07-23 11:58:50 +02:00
2019-11-02 10:38:58 +01:00
$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 ;
/**
* Filters the labels of a specific post type .
*
* The dynamic portion of the hook name , `$post_type` , refers to
* the post type slug .
*
2021-07-23 11:58:50 +02:00
* Possible hook names include :
*
* - `post_type_labels_post`
* - `post_type_labels_page`
* - `post_type_labels_attachment`
*
2019-11-02 10:38:58 +01:00
* @ 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 ;
}
/**
2022-12-15 17:47:31 +01:00
* Builds an object with custom - something object ( post type , taxonomy ) labels
2019-11-02 10:38:58 +01:00
* out of a custom - something object
*
* @ since 3.0 . 0
* @ access private
*
2023-04-26 17:39:43 +02:00
* @ param object $data_object A custom - something object .
2019-11-02 10:38:58 +01:00
* @ param array $nohier_vs_hier_defaults Hierarchical vs non - hierarchical default labels .
* @ return object Object containing labels for the given custom - something object .
*/
2023-04-26 17:39:43 +02:00
function _get_custom_object_labels ( $data_object , $nohier_vs_hier_defaults ) {
$data_object -> labels = ( array ) $data_object -> labels ;
2019-11-02 10:38:58 +01:00
2023-04-26 17:39:43 +02:00
if ( isset ( $data_object -> label ) && empty ( $data_object -> labels [ 'name' ] ) ) {
$data_object -> labels [ 'name' ] = $data_object -> label ;
2019-11-02 10:38:58 +01:00
}
2023-04-26 17:39:43 +02:00
if ( ! isset ( $data_object -> labels [ 'singular_name' ] ) && isset ( $data_object -> labels [ 'name' ] ) ) {
$data_object -> labels [ 'singular_name' ] = $data_object -> labels [ 'name' ];
2019-11-02 10:38:58 +01:00
}
2023-04-26 17:39:43 +02:00
if ( ! isset ( $data_object -> labels [ 'name_admin_bar' ] ) ) {
$data_object -> labels [ 'name_admin_bar' ] =
isset ( $data_object -> labels [ 'singular_name' ] )
? $data_object -> labels [ 'singular_name' ]
: $data_object -> name ;
2019-11-02 10:38:58 +01:00
}
2023-04-26 17:39:43 +02:00
if ( ! isset ( $data_object -> labels [ 'menu_name' ] ) && isset ( $data_object -> labels [ 'name' ] ) ) {
$data_object -> labels [ 'menu_name' ] = $data_object -> labels [ 'name' ];
2019-11-02 10:38:58 +01:00
}
2023-04-26 17:39:43 +02:00
if ( ! isset ( $data_object -> labels [ 'all_items' ] ) && isset ( $data_object -> labels [ 'menu_name' ] ) ) {
$data_object -> labels [ 'all_items' ] = $data_object -> labels [ 'menu_name' ];
2019-11-02 10:38:58 +01:00
}
2023-04-26 17:39:43 +02:00
if ( ! isset ( $data_object -> labels [ 'archives' ] ) && isset ( $data_object -> labels [ 'all_items' ] ) ) {
$data_object -> labels [ 'archives' ] = $data_object -> labels [ 'all_items' ];
2019-11-02 10:38:58 +01:00
}
$defaults = array ();
foreach ( $nohier_vs_hier_defaults as $key => $value ) {
2023-04-26 17:39:43 +02:00
$defaults [ $key ] = $data_object -> hierarchical ? $value [ 1 ] : $value [ 0 ];
2019-11-02 10:38:58 +01:00
}
2023-04-26 17:39:43 +02:00
$labels = array_merge ( $defaults , $data_object -> labels );
$data_object -> labels = ( object ) $data_object -> labels ;
2019-11-02 10:38:58 +01:00
return ( object ) $labels ;
}
/**
2022-12-15 17:47:31 +01:00
* Adds submenus for post types .
2019-11-02 10:38:58 +01:00
*
* @ 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.
2020-05-06 17:23:38 +02:00
if ( ! $ptype_obj -> show_in_menu || true === $ptype_obj -> show_in_menu ) {
2019-11-02 10:38:58 +01:00
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 " );
}
}
/**
2019-11-15 22:59:44 +01:00
* Registers support of certain features for a post type .
2019-11-02 10:38:58 +01:00
*
* 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 .
*
2019-11-15 22:59:44 +01:00
* A third , optional parameter can also be passed along with a feature to provide
* additional information about supporting that feature .
*
* Example usage :
*
* add_post_type_support ( 'my_post_type' , 'comments' );
* add_post_type_support ( 'my_post_type' , array (
* 'author' , 'excerpt' ,
* ) );
* add_post_type_support ( 'my_post_type' , 'my_feature' , array (
* 'field' => 'value' ,
* ) );
*
2019-11-02 10:38:58 +01:00
* @ since 3.0 . 0
2019-11-15 22:59:44 +01:00
* @ since 5.3 . 0 Formalized the existing and already documented `...$args` parameter
* by adding it to the function signature .
2019-11-02 10:38:58 +01:00
*
* @ 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 .
2019-11-15 22:59:44 +01:00
* @ param mixed ... $args Optional extra arguments to pass along with certain features .
2019-11-02 10:38:58 +01:00
*/
2019-11-15 22:59:44 +01:00
function add_post_type_support ( $post_type , $feature , ... $args ) {
2019-11-02 10:38:58 +01:00
global $_wp_post_type_features ;
$features = ( array ) $feature ;
foreach ( $features as $feature ) {
2019-11-15 22:59:44 +01:00
if ( $args ) {
$_wp_post_type_features [ $post_type ][ $feature ] = $args ;
2019-11-02 10:38:58 +01:00
} else {
2019-11-15 22:59:44 +01:00
$_wp_post_type_features [ $post_type ][ $feature ] = true ;
2019-11-02 10:38:58 +01:00
}
}
}
/**
2022-12-15 17:47:31 +01:00
* Removes support for a feature from a post type .
2019-11-02 10:38:58 +01:00
*
* @ 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 ] );
}
/**
2022-12-15 17:47:31 +01:00
* Gets all the post type features
2019-11-02 10:38:58 +01:00
*
* @ 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 ();
}
/**
2022-12-15 17:47:31 +01:00
* Checks a post type ' s support for a given feature .
2019-11-02 10:38:58 +01:00
*
* @ 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' .
2020-05-06 17:23:38 +02:00
* @ return string [] A list of post type names .
2019-11-02 10:38:58 +01:00
*/
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 ) );
}
/**
2022-12-15 17:47:31 +01:00
* Updates the post type for the post ID .
2019-11-02 10:38:58 +01:00
*
* 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 .
* @ since 4.6 . 0 Converted the `$post_type` parameter to accept a `WP_Post_Type` object .
2022-04-02 10:26:41 +02:00
* @ since 5.9 . 0 Added `is_post_type_viewable` hook to filter the result .
2019-11-02 10:38:58 +01:00
*
* @ 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 );
2022-12-15 17:47:31 +01:00
2019-11-02 10:38:58 +01:00
if ( ! $post_type ) {
return false ;
}
}
2021-04-27 08:32:47 +02:00
if ( ! is_object ( $post_type ) ) {
return false ;
}
2022-04-02 10:26:41 +02:00
$is_viewable = $post_type -> publicly_queryable || ( $post_type -> _builtin && $post_type -> public );
/**
* Filters whether a post type is considered " viewable " .
*
* The returned filtered value must be a boolean type to ensure
* `is_post_type_viewable()` only returns a boolean . This strictness
* is by design to maintain backwards - compatibility and guard against
* potential type errors in PHP 8.1 +. Non - boolean values ( even falsey
* and truthy values ) will result in the function returning false .
*
* @ since 5.9 . 0
*
* @ param bool $is_viewable Whether the post type is " viewable " ( strict type ) .
* @ param WP_Post_Type $post_type Post type object .
*/
return true === apply_filters ( 'is_post_type_viewable' , $is_viewable , $post_type );
2019-11-02 10:38:58 +01:00
}
2021-04-27 08:32:47 +02:00
/**
2022-12-15 17:47:31 +01:00
* Determines whether a post status is considered " viewable " .
2021-04-27 08:32:47 +02:00
*
2022-06-16 14:03:35 +02:00
* For built - in post statuses such as publish and private , the 'public' value will be evaluated .
2021-04-27 08:32:47 +02:00
* For all others , the 'publicly_queryable' value will be used .
*
* @ since 5.7 . 0
2022-04-02 10:26:41 +02:00
* @ since 5.9 . 0 Added `is_post_status_viewable` hook to filter the result .
2021-04-27 08:32:47 +02:00
*
* @ 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 );
2022-12-15 17:47:31 +01:00
2021-04-27 08:32:47 +02:00
if ( ! $post_status ) {
return false ;
}
}
if (
! is_object ( $post_status ) ||
$post_status -> internal ||
$post_status -> protected
) {
return false ;
}
2022-04-02 10:26:41 +02:00
$is_viewable = $post_status -> publicly_queryable || ( $post_status -> _builtin && $post_status -> public );
/**
* Filters whether a post status is considered " viewable " .
*
* The returned filtered value must be a boolean type to ensure
* `is_post_status_viewable()` only returns a boolean . This strictness
* is by design to maintain backwards - compatibility and guard against
* potential type errors in PHP 8.1 +. Non - boolean values ( even falsey
* and truthy values ) will result in the function returning false .
*
* @ since 5.9 . 0
*
* @ param bool $is_viewable Whether the post status is " viewable " ( strict type ) .
* @ param stdClass $post_status Post status object .
*/
return true === apply_filters ( 'is_post_status_viewable' , $is_viewable , $post_status );
2021-04-27 08:32:47 +02:00
}
/**
2022-12-15 17:47:31 +01:00
* Determines whether a post is publicly viewable .
2021-04-27 08:32:47 +02:00
*
* Posts are considered publicly viewable if both the post status and post type
* are viewable .
*
* @ since 5.7 . 0
*
* @ 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 );
if ( ! $post ) {
return false ;
}
$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 );
}
2019-11-02 10:38:58 +01:00
/**
* Retrieves an array of the latest posts , or posts matching the given criteria .
*
2021-04-27 08:32:47 +02:00
* 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` .
*
2019-11-02 10:38:58 +01:00
* The defaults are as follows :
*
* @ since 1.2 . 0
*
2021-04-27 08:32:47 +02:00
* @ see WP_Query
2019-11-02 10:38:58 +01:00
* @ see WP_Query :: parse_query ()
*
* @ param array $args {
2022-04-02 10:26:41 +02:00
* Optional . Arguments to retrieve posts . See WP_Query :: parse_query () for all available arguments .
2019-11-02 10:38:58 +01:00
*
2021-04-27 08:32:47 +02:00
* @ type int $numberposts Total number of posts to retrieve . Is an alias of `$posts_per_page`
2019-11-02 10:38:58 +01:00
* 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 ) .
2021-04-27 08:32:47 +02:00
* 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 .
2019-11-02 10:38:58 +01:00
* @ 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 ) {
$defaults = array (
'numberposts' => 5 ,
'category' => 0 ,
'orderby' => 'date' ,
'order' => 'DESC' ,
'include' => array (),
'exclude' => array (),
'meta_key' => '' ,
'meta_value' => '' ,
'post_type' => 'post' ,
'suppress_filters' => true ,
);
2019-11-15 22:59:44 +01:00
$parsed_args = wp_parse_args ( $args , $defaults );
if ( empty ( $parsed_args [ 'post_status' ] ) ) {
2020-09-15 14:29:22 +02:00
$parsed_args [ 'post_status' ] = ( 'attachment' === $parsed_args [ 'post_type' ] ) ? 'inherit' : 'publish' ;
2019-11-02 10:38:58 +01:00
}
2019-11-15 22:59:44 +01:00
if ( ! empty ( $parsed_args [ 'numberposts' ] ) && empty ( $parsed_args [ 'posts_per_page' ] ) ) {
$parsed_args [ 'posts_per_page' ] = $parsed_args [ 'numberposts' ];
2019-11-02 10:38:58 +01:00
}
2019-11-15 22:59:44 +01:00
if ( ! empty ( $parsed_args [ 'category' ] ) ) {
$parsed_args [ 'cat' ] = $parsed_args [ 'category' ];
2019-11-02 10:38:58 +01:00
}
2019-11-15 22:59:44 +01:00
if ( ! empty ( $parsed_args [ 'include' ] ) ) {
$incposts = wp_parse_id_list ( $parsed_args [ 'include' ] );
2020-05-06 17:23:38 +02:00
$parsed_args [ 'posts_per_page' ] = count ( $incposts ); // Only the number of posts included.
2019-11-15 22:59:44 +01:00
$parsed_args [ 'post__in' ] = $incposts ;
} elseif ( ! empty ( $parsed_args [ 'exclude' ] ) ) {
$parsed_args [ 'post__not_in' ] = wp_parse_id_list ( $parsed_args [ 'exclude' ] );
2019-11-02 10:38:58 +01:00
}
2019-11-15 22:59:44 +01:00
$parsed_args [ 'ignore_sticky_posts' ] = true ;
$parsed_args [ 'no_found_rows' ] = true ;
2019-11-02 10:38:58 +01:00
2023-04-26 17:39:43 +02:00
$get_posts = new WP_Query ();
2019-11-15 22:59:44 +01:00
return $get_posts -> query ( $parsed_args );
2019-11-02 10:38:58 +01:00
}
//
2020-05-06 17:23:38 +02:00
// Post meta functions.
2019-11-02 10:38:58 +01:00
//
/**
* Adds a meta field to the given 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.
$the_post = wp_is_post_revision ( $post_id );
if ( $the_post ) {
$post_id = $the_post ;
}
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 .
*
* @ since 1.5 . 0
*
* @ param int $post_id Post ID .
* @ param string $meta_key Metadata name .
2020-09-15 14:29:22 +02:00
* @ 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 .
2019-11-02 10:38:58 +01:00
* @ return bool True on success , false on failure .
*/
function delete_post_meta ( $post_id , $meta_key , $meta_value = '' ) {
2022-06-16 14:03:35 +02:00
// Make sure meta is deleted from the post, not from a revision.
2019-11-02 10:38:58 +01:00
$the_post = wp_is_post_revision ( $post_id );
if ( $the_post ) {
$post_id = $the_post ;
}
return delete_metadata ( 'post' , $post_id , $meta_key , $meta_value );
}
/**
* Retrieves a post meta field for the given post ID .
*
* @ since 1.5 . 0
*
* @ param int $post_id Post ID .
2020-09-15 14:29:22 +02:00
* @ 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 .
2021-07-23 11:58:50 +02:00
* This parameter has no effect if `$key` is not specified .
2020-09-15 14:29:22 +02:00
* Default false .
2021-07-23 11:58:50 +02:00
* @ return mixed An array of values if `$single` is false .
* The value of the meta field if `$single` is true .
* False for an invalid `$post_id` ( non - numeric , zero , or negative value ) .
* An empty string if a valid but non - existing post ID is passed .
2019-11-02 10:38:58 +01:00
*/
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
* same key and post ID .
*
* 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 () .
*
* @ 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 updating .
2020-09-15 14:29:22 +02:00
* 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 .
2019-11-02 10:38:58 +01:00
*/
function update_post_meta ( $post_id , $meta_key , $meta_value , $prev_value = '' ) {
2022-06-16 14:03:35 +02:00
// Make sure meta is updated for the post, not for a revision.
2019-11-02 10:38:58 +01:00
$the_post = wp_is_post_revision ( $post_id );
if ( $the_post ) {
$post_id = $the_post ;
}
return update_metadata ( 'post' , $post_id , $meta_key , $meta_value , $prev_value );
}
/**
* Deletes everything from post meta matching the given 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 );
}
/**
* Registers a meta key for posts .
*
* @ since 4.9 . 8
*
* @ 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 .
*
* @ since 4.9 . 8
*
* @ 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
* existing post types .
* @ 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 );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves post meta fields , based on post ID .
2019-11-02 10:38:58 +01:00
*
* 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
*
2022-04-02 10:26:41 +02:00
* @ param int $post_id Optional . Post ID . Default is the ID of the global `$post` .
2022-06-16 14:03:35 +02:00
* @ return mixed An array of values .
* False for an invalid `$post_id` ( non - numeric , zero , or negative value ) .
* An empty string if a valid but non - existing post ID is passed .
2019-11-02 10:38:58 +01:00
*/
function get_post_custom ( $post_id = 0 ) {
$post_id = absint ( $post_id );
2022-12-15 17:47:31 +01:00
2019-11-02 10:38:58 +01:00
if ( ! $post_id ) {
$post_id = get_the_ID ();
}
return get_post_meta ( $post_id );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves meta field names for a post .
2019-11-02 10:38:58 +01:00
*
* If there are no meta fields , then nothing ( null ) will be returned .
*
* @ since 1.2 . 0
*
2022-04-02 10:26:41 +02:00
* @ param int $post_id Optional . Post ID . Default is the ID of the global `$post` .
2019-11-02 10:38:58 +01:00
* @ 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 ;
}
2019-11-15 22:59:44 +01:00
$keys = array_keys ( $custom );
if ( $keys ) {
2019-11-02 10:38:58 +01:00
return $keys ;
}
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves values for a custom post field .
2019-11-02 10:38:58 +01:00
*
* 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 .
2022-04-02 10:26:41 +02:00
* @ param int $post_id Optional . Post ID . Default is the ID of the global `$post` .
2019-11-02 10:38:58 +01:00
* @ 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 ;
}
/**
* 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 .
*
* @ since 2.7 . 0
*
2022-04-02 10:26:41 +02:00
* @ param int $post_id Optional . Post ID . Default is the ID of the global `$post` .
2019-11-02 10:38:58 +01:00
* @ 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' );
2020-09-15 14:29:22 +02:00
if ( is_array ( $stickies ) ) {
$stickies = array_map ( 'intval' , $stickies );
$is_sticky = in_array ( $post_id , $stickies , true );
} else {
$is_sticky = false ;
}
2019-11-02 10:38:58 +01:00
2019-11-15 22:59:44 +01:00
/**
* Filters whether a post is sticky .
*
* @ since 5.3 . 0
*
* @ param bool $is_sticky Whether a post is sticky .
* @ param int $post_id Post ID .
*/
return apply_filters ( 'is_sticky' , $is_sticky , $post_id );
2019-11-02 10:38:58 +01:00
}
/**
2020-12-10 14:06:04 +01:00
* Sanitizes every post field .
2019-11-02 10:38:58 +01:00
*
* 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 ()
*
2020-12-10 14:06:04 +01:00
* @ param object | WP_Post | array $post The post object or array
2019-11-02 10:38:58 +01:00
* @ param string $context Optional . How to sanitize post fields .
2021-04-27 08:32:47 +02:00
* Accepts 'raw' , 'edit' , 'db' , 'display' ,
* 'attribute' , or 'js' . Default 'display' .
2020-12-10 14:06:04 +01:00
* @ return object | WP_Post | array The now sanitized post object or array ( will be the
* same type as `$post` ) .
2019-11-02 10:38:58 +01:00
*/
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 ) {
return $post ;
}
if ( ! isset ( $post -> ID ) ) {
$post -> ID = 0 ;
}
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' ] ) {
return $post ;
}
if ( ! isset ( $post [ 'ID' ] ) ) {
$post [ 'ID' ] = 0 ;
}
foreach ( array_keys ( $post ) as $field ) {
$post [ $field ] = sanitize_post_field ( $field , $post [ $field ], $post [ 'ID' ], $context );
}
$post [ 'filter' ] = $context ;
}
return $post ;
}
/**
2020-09-15 14:29:22 +02:00
* Sanitizes a post field based on context .
2019-11-02 10:38:58 +01:00
*
* 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 2.3 . 0
* @ 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 .
2020-09-15 14:29:22 +02:00
* @ param string $context Optional . How to sanitize the field . Possible values are 'raw' , 'edit' ,
2019-11-02 10:38:58 +01:00
* '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' );
2020-09-15 14:29:22 +02:00
if ( in_array ( $field , $int_fields , true ) ) {
2019-11-02 10:38:58 +01:00
$value = ( int ) $value ;
}
// Fields which contain arrays of integers.
$array_int_fields = array ( 'ancestors' );
2020-09-15 14:29:22 +02:00
if ( in_array ( $field , $array_int_fields , true ) ) {
2019-11-02 10:38:58 +01:00
$value = array_map ( 'absint' , $value );
return $value ;
}
2020-09-15 14:29:22 +02:00
if ( 'raw' === $context ) {
2019-11-02 10:38:58 +01:00
return $value ;
}
$prefixed = false ;
if ( false !== strpos ( $field , 'post_' ) ) {
$prefixed = true ;
$field_no_prefix = str_replace ( 'post_' , '' , $field );
}
2020-09-15 14:29:22 +02:00
if ( 'edit' === $context ) {
2019-11-02 10:38:58 +01:00
$format_to_edit = array ( 'post_content' , 'post_excerpt' , 'post_title' , 'post_password' );
if ( $prefixed ) {
/**
* Filters the value of a specific post field to edit .
*
* The dynamic portion of the hook name , `$field` , refers to the post
* field name .
*
* @ since 2.3 . 0
*
* @ param mixed $value Value of the post field .
* @ param int $post_id Post ID .
*/
$value = apply_filters ( " edit_ { $field } " , $value , $post_id );
/**
* Filters the value of a specific post field to edit .
*
* The dynamic portion of the hook name , `$field_no_prefix` , refers to
* the post field name .
*
* @ since 2.3 . 0
*
* @ param mixed $value Value of the post field .
* @ param int $post_id Post ID .
*/
$value = apply_filters ( " { $field_no_prefix } _edit_pre " , $value , $post_id );
} else {
$value = apply_filters ( " edit_post_ { $field } " , $value , $post_id );
}
2020-09-15 14:29:22 +02:00
if ( in_array ( $field , $format_to_edit , true ) ) {
if ( 'post_content' === $field ) {
2019-11-02 10:38:58 +01:00
$value = format_to_edit ( $value , user_can_richedit () );
} else {
$value = format_to_edit ( $value );
}
} else {
$value = esc_attr ( $value );
}
2020-09-15 14:29:22 +02:00
} elseif ( 'db' === $context ) {
2019-11-02 10:38:58 +01:00
if ( $prefixed ) {
/**
* Filters the value of a specific post field before saving .
*
* The dynamic portion of the hook name , `$field` , refers to the post
* field name .
*
* @ since 2.3 . 0
*
* @ param mixed $value Value of the post field .
*/
$value = apply_filters ( " pre_ { $field } " , $value );
/**
* Filters the value of a specific field before saving .
*
* The dynamic portion of the hook name , `$field_no_prefix` , refers
* to the post field name .
*
* @ since 2.3 . 0
*
* @ param mixed $value Value of the post field .
*/
$value = apply_filters ( " { $field_no_prefix } _save_pre " , $value );
} else {
$value = apply_filters ( " pre_post_ { $field } " , $value );
/**
* Filters the value of a specific post field before saving .
*
* The dynamic portion of the hook name , `$field` , refers to the post
* field name .
*
* @ since 2.3 . 0
*
* @ param mixed $value Value of the post field .
*/
$value = apply_filters ( " { $field } _pre " , $value );
}
} else {
// Use display filters by default.
if ( $prefixed ) {
/**
* Filters the value of a specific post field for display .
*
* The dynamic portion of the hook name , `$field` , refers to the post
* field name .
*
* @ since 2.3 . 0
*
* @ param mixed $value Value of the prefixed post field .
* @ param int $post_id Post ID .
2021-04-27 08:32:47 +02:00
* @ param string $context Context for how to sanitize the field .
* Accepts 'raw' , 'edit' , 'db' , 'display' ,
* 'attribute' , or 'js' . Default 'display' .
2019-11-02 10:38:58 +01:00
*/
$value = apply_filters ( " { $field } " , $value , $post_id , $context );
} else {
$value = apply_filters ( " post_ { $field } " , $value , $post_id , $context );
}
2020-09-15 14:29:22 +02:00
if ( 'attribute' === $context ) {
2019-11-02 10:38:58 +01:00
$value = esc_attr ( $value );
2020-09-15 14:29:22 +02:00
} elseif ( 'js' === $context ) {
2019-11-02 10:38:58 +01:00
$value = esc_js ( $value );
}
}
2021-07-23 11:58:50 +02:00
// Restore the type for integer fields after esc_attr().
if ( in_array ( $field , $int_fields , true ) ) {
$value = ( int ) $value ;
}
2019-11-02 10:38:58 +01:00
return $value ;
}
/**
2022-12-15 17:47:31 +01:00
* Makes a post sticky .
2019-11-02 10:38:58 +01:00
*
* Sticky posts should be displayed at the top of the front page .
*
* @ since 2.7 . 0
*
* @ param int $post_id Post ID .
*/
function stick_post ( $post_id ) {
2020-09-15 14:29:22 +02:00
$post_id = ( int ) $post_id ;
2019-11-02 10:38:58 +01:00
$stickies = get_option ( 'sticky_posts' );
2021-04-27 08:32:47 +02:00
$updated = false ;
2019-11-02 10:38:58 +01:00
if ( ! is_array ( $stickies ) ) {
2022-06-16 14:03:35 +02:00
$stickies = array ();
2021-04-27 08:32:47 +02:00
} else {
$stickies = array_unique ( array_map ( 'intval' , $stickies ) );
2019-11-02 10:38:58 +01:00
}
2020-09-15 14:29:22 +02:00
if ( ! in_array ( $post_id , $stickies , true ) ) {
2019-11-02 10:38:58 +01:00
$stickies [] = $post_id ;
2021-04-27 08:32:47 +02:00
$updated = update_option ( 'sticky_posts' , array_values ( $stickies ) );
2019-11-02 10:38:58 +01:00
}
if ( $updated ) {
/**
* Fires once a post has been added to the sticky list .
*
* @ since 4.6 . 0
*
* @ param int $post_id ID of the post that was stuck .
*/
do_action ( 'post_stuck' , $post_id );
}
}
/**
2022-12-15 17:47:31 +01:00
* Un - sticks a post .
2019-11-02 10:38:58 +01:00
*
* Sticky posts should be displayed at the top of the front page .
*
* @ since 2.7 . 0
*
* @ param int $post_id Post ID .
*/
function unstick_post ( $post_id ) {
2020-09-15 14:29:22 +02:00
$post_id = ( int ) $post_id ;
2019-11-02 10:38:58 +01:00
$stickies = get_option ( 'sticky_posts' );
if ( ! is_array ( $stickies ) ) {
return ;
}
2021-04-27 08:32:47 +02:00
$stickies = array_values ( array_unique ( array_map ( 'intval' , $stickies ) ) );
2020-09-15 14:29:22 +02:00
if ( ! in_array ( $post_id , $stickies , true ) ) {
2019-11-02 10:38:58 +01:00
return ;
}
2020-09-15 14:29:22 +02:00
$offset = array_search ( $post_id , $stickies , true );
2019-11-02 10:38:58 +01:00
if ( false === $offset ) {
return ;
}
array_splice ( $stickies , $offset , 1 );
$updated = update_option ( 'sticky_posts' , $stickies );
if ( $updated ) {
/**
* Fires once a post has been removed from the sticky list .
*
* @ since 4.6 . 0
*
* @ param int $post_id ID of the post that was unstuck .
*/
do_action ( 'post_unstuck' , $post_id );
}
}
/**
2022-12-15 17:47:31 +01:00
* Returns the cache key for wp_count_posts () based on the passed arguments .
2019-11-02 10:38:58 +01:00
*
* @ since 3.9 . 0
* @ access private
*
* @ param string $type Optional . Post type to retrieve count Default 'post' .
* @ param string $perm Optional . 'readable' or empty . Default empty .
* @ return string The cache key .
*/
function _count_posts_cache_key ( $type = 'post' , $perm = '' ) {
$cache_key = 'posts-' . $type ;
2020-09-15 14:29:22 +02:00
if ( 'readable' === $perm && is_user_logged_in () ) {
2019-11-02 10:38:58 +01:00
$post_type_object = get_post_type_object ( $type );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( $post_type_object && ! current_user_can ( $post_type_object -> cap -> read_private_posts ) ) {
$cache_key .= '_' . $perm . '_' . get_current_user_id ();
}
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
return $cache_key ;
}
/**
2022-12-15 17:47:31 +01:00
* Counts number of posts of a post type and if user has permissions to view .
2019-11-02 10:38:58 +01:00
*
* This function provides an efficient method of finding the amount of post ' s
* type a blog has . Another method is to count the amount of items in
* get_posts (), but that method has a lot of overhead with doing so . Therefore ,
* when developing for 2.5 + , use this function instead .
*
* The $perm parameter checks for 'readable' value and if the user can read
* private posts , it will display that for the user that is signed in .
*
* @ since 2.5 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param string $type Optional . Post type to retrieve count . Default 'post' .
* @ param string $perm Optional . 'readable' or empty . Default empty .
2022-04-02 10:26:41 +02:00
* @ return stdClass Number of posts for each status .
2019-11-02 10:38:58 +01:00
*/
function wp_count_posts ( $type = 'post' , $perm = '' ) {
global $wpdb ;
if ( ! post_type_exists ( $type ) ) {
2023-04-26 17:39:43 +02:00
return new stdClass ();
2019-11-02 10:38:58 +01:00
}
$cache_key = _count_posts_cache_key ( $type , $perm );
$counts = wp_cache_get ( $cache_key , 'counts' );
if ( false !== $counts ) {
2020-09-15 14:29:22 +02:00
// We may have cached this before every status was registered.
foreach ( get_post_stati () as $status ) {
if ( ! isset ( $counts -> { $status } ) ) {
$counts -> { $status } = 0 ;
}
}
2019-11-02 10:38:58 +01:00
/** This filter is documented in wp-includes/post.php */
return apply_filters ( 'wp_count_posts' , $counts , $type , $perm );
}
$query = " SELECT post_status, COUNT( * ) AS num_posts FROM { $wpdb -> posts } WHERE post_type = %s " ;
2020-09-15 14:29:22 +02:00
if ( 'readable' === $perm && is_user_logged_in () ) {
2019-11-02 10:38:58 +01:00
$post_type_object = get_post_type_object ( $type );
if ( ! current_user_can ( $post_type_object -> cap -> read_private_posts ) ) {
$query .= $wpdb -> prepare (
" AND (post_status != 'private' OR ( post_author = %d AND post_status = 'private' )) " ,
get_current_user_id ()
);
}
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
$query .= ' GROUP BY post_status' ;
$results = ( array ) $wpdb -> get_results ( $wpdb -> prepare ( $query , $type ), ARRAY_A );
$counts = array_fill_keys ( get_post_stati (), 0 );
foreach ( $results as $row ) {
$counts [ $row [ 'post_status' ] ] = $row [ 'num_posts' ];
}
$counts = ( object ) $counts ;
wp_cache_set ( $cache_key , $counts , 'counts' );
/**
2023-04-26 17:39:43 +02:00
* Filters the post counts by status for the current post type .
2019-11-02 10:38:58 +01:00
*
* @ since 3.7 . 0
*
2022-04-02 10:26:41 +02:00
* @ param stdClass $counts An object containing the current post_type ' s post
* counts by status .
* @ param string $type Post type .
* @ param string $perm The permission to determine if the posts are 'readable'
* by the current user .
2019-11-02 10:38:58 +01:00
*/
return apply_filters ( 'wp_count_posts' , $counts , $type , $perm );
}
/**
2022-12-15 17:47:31 +01:00
* Counts number of attachments for the mime type ( s ) .
2019-11-02 10:38:58 +01:00
*
* If you set the optional mime_type parameter , then an array will still be
* returned , but will only have the item you are looking for . It does not give
* you the number of attachments that are children of a post . You can get that
* by counting the number of children that post has .
*
* @ since 2.5 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
2021-04-27 08:32:47 +02:00
* @ param string | string [] $mime_type Optional . Array or comma - separated list of
* MIME patterns . Default empty .
2022-04-02 10:26:41 +02:00
* @ return stdClass An object containing the attachment counts by mime type .
2019-11-02 10:38:58 +01:00
*/
function wp_count_attachments ( $mime_type = '' ) {
global $wpdb ;
2022-12-15 17:47:31 +01:00
$cache_key = sprintf (
'attachments%s' ,
! empty ( $mime_type ) ? ':' . str_replace ( '/' , '_' , implode ( '-' , ( array ) $mime_type ) ) : ''
);
$counts = wp_cache_get ( $cache_key , 'counts' );
if ( false == $counts ) {
$and = wp_post_mime_type_where ( $mime_type );
$count = $wpdb -> get_results ( " SELECT post_mime_type, COUNT( * ) AS num_posts FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status != 'trash' $and GROUP BY post_mime_type " , ARRAY_A );
$counts = array ();
foreach ( ( array ) $count as $row ) {
$counts [ $row [ 'post_mime_type' ] ] = $row [ 'num_posts' ];
}
$counts [ 'trash' ] = $wpdb -> get_var ( " SELECT COUNT( * ) FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status = 'trash' $and " );
2019-11-02 10:38:58 +01:00
2022-12-15 17:47:31 +01:00
wp_cache_set ( $cache_key , ( object ) $counts , 'counts' );
2019-11-02 10:38:58 +01:00
}
/**
2023-04-26 17:39:43 +02:00
* Filters the attachment counts by mime type .
2019-11-02 10:38:58 +01:00
*
* @ since 3.7 . 0
*
2022-04-02 10:26:41 +02:00
* @ param stdClass $counts An object containing the attachment counts by
2021-04-27 08:32:47 +02:00
* mime type .
* @ param string | string [] $mime_type Array or comma - separated list of MIME patterns .
2019-11-02 10:38:58 +01:00
*/
return apply_filters ( 'wp_count_attachments' , ( object ) $counts , $mime_type );
}
/**
2022-12-15 17:47:31 +01:00
* Gets default post mime types .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
2019-11-15 22:59:44 +01:00
* @ since 5.3 . 0 Added the 'Documents' , 'Spreadsheets' , and 'Archives' mime type groups .
2019-11-02 10:38:58 +01:00
*
* @ return array List of post mime types .
*/
function get_post_mime_types () {
2020-05-06 17:23:38 +02:00
$post_mime_types = array ( // array( adj, noun )
2019-11-15 22:59:44 +01:00
'image' => array (
__ ( 'Images' ),
__ ( 'Manage Images' ),
/* translators: %s: Number of images. */
_n_noop (
'Image <span class="count">(%s)</span>' ,
'Images <span class="count">(%s)</span>'
),
),
'audio' => array (
2022-04-02 10:26:41 +02:00
_x ( 'Audio' , 'file type group' ),
2019-11-15 22:59:44 +01:00
__ ( 'Manage Audio' ),
/* translators: %s: Number of audio files. */
_n_noop (
'Audio <span class="count">(%s)</span>' ,
'Audio <span class="count">(%s)</span>'
),
),
'video' => array (
2022-04-02 10:26:41 +02:00
_x ( 'Video' , 'file type group' ),
2019-11-15 22:59:44 +01:00
__ ( 'Manage Video' ),
/* translators: %s: Number of video files. */
_n_noop (
'Video <span class="count">(%s)</span>' ,
'Video <span class="count">(%s)</span>'
),
),
'document' => array (
__ ( 'Documents' ),
__ ( 'Manage Documents' ),
/* translators: %s: Number of documents. */
_n_noop (
'Document <span class="count">(%s)</span>' ,
'Documents <span class="count">(%s)</span>'
),
),
'spreadsheet' => array (
__ ( 'Spreadsheets' ),
__ ( 'Manage Spreadsheets' ),
/* translators: %s: Number of spreadsheets. */
_n_noop (
'Spreadsheet <span class="count">(%s)</span>' ,
'Spreadsheets <span class="count">(%s)</span>'
),
),
'archive' => array (
_x ( 'Archives' , 'file type group' ),
__ ( 'Manage Archives' ),
/* translators: %s: Number of archives. */
_n_noop (
'Archive <span class="count">(%s)</span>' ,
'Archives <span class="count">(%s)</span>'
),
),
2019-11-02 10:38:58 +01:00
);
2019-11-15 22:59:44 +01:00
$ext_types = wp_get_ext_types ();
$mime_types = wp_get_mime_types ();
foreach ( $post_mime_types as $group => $labels ) {
2020-09-15 14:29:22 +02:00
if ( in_array ( $group , array ( 'image' , 'audio' , 'video' ), true ) ) {
2019-11-15 22:59:44 +01:00
continue ;
}
if ( ! isset ( $ext_types [ $group ] ) ) {
unset ( $post_mime_types [ $group ] );
continue ;
}
$group_mime_types = array ();
foreach ( $ext_types [ $group ] as $extension ) {
foreach ( $mime_types as $exts => $mime ) {
if ( preg_match ( '!^(' . $exts . ')$!i' , $extension ) ) {
$group_mime_types [] = $mime ;
break ;
}
}
}
$group_mime_types = implode ( ',' , array_unique ( $group_mime_types ) );
$post_mime_types [ $group_mime_types ] = $labels ;
unset ( $post_mime_types [ $group ] );
}
2019-11-02 10:38:58 +01:00
/**
* Filters the default list of post mime types .
*
* @ since 2.5 . 0
*
* @ param array $post_mime_types Default list of post mime types .
*/
return apply_filters ( 'post_mime_types' , $post_mime_types );
}
/**
2022-12-15 17:47:31 +01:00
* Checks a MIME - Type against a list .
2019-11-02 10:38:58 +01:00
*
2022-12-15 17:47:31 +01:00
* If the `$wildcard_mime_types` parameter is a string , it must be comma separated
* list . If the `$real_mime_types` is a string , it is also comma separated to
2019-11-02 10:38:58 +01:00
* create the list .
*
* @ since 2.5 . 0
*
2022-12-15 17:47:31 +01:00
* @ param string | string [] $wildcard_mime_types Mime types , e . g . `audio/mpeg` , `image` ( same as `image/*` ),
* or `flash` ( same as `*flash*` ) .
2021-04-27 08:32:47 +02:00
* @ param string | string [] $real_mime_types Real post mime type values .
2019-11-02 10:38:58 +01:00
* @ return array array ( wildcard => array ( real types )) .
*/
function wp_match_mime_types ( $wildcard_mime_types , $real_mime_types ) {
$matches = array ();
if ( is_string ( $wildcard_mime_types ) ) {
$wildcard_mime_types = array_map ( 'trim' , explode ( ',' , $wildcard_mime_types ) );
}
if ( is_string ( $real_mime_types ) ) {
$real_mime_types = array_map ( 'trim' , explode ( ',' , $real_mime_types ) );
}
$patternses = array ();
$wild = '[-._a-z0-9]*' ;
foreach ( ( array ) $wildcard_mime_types as $type ) {
$mimes = array_map ( 'trim' , explode ( ',' , $type ) );
foreach ( $mimes as $mime ) {
2020-09-15 14:29:22 +02:00
$regex = str_replace ( '__wildcard__' , $wild , preg_quote ( str_replace ( '*' , '__wildcard__' , $mime ) ) );
2019-11-02 10:38:58 +01:00
$patternses [][ $type ] = " ^ $regex $ " ;
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( false === strpos ( $mime , '/' ) ) {
$patternses [][ $type ] = " ^ $regex / " ;
$patternses [][ $type ] = $regex ;
}
}
}
asort ( $patternses );
foreach ( $patternses as $patterns ) {
foreach ( $patterns as $type => $pattern ) {
foreach ( ( array ) $real_mime_types as $real ) {
2020-09-15 14:29:22 +02:00
if ( preg_match ( " # $pattern # " , $real )
&& ( empty ( $matches [ $type ] ) || false === array_search ( $real , $matches [ $type ], true ) )
) {
2019-11-02 10:38:58 +01:00
$matches [ $type ][] = $real ;
}
}
}
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
return $matches ;
}
/**
2022-12-15 17:47:31 +01:00
* Converts MIME types into SQL .
2019-11-02 10:38:58 +01:00
*
* @ since 2.5 . 0
*
2021-04-27 08:32:47 +02:00
* @ param string | string [] $post_mime_types List of mime types or comma separated string
* of mime types .
* @ param string $table_alias Optional . Specify a table alias , if needed .
* Default empty .
2019-11-02 10:38:58 +01:00
* @ return string The SQL AND clause for mime searching .
*/
function wp_post_mime_type_where ( $post_mime_types , $table_alias = '' ) {
$where = '' ;
$wildcards = array ( '' , '%' , '%/%' );
if ( is_string ( $post_mime_types ) ) {
$post_mime_types = array_map ( 'trim' , explode ( ',' , $post_mime_types ) );
}
$wheres = array ();
foreach ( ( array ) $post_mime_types as $mime_type ) {
$mime_type = preg_replace ( '/\s/' , '' , $mime_type );
$slashpos = strpos ( $mime_type , '/' );
if ( false !== $slashpos ) {
$mime_group = preg_replace ( '/[^-*.a-zA-Z0-9]/' , '' , substr ( $mime_type , 0 , $slashpos ) );
$mime_subgroup = preg_replace ( '/[^-*.+a-zA-Z0-9]/' , '' , substr ( $mime_type , $slashpos + 1 ) );
if ( empty ( $mime_subgroup ) ) {
$mime_subgroup = '*' ;
} else {
$mime_subgroup = str_replace ( '/' , '' , $mime_subgroup );
}
$mime_pattern = " $mime_group / $mime_subgroup " ;
} else {
$mime_pattern = preg_replace ( '/[^-*.a-zA-Z0-9]/' , '' , $mime_type );
if ( false === strpos ( $mime_pattern , '*' ) ) {
$mime_pattern .= '/*' ;
}
}
$mime_pattern = preg_replace ( '/\*+/' , '%' , $mime_pattern );
2020-09-15 14:29:22 +02:00
if ( in_array ( $mime_type , $wildcards , true ) ) {
2019-11-02 10:38:58 +01:00
return '' ;
}
if ( false !== strpos ( $mime_pattern , '%' ) ) {
$wheres [] = empty ( $table_alias ) ? " post_mime_type LIKE ' $mime_pattern ' " : " $table_alias .post_mime_type LIKE ' $mime_pattern ' " ;
} else {
$wheres [] = empty ( $table_alias ) ? " post_mime_type = ' $mime_pattern ' " : " $table_alias .post_mime_type = ' $mime_pattern ' " ;
}
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( ! empty ( $wheres ) ) {
2020-12-10 14:06:04 +01:00
$where = ' AND (' . implode ( ' OR ' , $wheres ) . ') ' ;
2019-11-02 10:38:58 +01:00
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
return $where ;
}
/**
2022-12-15 17:47:31 +01:00
* Trashes or deletes a post or page .
2019-11-02 10:38:58 +01:00
*
* When the post and page is permanently deleted , everything that is tied to
* it is deleted also . This includes comments , post meta fields , and terms
* associated with the post .
*
2020-05-06 17:23:38 +02:00
* The post or page is moved to Trash instead of permanently deleted unless
* Trash is disabled , item is already in the Trash , or $force_delete is true .
2019-11-02 10:38:58 +01:00
*
* @ since 1.0 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
* @ see wp_delete_attachment ()
* @ see wp_trash_post ()
*
* @ param int $postid Optional . Post ID . Default 0.
2020-05-06 17:23:38 +02:00
* @ param bool $force_delete Optional . Whether to bypass Trash and force deletion .
2019-11-02 10:38:58 +01:00
* Default false .
* @ return WP_Post | false | null Post data on success , false or null on failure .
*/
function wp_delete_post ( $postid = 0 , $force_delete = false ) {
global $wpdb ;
$post = $wpdb -> get_row ( $wpdb -> prepare ( " SELECT * FROM $wpdb->posts WHERE ID = %d " , $postid ) );
if ( ! $post ) {
return $post ;
}
$post = get_post ( $post );
if ( ! $force_delete && ( 'post' === $post -> post_type || 'page' === $post -> post_type ) && 'trash' !== get_post_status ( $postid ) && EMPTY_TRASH_DAYS ) {
return wp_trash_post ( $postid );
}
if ( 'attachment' === $post -> post_type ) {
return wp_delete_attachment ( $postid , $force_delete );
}
/**
* Filters whether a post deletion should take place .
*
* @ since 4.4 . 0
*
2022-12-15 17:47:31 +01:00
* @ param WP_Post | false | null $delete Whether to go forward with deletion .
2022-06-16 14:03:35 +02:00
* @ param WP_Post $post Post object .
* @ param bool $force_delete Whether to bypass the Trash .
2019-11-02 10:38:58 +01:00
*/
$check = apply_filters ( 'pre_delete_post' , null , $post , $force_delete );
if ( null !== $check ) {
return $check ;
}
/**
* Fires before a post is deleted , at the start of wp_delete_post () .
*
* @ since 3.2 . 0
2020-09-15 14:29:22 +02:00
* @ since 5.5 . 0 Added the `$post` parameter .
2019-11-02 10:38:58 +01:00
*
* @ see wp_delete_post ()
*
2020-09-15 14:29:22 +02:00
* @ param int $postid Post ID .
* @ param WP_Post $post Post object .
2019-11-02 10:38:58 +01:00
*/
2020-09-15 14:29:22 +02:00
do_action ( 'before_delete_post' , $postid , $post );
2019-11-02 10:38:58 +01:00
delete_post_meta ( $postid , '_wp_trash_meta_status' );
delete_post_meta ( $postid , '_wp_trash_meta_time' );
wp_delete_object_term_relationships ( $postid , get_object_taxonomies ( $post -> post_type ) );
$parent_data = array ( 'post_parent' => $post -> post_parent );
$parent_where = array ( 'post_parent' => $postid );
if ( is_post_type_hierarchical ( $post -> post_type ) ) {
// Point children of this page to its parent, also clean the cache of affected children.
$children_query = $wpdb -> prepare ( " SELECT * FROM $wpdb->posts WHERE post_parent = %d AND post_type = %s " , $postid , $post -> post_type );
$children = $wpdb -> get_results ( $children_query );
if ( $children ) {
$wpdb -> update ( $wpdb -> posts , $parent_data , $parent_where + array ( 'post_type' => $post -> post_type ) );
}
}
// Do raw query. wp_get_post_revisions() is filtered.
$revision_ids = $wpdb -> get_col ( $wpdb -> prepare ( " SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision' " , $postid ) );
// Use wp_delete_post (via wp_delete_post_revision) again. Ensures any meta/misplaced data gets cleaned up.
foreach ( $revision_ids as $revision_id ) {
wp_delete_post_revision ( $revision_id );
}
// Point all attachments to this post up one level.
$wpdb -> update ( $wpdb -> posts , $parent_data , $parent_where + array ( 'post_type' => 'attachment' ) );
wp_defer_comment_counting ( true );
2022-04-02 10:26:41 +02:00
$comment_ids = $wpdb -> get_col ( $wpdb -> prepare ( " SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d ORDER BY comment_ID DESC " , $postid ) );
2019-11-02 10:38:58 +01:00
foreach ( $comment_ids as $comment_id ) {
wp_delete_comment ( $comment_id , true );
}
wp_defer_comment_counting ( false );
$post_meta_ids = $wpdb -> get_col ( $wpdb -> prepare ( " SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d " , $postid ) );
foreach ( $post_meta_ids as $mid ) {
delete_metadata_by_mid ( 'post' , $mid );
}
/**
* Fires immediately before a post is deleted from the database .
*
* @ since 1.2 . 0
2020-09-15 14:29:22 +02:00
* @ since 5.5 . 0 Added the `$post` parameter .
2019-11-02 10:38:58 +01:00
*
2020-09-15 14:29:22 +02:00
* @ param int $postid Post ID .
* @ param WP_Post $post Post object .
2019-11-02 10:38:58 +01:00
*/
2020-09-15 14:29:22 +02:00
do_action ( 'delete_post' , $postid , $post );
2019-11-02 10:38:58 +01:00
$result = $wpdb -> delete ( $wpdb -> posts , array ( 'ID' => $postid ) );
if ( ! $result ) {
return false ;
}
/**
* Fires immediately after a post is deleted from the database .
*
* @ since 2.2 . 0
2020-09-15 14:29:22 +02:00
* @ since 5.5 . 0 Added the `$post` parameter .
2019-11-02 10:38:58 +01:00
*
2020-09-15 14:29:22 +02:00
* @ param int $postid Post ID .
* @ param WP_Post $post Post object .
2019-11-02 10:38:58 +01:00
*/
2020-09-15 14:29:22 +02:00
do_action ( 'deleted_post' , $postid , $post );
2019-11-02 10:38:58 +01:00
clean_post_cache ( $post );
if ( is_post_type_hierarchical ( $post -> post_type ) && $children ) {
foreach ( $children as $child ) {
clean_post_cache ( $child );
}
}
wp_clear_scheduled_hook ( 'publish_future_post' , array ( $postid ) );
/**
* Fires after a post is deleted , at the conclusion of wp_delete_post () .
*
* @ since 3.2 . 0
2020-09-15 14:29:22 +02:00
* @ since 5.5 . 0 Added the `$post` parameter .
2019-11-02 10:38:58 +01:00
*
* @ see wp_delete_post ()
*
2020-09-15 14:29:22 +02:00
* @ param int $postid Post ID .
* @ param WP_Post $post Post object .
2019-11-02 10:38:58 +01:00
*/
2020-09-15 14:29:22 +02:00
do_action ( 'after_delete_post' , $postid , $post );
2019-11-02 10:38:58 +01:00
return $post ;
}
/**
2022-12-15 17:47:31 +01:00
* Resets the page_on_front , show_on_front , and page_for_post settings when
2019-11-02 10:38:58 +01:00
* a linked page is deleted or trashed .
*
* Also ensures the post is no longer sticky .
*
* @ since 3.7 . 0
* @ access private
*
* @ param int $post_id Post ID .
*/
function _reset_front_page_settings_for_post ( $post_id ) {
$post = get_post ( $post_id );
2020-09-15 14:29:22 +02:00
if ( 'page' === $post -> post_type ) {
2019-11-02 10:38:58 +01:00
/*
2019-11-15 22:59:44 +01:00
* If the page is defined in option page_on_front or post_for_posts ,
* adjust the corresponding options .
*/
2019-11-02 10:38:58 +01:00
if ( get_option ( 'page_on_front' ) == $post -> ID ) {
update_option ( 'show_on_front' , 'posts' );
update_option ( 'page_on_front' , 0 );
}
if ( get_option ( 'page_for_posts' ) == $post -> ID ) {
2019-11-15 22:59:44 +01:00
update_option ( 'page_for_posts' , 0 );
2019-11-02 10:38:58 +01:00
}
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
unstick_post ( $post -> ID );
}
/**
2022-12-15 17:47:31 +01:00
* Moves a post or page to the Trash
2019-11-02 10:38:58 +01:00
*
2020-05-06 17:23:38 +02:00
* If Trash is disabled , the post or page is permanently deleted .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
*
* @ see wp_delete_post ()
*
2022-04-02 10:26:41 +02:00
* @ param int $post_id Optional . Post ID . Default is the ID of the global `$post`
* if `EMPTY_TRASH_DAYS` equals true .
2019-11-02 10:38:58 +01:00
* @ return WP_Post | false | null Post data on success , false or null on failure .
*/
function wp_trash_post ( $post_id = 0 ) {
if ( ! EMPTY_TRASH_DAYS ) {
return wp_delete_post ( $post_id , true );
}
$post = get_post ( $post_id );
if ( ! $post ) {
return $post ;
}
if ( 'trash' === $post -> post_status ) {
return false ;
}
/**
* Filters whether a post trashing should take place .
*
* @ since 4.9 . 0
*
2019-11-15 22:59:44 +01:00
* @ param bool | null $trash Whether to go forward with trashing .
* @ param WP_Post $post Post object .
2019-11-02 10:38:58 +01:00
*/
$check = apply_filters ( 'pre_trash_post' , null , $post );
2020-12-10 14:06:04 +01:00
2019-11-02 10:38:58 +01:00
if ( null !== $check ) {
return $check ;
}
/**
2020-05-06 17:23:38 +02:00
* Fires before a post is sent to the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 3.3 . 0
*
* @ param int $post_id Post ID .
*/
do_action ( 'wp_trash_post' , $post_id );
add_post_meta ( $post_id , '_wp_trash_meta_status' , $post -> post_status );
add_post_meta ( $post_id , '_wp_trash_meta_time' , time () );
2019-11-15 22:59:44 +01:00
$post_updated = wp_update_post (
2019-11-02 10:38:58 +01:00
array (
'ID' => $post_id ,
'post_status' => 'trash' ,
)
);
2019-11-15 22:59:44 +01:00
if ( ! $post_updated ) {
return false ;
}
2019-11-02 10:38:58 +01:00
wp_trash_post_comments ( $post_id );
/**
2020-05-06 17:23:38 +02:00
* Fires after a post is sent to the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
*
* @ param int $post_id Post ID .
*/
do_action ( 'trashed_post' , $post_id );
return $post ;
}
/**
2020-12-10 14:06:04 +01:00
* Restores a post from the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
2020-12-10 14:06:04 +01:00
* @ since 5.6 . 0 An untrashed post is now returned to 'draft' status by default , except for
* attachments which are returned to their original 'inherit' status .
2019-11-02 10:38:58 +01:00
*
2022-04-02 10:26:41 +02:00
* @ param int $post_id Optional . Post ID . Default is the ID of the global `$post` .
2019-11-02 10:38:58 +01:00
* @ return WP_Post | false | null Post data on success , false or null on failure .
*/
function wp_untrash_post ( $post_id = 0 ) {
$post = get_post ( $post_id );
if ( ! $post ) {
return $post ;
}
2020-12-10 14:06:04 +01:00
$post_id = $post -> ID ;
2019-11-02 10:38:58 +01:00
if ( 'trash' !== $post -> post_status ) {
return false ;
}
2020-12-10 14:06:04 +01:00
$previous_status = get_post_meta ( $post_id , '_wp_trash_meta_status' , true );
2019-11-02 10:38:58 +01:00
/**
* Filters whether a post untrashing should take place .
*
* @ since 4.9 . 0
2020-12-10 14:06:04 +01:00
* @ since 5.6 . 0 The `$previous_status` parameter was added .
2019-11-02 10:38:58 +01:00
*
2020-12-10 14:06:04 +01:00
* @ param bool | null $untrash Whether to go forward with untrashing .
* @ param WP_Post $post Post object .
* @ param string $previous_status The status of the post at the point where it was trashed .
2019-11-02 10:38:58 +01:00
*/
2020-12-10 14:06:04 +01:00
$check = apply_filters ( 'pre_untrash_post' , null , $post , $previous_status );
2019-11-02 10:38:58 +01:00
if ( null !== $check ) {
return $check ;
}
/**
2020-05-06 17:23:38 +02:00
* Fires before a post is restored from the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
2020-12-10 14:06:04 +01:00
* @ since 5.6 . 0 The `$previous_status` parameter was added .
2019-11-02 10:38:58 +01:00
*
2020-12-10 14:06:04 +01:00
* @ param int $post_id Post ID .
* @ param string $previous_status The status of the post at the point where it was trashed .
2019-11-02 10:38:58 +01:00
*/
2020-12-10 14:06:04 +01:00
do_action ( 'untrash_post' , $post_id , $previous_status );
$new_status = ( 'attachment' === $post -> post_type ) ? 'inherit' : 'draft' ;
2019-11-02 10:38:58 +01:00
2020-12-10 14:06:04 +01:00
/**
* Filters the status that a post gets assigned when it is restored from the trash ( untrashed ) .
*
* By default posts that are restored will be assigned a status of 'draft' . Return the value of `$previous_status`
* in order to assign the status that the post had before it was trashed . The `wp_untrash_post_set_previous_status()`
* function is available for this .
*
* Prior to WordPress 5.6 . 0 , restored posts were always assigned their original status .
*
* @ since 5.6 . 0
*
* @ param string $new_status The new status of the post being restored .
* @ param int $post_id The ID of the post being restored .
* @ param string $previous_status The status of the post at the point where it was trashed .
*/
$post_status = apply_filters ( 'wp_untrash_post_status' , $new_status , $post_id , $previous_status );
2019-11-02 10:38:58 +01:00
delete_post_meta ( $post_id , '_wp_trash_meta_status' );
delete_post_meta ( $post_id , '_wp_trash_meta_time' );
2019-11-15 22:59:44 +01:00
$post_updated = wp_update_post (
2019-11-02 10:38:58 +01:00
array (
'ID' => $post_id ,
'post_status' => $post_status ,
)
);
2019-11-15 22:59:44 +01:00
if ( ! $post_updated ) {
return false ;
}
2019-11-02 10:38:58 +01:00
wp_untrash_post_comments ( $post_id );
/**
2020-05-06 17:23:38 +02:00
* Fires after a post is restored from the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
2020-12-10 14:06:04 +01:00
* @ since 5.6 . 0 The `$previous_status` parameter was added .
2019-11-02 10:38:58 +01:00
*
2020-12-10 14:06:04 +01:00
* @ param int $post_id Post ID .
* @ param string $previous_status The status of the post at the point where it was trashed .
2019-11-02 10:38:58 +01:00
*/
2020-12-10 14:06:04 +01:00
do_action ( 'untrashed_post' , $post_id , $previous_status );
2019-11-02 10:38:58 +01:00
return $post ;
}
/**
2020-05-06 17:23:38 +02:00
* Moves comments for a post to the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param int | WP_Post | null $post Optional . Post ID or post object . Defaults to global $post .
* @ return mixed | void False on failure .
*/
function wp_trash_post_comments ( $post = null ) {
global $wpdb ;
$post = get_post ( $post );
2020-12-10 14:06:04 +01:00
if ( ! $post ) {
2019-11-02 10:38:58 +01:00
return ;
}
$post_id = $post -> ID ;
/**
2020-05-06 17:23:38 +02:00
* Fires before comments are sent to the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
*
* @ param int $post_id Post ID .
*/
do_action ( 'trash_post_comments' , $post_id );
$comments = $wpdb -> get_results ( $wpdb -> prepare ( " SELECT comment_ID, comment_approved FROM $wpdb->comments WHERE comment_post_ID = %d " , $post_id ) );
2020-12-10 14:06:04 +01:00
if ( ! $comments ) {
2019-11-02 10:38:58 +01:00
return ;
}
// Cache current status for each comment.
$statuses = array ();
foreach ( $comments as $comment ) {
$statuses [ $comment -> comment_ID ] = $comment -> comment_approved ;
}
add_post_meta ( $post_id , '_wp_trash_meta_comments_status' , $statuses );
// Set status for all comments to post-trashed.
$result = $wpdb -> update ( $wpdb -> comments , array ( 'comment_approved' => 'post-trashed' ), array ( 'comment_post_ID' => $post_id ) );
clean_comment_cache ( array_keys ( $statuses ) );
/**
2020-05-06 17:23:38 +02:00
* Fires after comments are sent to the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
*
* @ param int $post_id Post ID .
* @ param array $statuses Array of comment statuses .
*/
do_action ( 'trashed_post_comments' , $post_id , $statuses );
return $result ;
}
/**
2022-12-15 17:47:31 +01:00
* Restores comments for a post from the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param int | WP_Post | null $post Optional . Post ID or post object . Defaults to global $post .
* @ return true | void
*/
function wp_untrash_post_comments ( $post = null ) {
global $wpdb ;
$post = get_post ( $post );
2020-12-10 14:06:04 +01:00
if ( ! $post ) {
2019-11-02 10:38:58 +01:00
return ;
}
$post_id = $post -> ID ;
$statuses = get_post_meta ( $post_id , '_wp_trash_meta_comments_status' , true );
2020-12-10 14:06:04 +01:00
if ( ! $statuses ) {
2019-11-02 10:38:58 +01:00
return true ;
}
/**
2020-05-06 17:23:38 +02:00
* Fires before comments are restored for a post from the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
*
* @ param int $post_id Post ID .
*/
do_action ( 'untrash_post_comments' , $post_id );
// Restore each comment to its original status.
$group_by_status = array ();
foreach ( $statuses as $comment_id => $comment_status ) {
$group_by_status [ $comment_status ][] = $comment_id ;
}
foreach ( $group_by_status as $status => $comments ) {
// Sanity check. This shouldn't happen.
2020-09-15 14:29:22 +02:00
if ( 'post-trashed' === $status ) {
2019-11-02 10:38:58 +01:00
$status = '0' ;
}
$comments_in = implode ( ', ' , array_map ( 'intval' , $comments ) );
$wpdb -> query ( $wpdb -> prepare ( " UPDATE $wpdb->comments SET comment_approved = %s WHERE comment_ID IN ( $comments_in ) " , $status ) );
}
clean_comment_cache ( array_keys ( $statuses ) );
delete_post_meta ( $post_id , '_wp_trash_meta_comments_status' );
/**
2020-05-06 17:23:38 +02:00
* Fires after comments are restored for a post from the Trash .
2019-11-02 10:38:58 +01:00
*
* @ since 2.9 . 0
*
* @ param int $post_id Post ID .
*/
do_action ( 'untrashed_post_comments' , $post_id );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves the list of categories for a post .
2019-11-02 10:38:58 +01:00
*
* Compatibility layer for themes and plugins . Also an easy layer of abstraction
* away from the complexity of the taxonomy layer .
*
* @ since 2.1 . 0
*
* @ see wp_get_object_terms ()
*
* @ param int $post_id Optional . The Post ID . Does not default to the ID of the
* global $post . Default 0.
* @ param array $args Optional . Category query parameters . Default empty array .
* See WP_Term_Query :: __construct () for supported arguments .
* @ return array | WP_Error List of categories . If the `$fields` argument passed via `$args` is 'all' or
* 'all_with_object_id' , an array of WP_Term objects will be returned . If `$fields`
2020-09-15 14:29:22 +02:00
* is 'ids' , an array of category IDs . If `$fields` is 'names' , an array of category names .
2019-11-02 10:38:58 +01:00
* WP_Error object if 'category' taxonomy doesn ' t exist .
*/
function wp_get_post_categories ( $post_id = 0 , $args = array () ) {
$post_id = ( int ) $post_id ;
$defaults = array ( 'fields' => 'ids' );
$args = wp_parse_args ( $args , $defaults );
$cats = wp_get_object_terms ( $post_id , 'category' , $args );
return $cats ;
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves the tags for a post .
2019-11-02 10:38:58 +01:00
*
* There is only one default for this function , called 'fields' and by default
* is set to 'all' . There are other defaults that can be overridden in
* wp_get_object_terms () .
*
* @ since 2.3 . 0
*
* @ param int $post_id Optional . The Post ID . Does not default to the ID of the
* global $post . Default 0.
* @ param array $args Optional . Tag query parameters . Default empty array .
* See WP_Term_Query :: __construct () for supported arguments .
* @ return array | WP_Error Array of WP_Term objects on success or empty array if no tags were found .
* WP_Error object if 'post_tag' taxonomy doesn ' t exist .
*/
function wp_get_post_tags ( $post_id = 0 , $args = array () ) {
return wp_get_post_terms ( $post_id , 'post_tag' , $args );
}
/**
* Retrieves the terms for a post .
*
* @ since 2.8 . 0
*
2021-04-27 08:32:47 +02:00
* @ param int $post_id Optional . The Post ID . Does not default to the ID of the
* global $post . Default 0.
* @ param string | string [] $taxonomy Optional . The taxonomy slug or array of slugs for which
* to retrieve terms . Default 'post_tag' .
* @ param array $args {
2019-11-02 10:38:58 +01:00
* Optional . Term query parameters . See WP_Term_Query :: __construct () for supported arguments .
*
* @ type string $fields Term fields to retrieve . Default 'all' .
* }
* @ return array | WP_Error Array of WP_Term objects on success or empty array if no terms were found .
* WP_Error object if `$taxonomy` doesn ' t exist .
*/
function wp_get_post_terms ( $post_id = 0 , $taxonomy = 'post_tag' , $args = array () ) {
$post_id = ( int ) $post_id ;
$defaults = array ( 'fields' => 'all' );
$args = wp_parse_args ( $args , $defaults );
$tags = wp_get_object_terms ( $post_id , $taxonomy , $args );
return $tags ;
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves a number of recent posts .
2019-11-02 10:38:58 +01:00
*
* @ since 1.0 . 0
*
* @ see get_posts ()
*
* @ param array $args Optional . Arguments to retrieve posts . Default empty array .
2020-09-15 14:29:22 +02:00
* @ param string $output Optional . The required return type . One of OBJECT or ARRAY_A , which
* correspond to a WP_Post object or an associative array , respectively .
* Default ARRAY_A .
* @ return array | false Array of recent posts , where the type of each element is determined
* by the `$output` parameter . Empty array on failure .
2019-11-02 10:38:58 +01:00
*/
function wp_get_recent_posts ( $args = array (), $output = ARRAY_A ) {
if ( is_numeric ( $args ) ) {
_deprecated_argument ( __FUNCTION__ , '3.1.0' , __ ( 'Passing an integer number of posts is deprecated. Pass an array of arguments instead.' ) );
$args = array ( 'numberposts' => absint ( $args ) );
}
// Set default arguments.
$defaults = array (
'numberposts' => 10 ,
'offset' => 0 ,
'category' => 0 ,
'orderby' => 'post_date' ,
'order' => 'DESC' ,
'include' => '' ,
'exclude' => '' ,
'meta_key' => '' ,
'meta_value' => '' ,
'post_type' => 'post' ,
'post_status' => 'draft, publish, future, pending, private' ,
'suppress_filters' => true ,
);
2019-11-15 22:59:44 +01:00
$parsed_args = wp_parse_args ( $args , $defaults );
2019-11-02 10:38:58 +01:00
2019-11-15 22:59:44 +01:00
$results = get_posts ( $parsed_args );
2019-11-02 10:38:58 +01:00
// Backward compatibility. Prior to 3.1 expected posts to be returned in array.
2021-07-23 11:58:50 +02:00
if ( ARRAY_A === $output ) {
2019-11-02 10:38:58 +01:00
foreach ( $results as $key => $result ) {
$results [ $key ] = get_object_vars ( $result );
}
return $results ? $results : array ();
}
return $results ? $results : false ;
}
/**
2022-12-15 17:47:31 +01:00
* Inserts or update a post .
2019-11-02 10:38:58 +01:00
*
* If the $postarr parameter has 'ID' set to a value , then post will be updated .
*
* You can set the post date manually , by setting the values for 'post_date'
* and 'post_date_gmt' keys . You can close the comments or open the comments by
* setting the value for 'comment_status' key .
*
* @ since 1.0 . 0
2020-12-10 14:06:04 +01:00
* @ since 2.6 . 0 Added the `$wp_error` parameter to allow a WP_Error to be returned on failure .
2019-11-02 10:38:58 +01:00
* @ since 4.2 . 0 Support was added for encoding emoji in the post title , content , and excerpt .
* @ since 4.4 . 0 A 'meta_input' array can now be passed to `$postarr` to add post meta data .
2020-12-10 14:06:04 +01:00
* @ since 5.6 . 0 Added the `$fire_after_hooks` parameter .
2019-11-02 10:38:58 +01:00
*
* @ see sanitize_post ()
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param array $postarr {
* An array of elements that make up a post to update or insert .
*
* @ type int $ID The post ID . If equal to something other than 0 ,
* the post with that ID will be updated . Default 0.
* @ type int $post_author The ID of the user who added the post . Default is
* the current user ID .
* @ type string $post_date The date of the post . Default is the current time .
* @ type string $post_date_gmt The date of the post in the GMT timezone . Default is
* the value of `$post_date` .
2022-04-02 10:26:41 +02:00
* @ type string $post_content The post content . Default empty .
2019-11-02 10:38:58 +01:00
* @ type string $post_content_filtered The filtered post content . Default empty .
* @ type string $post_title The post title . Default empty .
* @ type string $post_excerpt The post excerpt . Default empty .
* @ type string $post_status The post status . Default 'draft' .
* @ type string $post_type The post type . Default 'post' .
* @ type string $comment_status Whether the post can accept comments . Accepts 'open' or 'closed' .
* Default is the value of 'default_comment_status' option .
* @ type string $ping_status Whether the post can accept pings . Accepts 'open' or 'closed' .
* Default is the value of 'default_ping_status' option .
* @ type string $post_password The password to access the post . Default empty .
* @ type string $post_name The post name . Default is the sanitized post title
* when creating a new post .
* @ type string $to_ping Space or carriage return - separated list of URLs to ping .
* Default empty .
* @ type string $pinged Space or carriage return - separated list of URLs that have
* been pinged . Default empty .
* @ type int $post_parent Set this for the post it belongs to , if any . Default 0.
* @ type int $menu_order The order the post should be displayed in . Default 0.
* @ type string $post_mime_type The mime type of the post . Default empty .
* @ type string $guid Global Unique ID for referencing the post . Default empty .
2021-07-23 11:58:50 +02:00
* @ type int $import_id The post ID to be used when inserting a new post .
* If specified , must not match any existing post ID . Default 0.
2021-04-27 08:32:47 +02:00
* @ type int [] $post_category Array of category IDs .
2019-11-02 10:38:58 +01:00
* Defaults to value of the 'default_category' option .
* @ type array $tags_input Array of tag names , slugs , or IDs . Default empty .
2022-04-02 10:26:41 +02:00
* @ type array $tax_input An array of taxonomy terms keyed by their taxonomy name .
* If the taxonomy is hierarchical , the term list needs to be
* either an array of term IDs or a comma - separated string of IDs .
* If the taxonomy is non - hierarchical , the term list can be an array
* that contains term names or slugs , or a comma - separated string
* of names or slugs . This is because , in hierarchical taxonomy ,
* child terms can have the same names with different parent terms ,
* so the only way to connect them is using ID . Default empty .
2019-11-02 10:38:58 +01:00
* @ type array $meta_input Array of post meta values keyed by their post meta key . Default empty .
2022-12-15 17:47:31 +01:00
* @ type string $page_template Page template to use .
2019-11-02 10:38:58 +01:00
* }
2020-12-10 14:06:04 +01:00
* @ param bool $wp_error Optional . Whether to return a WP_Error on failure . Default false .
* @ param bool $fire_after_hooks Optional . Whether to fire the after insert hooks . Default true .
2019-11-02 10:38:58 +01:00
* @ return int | WP_Error The post ID on success . The value 0 or WP_Error on failure .
*/
2020-12-10 14:06:04 +01:00
function wp_insert_post ( $postarr , $wp_error = false , $fire_after_hooks = true ) {
2019-11-02 10:38:58 +01:00
global $wpdb ;
2020-05-06 17:23:38 +02:00
// Capture original pre-sanitized array for passing into filters.
$unsanitized_postarr = $postarr ;
2019-11-02 10:38:58 +01:00
$user_id = get_current_user_id ();
$defaults = array (
'post_author' => $user_id ,
'post_content' => '' ,
'post_content_filtered' => '' ,
'post_title' => '' ,
'post_excerpt' => '' ,
'post_status' => 'draft' ,
'post_type' => 'post' ,
'comment_status' => '' ,
'ping_status' => '' ,
'post_password' => '' ,
'to_ping' => '' ,
'pinged' => '' ,
'post_parent' => 0 ,
'menu_order' => 0 ,
'guid' => '' ,
'import_id' => 0 ,
'context' => '' ,
2021-04-27 08:32:47 +02:00
'post_date' => '' ,
'post_date_gmt' => '' ,
2019-11-02 10:38:58 +01:00
);
$postarr = wp_parse_args ( $postarr , $defaults );
unset ( $postarr [ 'filter' ] );
$postarr = sanitize_post ( $postarr , 'db' );
// Are we updating or creating?
2023-04-26 17:39:43 +02:00
$post_id = 0 ;
2019-11-02 10:38:58 +01:00
$update = false ;
$guid = $postarr [ 'guid' ];
if ( ! empty ( $postarr [ 'ID' ] ) ) {
$update = true ;
// Get the post ID and GUID.
2023-04-26 17:39:43 +02:00
$post_id = $postarr [ 'ID' ];
$post_before = get_post ( $post_id );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( is_null ( $post_before ) ) {
if ( $wp_error ) {
return new WP_Error ( 'invalid_post' , __ ( 'Invalid post ID.' ) );
}
return 0 ;
}
2023-04-26 17:39:43 +02:00
$guid = get_post_field ( 'guid' , $post_id );
$previous_status = get_post_field ( 'post_status' , $post_id );
2019-11-02 10:38:58 +01:00
} else {
$previous_status = 'new' ;
2020-12-10 14:06:04 +01:00
$post_before = null ;
2019-11-02 10:38:58 +01:00
}
$post_type = empty ( $postarr [ 'post_type' ] ) ? 'post' : $postarr [ 'post_type' ];
$post_title = $postarr [ 'post_title' ];
$post_content = $postarr [ 'post_content' ];
$post_excerpt = $postarr [ 'post_excerpt' ];
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( isset ( $postarr [ 'post_name' ] ) ) {
$post_name = $postarr [ 'post_name' ];
} elseif ( $update ) {
// For an update, don't modify the post_name if it wasn't supplied as an argument.
$post_name = $post_before -> post_name ;
}
$maybe_empty = 'attachment' !== $post_type
&& ! $post_content && ! $post_title && ! $post_excerpt
&& post_type_supports ( $post_type , 'editor' )
&& post_type_supports ( $post_type , 'title' )
&& post_type_supports ( $post_type , 'excerpt' );
/**
* Filters whether the post should be considered " empty " .
*
* The post is considered " empty " if both :
* 1. The post type supports the title , editor , and excerpt fields
* 2. The title , editor , and excerpt fields are all empty
*
2020-09-15 14:29:22 +02:00
* Returning a truthy value from the filter will effectively short - circuit
* the new post being inserted and return 0. If $wp_error is true , a WP_Error
2019-11-02 10:38:58 +01:00
* will be returned instead .
*
* @ since 3.3 . 0
*
* @ param bool $maybe_empty Whether the post should be considered " empty " .
* @ param array $postarr Array of post data .
*/
if ( apply_filters ( 'wp_insert_post_empty_content' , $maybe_empty , $postarr ) ) {
if ( $wp_error ) {
return new WP_Error ( 'empty_content' , __ ( 'Content, title, and excerpt are empty.' ) );
} else {
return 0 ;
}
}
$post_status = empty ( $postarr [ 'post_status' ] ) ? 'draft' : $postarr [ 'post_status' ];
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( 'attachment' === $post_type && ! in_array ( $post_status , array ( 'inherit' , 'private' , 'trash' , 'auto-draft' ), true ) ) {
$post_status = 'inherit' ;
}
if ( ! empty ( $postarr [ 'post_category' ] ) ) {
// Filter out empty terms.
$post_category = array_filter ( $postarr [ 'post_category' ] );
2022-12-15 17:47:31 +01:00
} elseif ( $update && ! isset ( $postarr [ 'post_category' ] ) ) {
$post_category = $post_before -> post_category ;
2019-11-02 10:38:58 +01:00
}
// Make sure we set a valid category.
2020-09-15 14:29:22 +02:00
if ( empty ( $post_category ) || 0 === count ( $post_category ) || ! is_array ( $post_category ) ) {
2019-11-02 10:38:58 +01:00
// 'post' requires at least one category.
2020-09-15 14:29:22 +02:00
if ( 'post' === $post_type && 'auto-draft' !== $post_status ) {
2019-11-02 10:38:58 +01:00
$post_category = array ( get_option ( 'default_category' ) );
} else {
$post_category = array ();
}
}
/*
* Don ' t allow contributors to set the post slug for pending review posts .
*
* For new posts check the primitive capability , for updates check the meta capability .
*/
2022-12-15 17:47:31 +01:00
if ( 'pending' === $post_status ) {
$post_type_object = get_post_type_object ( $post_type );
2019-11-02 10:38:58 +01:00
2022-12-15 17:47:31 +01:00
if ( ! $update && $post_type_object && ! current_user_can ( $post_type_object -> cap -> publish_posts ) ) {
$post_name = '' ;
2023-04-26 17:39:43 +02:00
} elseif ( $update && ! current_user_can ( 'publish_post' , $post_id ) ) {
2022-12-15 17:47:31 +01:00
$post_name = '' ;
}
2019-11-02 10:38:58 +01:00
}
/*
* Create a valid post name . Drafts and pending posts are allowed to have
* an empty post name .
*/
if ( empty ( $post_name ) ) {
2020-09-15 14:29:22 +02:00
if ( ! in_array ( $post_status , array ( 'draft' , 'pending' , 'auto-draft' ), true ) ) {
2019-11-02 10:38:58 +01:00
$post_name = sanitize_title ( $post_title );
} else {
$post_name = '' ;
}
} else {
// On updates, we need to check to see if it's using the old, fixed sanitization context.
$check_name = sanitize_title ( $post_name , '' , 'old-save' );
2020-09-15 14:29:22 +02:00
2023-04-26 17:39:43 +02:00
if ( $update && strtolower ( urlencode ( $post_name ) ) == $check_name && get_post_field ( 'post_name' , $post_id ) == $check_name ) {
2019-11-02 10:38:58 +01:00
$post_name = $check_name ;
2023-04-26 17:39:43 +02:00
} else { // New post, or slug has changed.
2019-11-02 10:38:58 +01:00
$post_name = sanitize_title ( $post_name );
}
}
/*
2021-04-27 08:32:47 +02:00
* Resolve the post date from any provided post date or post date GMT strings ;
* if none are provided , the date will be set to now .
2019-11-02 10:38:58 +01:00
*/
2021-04-27 08:32:47 +02:00
$post_date = wp_resolve_post_date ( $postarr [ 'post_date' ], $postarr [ 'post_date_gmt' ] );
2022-12-15 17:47:31 +01:00
2021-04-27 08:32:47 +02:00
if ( ! $post_date ) {
2019-11-02 10:38:58 +01:00
if ( $wp_error ) {
return new WP_Error ( 'invalid_date' , __ ( 'Invalid date.' ) );
} else {
return 0 ;
}
}
2020-09-15 14:29:22 +02:00
if ( empty ( $postarr [ 'post_date_gmt' ] ) || '0000-00-00 00:00:00' === $postarr [ 'post_date_gmt' ] ) {
2019-11-15 22:59:44 +01:00
if ( ! in_array ( $post_status , get_post_stati ( array ( 'date_floating' => true ) ), true ) ) {
2019-11-02 10:38:58 +01:00
$post_date_gmt = get_gmt_from_date ( $post_date );
} else {
$post_date_gmt = '0000-00-00 00:00:00' ;
}
} else {
$post_date_gmt = $postarr [ 'post_date_gmt' ];
}
2020-09-15 14:29:22 +02:00
if ( $update || '0000-00-00 00:00:00' === $post_date ) {
2019-11-02 10:38:58 +01:00
$post_modified = current_time ( 'mysql' );
$post_modified_gmt = current_time ( 'mysql' , 1 );
} else {
$post_modified = $post_date ;
$post_modified_gmt = $post_date_gmt ;
}
if ( 'attachment' !== $post_type ) {
2020-01-26 12:53:20 +01:00
$now = gmdate ( 'Y-m-d H:i:s' );
2019-11-15 22:59:44 +01:00
if ( 'publish' === $post_status ) {
2020-01-26 12:53:20 +01:00
if ( strtotime ( $post_date_gmt ) - strtotime ( $now ) >= MINUTE_IN_SECONDS ) {
2019-11-02 10:38:58 +01:00
$post_status = 'future' ;
}
2019-11-15 22:59:44 +01:00
} elseif ( 'future' === $post_status ) {
2020-01-26 12:53:20 +01:00
if ( strtotime ( $post_date_gmt ) - strtotime ( $now ) < MINUTE_IN_SECONDS ) {
2019-11-02 10:38:58 +01:00
$post_status = 'publish' ;
}
}
}
// Comment status.
if ( empty ( $postarr [ 'comment_status' ] ) ) {
if ( $update ) {
$comment_status = 'closed' ;
} else {
$comment_status = get_default_comment_status ( $post_type );
}
} else {
$comment_status = $postarr [ 'comment_status' ];
}
// These variables are needed by compact() later.
$post_content_filtered = $postarr [ 'post_content_filtered' ];
$post_author = isset ( $postarr [ 'post_author' ] ) ? $postarr [ 'post_author' ] : $user_id ;
$ping_status = empty ( $postarr [ 'ping_status' ] ) ? get_default_comment_status ( $post_type , 'pingback' ) : $postarr [ 'ping_status' ];
$to_ping = isset ( $postarr [ 'to_ping' ] ) ? sanitize_trackback_urls ( $postarr [ 'to_ping' ] ) : '' ;
$pinged = isset ( $postarr [ 'pinged' ] ) ? $postarr [ 'pinged' ] : '' ;
$import_id = isset ( $postarr [ 'import_id' ] ) ? $postarr [ 'import_id' ] : 0 ;
/*
* The 'wp_insert_post_parent' filter expects all variables to be present .
* Previously , these variables would have already been extracted
*/
if ( isset ( $postarr [ 'menu_order' ] ) ) {
$menu_order = ( int ) $postarr [ 'menu_order' ];
} else {
$menu_order = 0 ;
}
$post_password = isset ( $postarr [ 'post_password' ] ) ? $postarr [ 'post_password' ] : '' ;
2020-09-15 14:29:22 +02:00
if ( 'private' === $post_status ) {
2019-11-02 10:38:58 +01:00
$post_password = '' ;
}
if ( isset ( $postarr [ 'post_parent' ] ) ) {
$post_parent = ( int ) $postarr [ 'post_parent' ];
} else {
$post_parent = 0 ;
}
$new_postarr = array_merge (
array (
2023-04-26 17:39:43 +02:00
'ID' => $post_id ,
2019-11-02 10:38:58 +01:00
),
compact ( array_diff ( array_keys ( $defaults ), array ( 'context' , 'filter' ) ) )
);
/**
* Filters the post parent -- used to check for and prevent hierarchy loops .
*
* @ since 3.1 . 0
*
* @ param int $post_parent Post parent ID .
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param array $new_postarr Array of parsed post data .
* @ param array $postarr Array of sanitized , but otherwise unmodified post data .
*/
2023-04-26 17:39:43 +02:00
$post_parent = apply_filters ( 'wp_insert_post_parent' , $post_parent , $post_id , $new_postarr , $postarr );
2019-11-02 10:38:58 +01:00
/*
* If the post is being untrashed and it has a desired slug stored in post meta ,
* reassign it .
*/
if ( 'trash' === $previous_status && 'trash' !== $post_status ) {
2023-04-26 17:39:43 +02:00
$desired_post_slug = get_post_meta ( $post_id , '_wp_desired_post_slug' , true );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( $desired_post_slug ) {
2023-04-26 17:39:43 +02:00
delete_post_meta ( $post_id , '_wp_desired_post_slug' );
2019-11-02 10:38:58 +01:00
$post_name = $desired_post_slug ;
}
}
// If a trashed post has the desired slug, change it and let this post have it.
if ( 'trash' !== $post_status && $post_name ) {
2020-05-06 17:23:38 +02:00
/**
* Filters whether or not to add a `__trashed` suffix to trashed posts that match the name of the updated post .
*
* @ since 5.4 . 0
*
* @ param bool $add_trashed_suffix Whether to attempt to add the suffix .
* @ param string $post_name The name of the post being updated .
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2020-05-06 17:23:38 +02:00
*/
2023-04-26 17:39:43 +02:00
$add_trashed_suffix = apply_filters ( 'add_trashed_suffix_to_trashed_posts' , true , $post_name , $post_id );
2020-05-06 17:23:38 +02:00
if ( $add_trashed_suffix ) {
2023-04-26 17:39:43 +02:00
wp_add_trashed_suffix_to_post_name_for_trashed_posts ( $post_name , $post_id );
2020-05-06 17:23:38 +02:00
}
2019-11-02 10:38:58 +01:00
}
// When trashing an existing post, change its slug to allow non-trashed posts to use it.
if ( 'trash' === $post_status && 'trash' !== $previous_status && 'new' !== $previous_status ) {
2023-04-26 17:39:43 +02:00
$post_name = wp_add_trashed_suffix_to_post_name_for_post ( $post_id );
2019-11-02 10:38:58 +01:00
}
2023-04-26 17:39:43 +02:00
$post_name = wp_unique_post_slug ( $post_name , $post_id , $post_status , $post_type , $post_parent );
2019-11-02 10:38:58 +01:00
// Don't unslash.
$post_mime_type = isset ( $postarr [ 'post_mime_type' ] ) ? $postarr [ 'post_mime_type' ] : '' ;
// Expected_slashed (everything!).
2022-12-15 17:47:31 +01:00
$data = compact (
'post_author' ,
'post_date' ,
'post_date_gmt' ,
'post_content' ,
'post_content_filtered' ,
'post_title' ,
'post_excerpt' ,
'post_status' ,
'post_type' ,
'comment_status' ,
'ping_status' ,
'post_password' ,
'post_name' ,
'to_ping' ,
'pinged' ,
'post_modified' ,
'post_modified_gmt' ,
'post_parent' ,
'menu_order' ,
'post_mime_type' ,
'guid'
);
2019-11-02 10:38:58 +01:00
$emoji_fields = array ( 'post_title' , 'post_content' , 'post_excerpt' );
foreach ( $emoji_fields as $emoji_field ) {
if ( isset ( $data [ $emoji_field ] ) ) {
$charset = $wpdb -> get_col_charset ( $wpdb -> posts , $emoji_field );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( 'utf8' === $charset ) {
$data [ $emoji_field ] = wp_encode_emoji ( $data [ $emoji_field ] );
}
}
}
if ( 'attachment' === $post_type ) {
/**
* Filters attachment post data before it is updated in or added to the database .
*
* @ since 3.9 . 0
2022-06-16 14:03:35 +02:00
* @ since 5.4 . 1 The `$unsanitized_postarr` parameter was added .
* @ since 6.0 . 0 The `$update` parameter was added .
2019-11-02 10:38:58 +01:00
*
2020-05-06 17:23:38 +02:00
* @ param array $data An array of slashed , sanitized , and processed attachment post data .
* @ param array $postarr An array of slashed and sanitized attachment post data , but not processed .
* @ param array $unsanitized_postarr An array of slashed yet * unsanitized * and unprocessed attachment post data
* as originally passed to wp_insert_post () .
2022-06-16 14:03:35 +02:00
* @ param bool $update Whether this is an existing attachment post being updated .
2019-11-02 10:38:58 +01:00
*/
2022-06-16 14:03:35 +02:00
$data = apply_filters ( 'wp_insert_attachment_data' , $data , $postarr , $unsanitized_postarr , $update );
2019-11-02 10:38:58 +01:00
} else {
/**
* Filters slashed post data just before it is inserted into the database .
*
* @ since 2.7 . 0
2022-06-16 14:03:35 +02:00
* @ since 5.4 . 1 The `$unsanitized_postarr` parameter was added .
* @ since 6.0 . 0 The `$update` parameter was added .
2019-11-02 10:38:58 +01:00
*
2020-05-06 17:23:38 +02:00
* @ param array $data An array of slashed , sanitized , and processed post data .
* @ param array $postarr An array of sanitized ( and slashed ) but otherwise unmodified post data .
* @ param array $unsanitized_postarr An array of slashed yet * unsanitized * and unprocessed post data as
* originally passed to wp_insert_post () .
2022-06-16 14:03:35 +02:00
* @ param bool $update Whether this is an existing post being updated .
2019-11-02 10:38:58 +01:00
*/
2022-06-16 14:03:35 +02:00
$data = apply_filters ( 'wp_insert_post_data' , $data , $postarr , $unsanitized_postarr , $update );
2019-11-02 10:38:58 +01:00
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
$data = wp_unslash ( $data );
2023-04-26 17:39:43 +02:00
$where = array ( 'ID' => $post_id );
2019-11-02 10:38:58 +01:00
if ( $update ) {
/**
* Fires immediately before an existing post is updated in the database .
*
* @ since 2.5 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param array $data Array of unslashed post data .
*/
2023-04-26 17:39:43 +02:00
do_action ( 'pre_post_update' , $post_id , $data );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( false === $wpdb -> update ( $wpdb -> posts , $data , $where ) ) {
if ( $wp_error ) {
2020-09-15 14:29:22 +02:00
if ( 'attachment' === $post_type ) {
$message = __ ( 'Could not update attachment in the database.' );
} else {
$message = __ ( 'Could not update post in the database.' );
}
return new WP_Error ( 'db_update_error' , $message , $wpdb -> last_error );
2019-11-02 10:38:58 +01:00
} else {
return 0 ;
}
}
} else {
// If there is a suggested ID, use it if not already present.
if ( ! empty ( $import_id ) ) {
$import_id = ( int ) $import_id ;
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( ! $wpdb -> get_var ( $wpdb -> prepare ( " SELECT ID FROM $wpdb->posts WHERE ID = %d " , $import_id ) ) ) {
$data [ 'ID' ] = $import_id ;
}
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( false === $wpdb -> insert ( $wpdb -> posts , $data ) ) {
if ( $wp_error ) {
2020-09-15 14:29:22 +02:00
if ( 'attachment' === $post_type ) {
$message = __ ( 'Could not insert attachment into the database.' );
} else {
$message = __ ( 'Could not insert post into the database.' );
}
return new WP_Error ( 'db_insert_error' , $message , $wpdb -> last_error );
2019-11-02 10:38:58 +01:00
} else {
return 0 ;
}
}
2020-09-15 14:29:22 +02:00
2023-04-26 17:39:43 +02:00
$post_id = ( int ) $wpdb -> insert_id ;
2019-11-02 10:38:58 +01:00
2023-04-26 17:39:43 +02:00
// Use the newly generated $post_id.
$where = array ( 'ID' => $post_id );
2019-11-02 10:38:58 +01:00
}
2020-09-15 14:29:22 +02:00
if ( empty ( $data [ 'post_name' ] ) && ! in_array ( $data [ 'post_status' ], array ( 'draft' , 'pending' , 'auto-draft' ), true ) ) {
2023-04-26 17:39:43 +02:00
$data [ 'post_name' ] = wp_unique_post_slug ( sanitize_title ( $data [ 'post_title' ], $post_id ), $post_id , $data [ 'post_status' ], $post_type , $post_parent );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
$wpdb -> update ( $wpdb -> posts , array ( 'post_name' => $data [ 'post_name' ] ), $where );
2023-04-26 17:39:43 +02:00
clean_post_cache ( $post_id );
2019-11-02 10:38:58 +01:00
}
if ( is_object_in_taxonomy ( $post_type , 'category' ) ) {
2023-04-26 17:39:43 +02:00
wp_set_post_categories ( $post_id , $post_category );
2019-11-02 10:38:58 +01:00
}
if ( isset ( $postarr [ 'tags_input' ] ) && is_object_in_taxonomy ( $post_type , 'post_tag' ) ) {
2023-04-26 17:39:43 +02:00
wp_set_post_tags ( $post_id , $postarr [ 'tags_input' ] );
2019-11-02 10:38:58 +01:00
}
2020-09-15 14:29:22 +02:00
// Add default term for all associated custom taxonomies.
if ( 'auto-draft' !== $post_status ) {
foreach ( get_object_taxonomies ( $post_type , 'object' ) as $taxonomy => $tax_object ) {
if ( ! empty ( $tax_object -> default_term ) ) {
// Filter out empty terms.
2020-11-18 09:08:48 +01:00
if ( isset ( $postarr [ 'tax_input' ][ $taxonomy ] ) && is_array ( $postarr [ 'tax_input' ][ $taxonomy ] ) ) {
2020-09-15 14:29:22 +02:00
$postarr [ 'tax_input' ][ $taxonomy ] = array_filter ( $postarr [ 'tax_input' ][ $taxonomy ] );
}
// Passed custom taxonomy list overwrites the existing list if not empty.
2023-04-26 17:39:43 +02:00
$terms = wp_get_object_terms ( $post_id , $taxonomy , array ( 'fields' => 'ids' ) );
2020-09-15 14:29:22 +02:00
if ( ! empty ( $terms ) && empty ( $postarr [ 'tax_input' ][ $taxonomy ] ) ) {
$postarr [ 'tax_input' ][ $taxonomy ] = $terms ;
}
if ( empty ( $postarr [ 'tax_input' ][ $taxonomy ] ) ) {
$default_term_id = get_option ( 'default_term_' . $taxonomy );
if ( ! empty ( $default_term_id ) ) {
$postarr [ 'tax_input' ][ $taxonomy ] = array ( ( int ) $default_term_id );
}
}
}
}
}
2019-11-02 10:38:58 +01:00
// New-style support for all custom taxonomies.
if ( ! empty ( $postarr [ 'tax_input' ] ) ) {
foreach ( $postarr [ 'tax_input' ] as $taxonomy => $tags ) {
$taxonomy_obj = get_taxonomy ( $taxonomy );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( ! $taxonomy_obj ) {
2019-11-15 22:59:44 +01:00
/* translators: %s: Taxonomy name. */
2019-11-02 10:38:58 +01:00
_doing_it_wrong ( __FUNCTION__ , sprintf ( __ ( 'Invalid taxonomy: %s.' ), $taxonomy ), '4.4.0' );
continue ;
}
// array = hierarchical, string = non-hierarchical.
if ( is_array ( $tags ) ) {
$tags = array_filter ( $tags );
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( current_user_can ( $taxonomy_obj -> cap -> assign_terms ) ) {
2023-04-26 17:39:43 +02:00
wp_set_post_terms ( $post_id , $tags , $taxonomy );
2019-11-02 10:38:58 +01:00
}
}
}
if ( ! empty ( $postarr [ 'meta_input' ] ) ) {
foreach ( $postarr [ 'meta_input' ] as $field => $value ) {
2023-04-26 17:39:43 +02:00
update_post_meta ( $post_id , $field , $value );
2019-11-02 10:38:58 +01:00
}
}
2023-04-26 17:39:43 +02:00
$current_guid = get_post_field ( 'guid' , $post_id );
2019-11-02 10:38:58 +01:00
// Set GUID.
2020-09-15 14:29:22 +02:00
if ( ! $update && '' === $current_guid ) {
2023-04-26 17:39:43 +02:00
$wpdb -> update ( $wpdb -> posts , array ( 'guid' => get_permalink ( $post_id ) ), $where );
2019-11-02 10:38:58 +01:00
}
if ( 'attachment' === $postarr [ 'post_type' ] ) {
if ( ! empty ( $postarr [ 'file' ] ) ) {
2023-04-26 17:39:43 +02:00
update_attached_file ( $post_id , $postarr [ 'file' ] );
2019-11-02 10:38:58 +01:00
}
if ( ! empty ( $postarr [ 'context' ] ) ) {
2023-04-26 17:39:43 +02:00
add_post_meta ( $post_id , '_wp_attachment_context' , $postarr [ 'context' ], true );
2019-11-02 10:38:58 +01:00
}
}
// Set or remove featured image.
if ( isset ( $postarr [ '_thumbnail_id' ] ) ) {
$thumbnail_support = current_theme_supports ( 'post-thumbnails' , $post_type ) && post_type_supports ( $post_type , 'thumbnail' ) || 'revision' === $post_type ;
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( ! $thumbnail_support && 'attachment' === $post_type && $post_mime_type ) {
2023-04-26 17:39:43 +02:00
if ( wp_attachment_is ( 'audio' , $post_id ) ) {
2019-11-02 10:38:58 +01:00
$thumbnail_support = post_type_supports ( 'attachment:audio' , 'thumbnail' ) || current_theme_supports ( 'post-thumbnails' , 'attachment:audio' );
2023-04-26 17:39:43 +02:00
} elseif ( wp_attachment_is ( 'video' , $post_id ) ) {
2019-11-02 10:38:58 +01:00
$thumbnail_support = post_type_supports ( 'attachment:video' , 'thumbnail' ) || current_theme_supports ( 'post-thumbnails' , 'attachment:video' );
}
}
if ( $thumbnail_support ) {
2020-12-10 14:06:04 +01:00
$thumbnail_id = ( int ) $postarr [ '_thumbnail_id' ];
2019-11-02 10:38:58 +01:00
if ( - 1 === $thumbnail_id ) {
2023-04-26 17:39:43 +02:00
delete_post_thumbnail ( $post_id );
2019-11-02 10:38:58 +01:00
} else {
2023-04-26 17:39:43 +02:00
set_post_thumbnail ( $post_id , $thumbnail_id );
2019-11-02 10:38:58 +01:00
}
}
}
2023-04-26 17:39:43 +02:00
clean_post_cache ( $post_id );
2019-11-02 10:38:58 +01:00
2023-04-26 17:39:43 +02:00
$post = get_post ( $post_id );
2019-11-02 10:38:58 +01:00
if ( ! empty ( $postarr [ 'page_template' ] ) ) {
$post -> page_template = $postarr [ 'page_template' ];
$page_templates = wp_get_theme () -> get_page_templates ( $post );
2020-09-15 14:29:22 +02:00
if ( 'default' !== $postarr [ 'page_template' ] && ! isset ( $page_templates [ $postarr [ 'page_template' ] ] ) ) {
2019-11-02 10:38:58 +01:00
if ( $wp_error ) {
return new WP_Error ( 'invalid_page_template' , __ ( 'Invalid page template.' ) );
}
2020-09-15 14:29:22 +02:00
2023-04-26 17:39:43 +02:00
update_post_meta ( $post_id , '_wp_page_template' , 'default' );
2019-11-02 10:38:58 +01:00
} else {
2023-04-26 17:39:43 +02:00
update_post_meta ( $post_id , '_wp_page_template' , $postarr [ 'page_template' ] );
2019-11-02 10:38:58 +01:00
}
}
if ( 'attachment' !== $postarr [ 'post_type' ] ) {
wp_transition_post_status ( $data [ 'post_status' ], $previous_status , $post );
} else {
if ( $update ) {
/**
* Fires once an existing attachment has been updated .
*
* @ since 2.0 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Attachment ID .
2019-11-02 10:38:58 +01:00
*/
2023-04-26 17:39:43 +02:00
do_action ( 'edit_attachment' , $post_id );
2020-09-15 14:29:22 +02:00
2023-04-26 17:39:43 +02:00
$post_after = get_post ( $post_id );
2019-11-02 10:38:58 +01:00
/**
* Fires once an existing attachment has been updated .
*
* @ since 4.4 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param WP_Post $post_after Post object following the update .
* @ param WP_Post $post_before Post object before the update .
*/
2023-04-26 17:39:43 +02:00
do_action ( 'attachment_updated' , $post_id , $post_after , $post_before );
2019-11-02 10:38:58 +01:00
} else {
/**
* Fires once an attachment has been added .
*
* @ since 2.0 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Attachment ID .
2019-11-02 10:38:58 +01:00
*/
2023-04-26 17:39:43 +02:00
do_action ( 'add_attachment' , $post_id );
2019-11-02 10:38:58 +01:00
}
2023-04-26 17:39:43 +02:00
return $post_id ;
2019-11-02 10:38:58 +01:00
}
if ( $update ) {
/**
* Fires once an existing post has been updated .
*
* The dynamic portion of the hook name , `$post->post_type` , refers to
* the post type slug .
*
2022-04-02 10:26:41 +02:00
* Possible hook names include :
*
* - `edit_post_post`
* - `edit_post_page`
*
2019-11-02 10:38:58 +01:00
* @ since 5.1 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param WP_Post $post Post object .
*/
2023-04-26 17:39:43 +02:00
do_action ( " edit_post_ { $post -> post_type } " , $post_id , $post );
2019-11-02 10:38:58 +01:00
/**
* Fires once an existing post has been updated .
*
* @ since 1.2 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param WP_Post $post Post object .
*/
2023-04-26 17:39:43 +02:00
do_action ( 'edit_post' , $post_id , $post );
2019-11-02 10:38:58 +01:00
2023-04-26 17:39:43 +02:00
$post_after = get_post ( $post_id );
2019-11-02 10:38:58 +01:00
/**
* Fires once an existing post has been updated .
*
* @ since 3.0 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param WP_Post $post_after Post object following the update .
* @ param WP_Post $post_before Post object before the update .
*/
2023-04-26 17:39:43 +02:00
do_action ( 'post_updated' , $post_id , $post_after , $post_before );
2019-11-02 10:38:58 +01:00
}
/**
* Fires once a post has been saved .
*
* The dynamic portion of the hook name , `$post->post_type` , refers to
* the post type slug .
*
2022-04-02 10:26:41 +02:00
* Possible hook names include :
*
* - `save_post_post`
* - `save_post_page`
*
2019-11-02 10:38:58 +01:00
* @ since 3.7 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param WP_Post $post Post object .
2020-09-15 14:29:22 +02:00
* @ param bool $update Whether this is an existing post being updated .
2019-11-02 10:38:58 +01:00
*/
2023-04-26 17:39:43 +02:00
do_action ( " save_post_ { $post -> post_type } " , $post_id , $post , $update );
2019-11-02 10:38:58 +01:00
/**
* Fires once a post has been saved .
*
* @ since 1.5 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param WP_Post $post Post object .
2020-09-15 14:29:22 +02:00
* @ param bool $update Whether this is an existing post being updated .
2019-11-02 10:38:58 +01:00
*/
2023-04-26 17:39:43 +02:00
do_action ( 'save_post' , $post_id , $post , $update );
2019-11-02 10:38:58 +01:00
/**
* Fires once a post has been saved .
*
* @ since 2.0 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param WP_Post $post Post object .
2020-09-15 14:29:22 +02:00
* @ param bool $update Whether this is an existing post being updated .
2019-11-02 10:38:58 +01:00
*/
2023-04-26 17:39:43 +02:00
do_action ( 'wp_insert_post' , $post_id , $post , $update );
2019-11-02 10:38:58 +01:00
2020-12-10 14:06:04 +01:00
if ( $fire_after_hooks ) {
wp_after_insert_post ( $post , $update , $post_before );
}
2023-04-26 17:39:43 +02:00
return $post_id ;
2019-11-02 10:38:58 +01:00
}
/**
2022-12-15 17:47:31 +01:00
* Updates a post with new post data .
2019-11-02 10:38:58 +01:00
*
* The date does not have to be set for drafts . You can set the date and it will
* not be overridden .
*
* @ since 1.0 . 0
2020-12-10 14:06:04 +01:00
* @ since 3.5 . 0 Added the `$wp_error` parameter to allow a WP_Error to be returned on failure .
* @ since 5.6 . 0 Added the `$fire_after_hooks` parameter .
*
* @ param array | object $postarr Optional . Post data . Arrays are expected to be escaped ,
* objects are not . See wp_insert_post () for accepted arguments .
* Default array .
* @ param bool $wp_error Optional . Whether to return a WP_Error on failure . Default false .
* @ param bool $fire_after_hooks Optional . Whether to fire the after insert hooks . Default true .
2020-05-06 17:23:38 +02:00
* @ return int | WP_Error The post ID on success . The value 0 or WP_Error on failure .
2019-11-02 10:38:58 +01:00
*/
2020-12-10 14:06:04 +01:00
function wp_update_post ( $postarr = array (), $wp_error = false , $fire_after_hooks = true ) {
2019-11-02 10:38:58 +01:00
if ( is_object ( $postarr ) ) {
// Non-escaped post was passed.
$postarr = get_object_vars ( $postarr );
$postarr = wp_slash ( $postarr );
}
// First, get all of the original fields.
$post = get_post ( $postarr [ 'ID' ], ARRAY_A );
if ( is_null ( $post ) ) {
if ( $wp_error ) {
return new WP_Error ( 'invalid_post' , __ ( 'Invalid post ID.' ) );
}
return 0 ;
}
// Escape data pulled from DB.
$post = wp_slash ( $post );
// Passed post category list overwrites existing category list if not empty.
if ( isset ( $postarr [ 'post_category' ] ) && is_array ( $postarr [ 'post_category' ] )
2020-09-15 14:29:22 +02:00
&& count ( $postarr [ 'post_category' ] ) > 0
) {
2019-11-02 10:38:58 +01:00
$post_cats = $postarr [ 'post_category' ];
} else {
$post_cats = $post [ 'post_category' ];
}
// Drafts shouldn't be assigned a date unless explicitly done so by the user.
2020-09-15 14:29:22 +02:00
if ( isset ( $post [ 'post_status' ] )
&& in_array ( $post [ 'post_status' ], array ( 'draft' , 'pending' , 'auto-draft' ), true )
&& empty ( $postarr [ 'edit_date' ] ) && ( '0000-00-00 00:00:00' === $post [ 'post_date_gmt' ] )
) {
2019-11-02 10:38:58 +01:00
$clear_date = true ;
} else {
$clear_date = false ;
}
// Merge old and new fields with new fields overwriting old ones.
$postarr = array_merge ( $post , $postarr );
$postarr [ 'post_category' ] = $post_cats ;
if ( $clear_date ) {
$postarr [ 'post_date' ] = current_time ( 'mysql' );
$postarr [ 'post_date_gmt' ] = '' ;
}
2020-05-06 17:23:38 +02:00
if ( 'attachment' === $postarr [ 'post_type' ] ) {
2019-11-02 10:38:58 +01:00
return wp_insert_attachment ( $postarr , false , 0 , $wp_error );
}
2020-05-06 17:23:38 +02:00
// Discard 'tags_input' parameter if it's the same as existing post tags.
if ( isset ( $postarr [ 'tags_input' ] ) && is_object_in_taxonomy ( $postarr [ 'post_type' ], 'post_tag' ) ) {
$tags = get_the_terms ( $postarr [ 'ID' ], 'post_tag' );
$tag_names = array ();
if ( $tags && ! is_wp_error ( $tags ) ) {
$tag_names = wp_list_pluck ( $tags , 'name' );
}
if ( $postarr [ 'tags_input' ] === $tag_names ) {
unset ( $postarr [ 'tags_input' ] );
}
}
2020-12-10 14:06:04 +01:00
return wp_insert_post ( $postarr , $wp_error , $fire_after_hooks );
2019-11-02 10:38:58 +01:00
}
/**
2022-12-15 17:47:31 +01:00
* Publishes a post by transitioning the post status .
2019-11-02 10:38:58 +01:00
*
* @ since 2.1 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param int | WP_Post $post Post ID or post object .
*/
function wp_publish_post ( $post ) {
global $wpdb ;
2019-11-15 22:59:44 +01:00
$post = get_post ( $post );
2020-12-10 14:06:04 +01:00
2019-11-15 22:59:44 +01:00
if ( ! $post ) {
2019-11-02 10:38:58 +01:00
return ;
}
2020-09-15 14:29:22 +02:00
if ( 'publish' === $post -> post_status ) {
2019-11-02 10:38:58 +01:00
return ;
}
2020-12-10 14:06:04 +01:00
$post_before = get_post ( $post -> ID );
// Ensure at least one term is applied for taxonomies with a default term.
foreach ( get_object_taxonomies ( $post -> post_type , 'object' ) as $taxonomy => $tax_object ) {
// Skip taxonomy if no default term is set.
if (
'category' !== $taxonomy &&
empty ( $tax_object -> default_term )
) {
continue ;
}
// Do not modify previously set terms.
if ( ! empty ( get_the_terms ( $post , $taxonomy ) ) ) {
continue ;
}
if ( 'category' === $taxonomy ) {
$default_term_id = ( int ) get_option ( 'default_category' , 0 );
} else {
$default_term_id = ( int ) get_option ( 'default_term_' . $taxonomy , 0 );
}
if ( ! $default_term_id ) {
continue ;
}
wp_set_post_terms ( $post -> ID , array ( $default_term_id ), $taxonomy );
}
2019-11-02 10:38:58 +01:00
$wpdb -> update ( $wpdb -> posts , array ( 'post_status' => 'publish' ), array ( 'ID' => $post -> ID ) );
clean_post_cache ( $post -> ID );
$old_status = $post -> post_status ;
$post -> post_status = 'publish' ;
wp_transition_post_status ( 'publish' , $old_status , $post );
/** This action is documented in wp-includes/post.php */
do_action ( " edit_post_ { $post -> post_type } " , $post -> ID , $post );
/** This action is documented in wp-includes/post.php */
do_action ( 'edit_post' , $post -> ID , $post );
/** This action is documented in wp-includes/post.php */
do_action ( " save_post_ { $post -> post_type } " , $post -> ID , $post , true );
/** This action is documented in wp-includes/post.php */
do_action ( 'save_post' , $post -> ID , $post , true );
/** This action is documented in wp-includes/post.php */
do_action ( 'wp_insert_post' , $post -> ID , $post , true );
2020-12-10 14:06:04 +01:00
wp_after_insert_post ( $post , true , $post_before );
2019-11-02 10:38:58 +01:00
}
/**
2022-12-15 17:47:31 +01:00
* Publishes future post and make sure post ID has future post status .
2019-11-02 10:38:58 +01:00
*
* Invoked by cron 'publish_future_post' event . This safeguard prevents cron
* from publishing drafts , etc .
*
* @ since 2.5 . 0
*
2022-12-15 17:47:31 +01:00
* @ param int | WP_Post $post Post ID or post object .
2019-11-02 10:38:58 +01:00
*/
2022-12-15 17:47:31 +01:00
function check_and_publish_future_post ( $post ) {
$post = get_post ( $post );
2019-11-02 10:38:58 +01:00
2020-12-10 14:06:04 +01:00
if ( ! $post ) {
2019-11-02 10:38:58 +01:00
return ;
}
2020-09-15 14:29:22 +02:00
if ( 'future' !== $post -> post_status ) {
2019-11-02 10:38:58 +01:00
return ;
}
$time = strtotime ( $post -> post_date_gmt . ' GMT' );
// Uh oh, someone jumped the gun!
if ( $time > time () ) {
2022-12-15 17:47:31 +01:00
wp_clear_scheduled_hook ( 'publish_future_post' , array ( $post -> ID ) ); // Clear anything else in the system.
wp_schedule_single_event ( $time , 'publish_future_post' , array ( $post -> ID ) );
2019-11-02 10:38:58 +01:00
return ;
}
// wp_publish_post() returns no meaningful value.
2022-12-15 17:47:31 +01:00
wp_publish_post ( $post -> ID );
2019-11-02 10:38:58 +01:00
}
2021-04-27 08:32:47 +02:00
/**
* Uses wp_checkdate to return a valid Gregorian - calendar value for post_date .
* If post_date is not provided , this first checks post_date_gmt if provided ,
* then falls back to use the current time .
*
* For back - compat purposes in wp_insert_post , an empty post_date and an invalid
* post_date_gmt will continue to return '1970-01-01 00:00:00' rather than false .
*
* @ since 5.7 . 0
*
* @ param string $post_date The date in mysql format .
* @ param string $post_date_gmt The GMT date in mysql format .
* @ return string | false A valid Gregorian - calendar date string , or false on failure .
*/
function wp_resolve_post_date ( $post_date = '' , $post_date_gmt = '' ) {
// If the date is empty, set the date to now.
if ( empty ( $post_date ) || '0000-00-00 00:00:00' === $post_date ) {
if ( empty ( $post_date_gmt ) || '0000-00-00 00:00:00' === $post_date_gmt ) {
$post_date = current_time ( 'mysql' );
} else {
$post_date = get_date_from_gmt ( $post_date_gmt );
}
}
// Validate the date.
2022-12-15 17:47:31 +01:00
$month = ( int ) substr ( $post_date , 5 , 2 );
$day = ( int ) substr ( $post_date , 8 , 2 );
$year = ( int ) substr ( $post_date , 0 , 4 );
2021-04-27 08:32:47 +02:00
$valid_date = wp_checkdate ( $month , $day , $year , $post_date );
if ( ! $valid_date ) {
return false ;
}
return $post_date ;
}
2019-11-02 10:38:58 +01:00
/**
* Computes a unique slug for the post , when given the desired slug and some post details .
*
* @ since 2.8 . 0
*
2019-11-15 22:59:44 +01:00
* @ global wpdb $wpdb WordPress database abstraction object .
* @ global WP_Rewrite $wp_rewrite WordPress rewrite component .
2019-11-02 10:38:58 +01:00
*
* @ param string $slug The desired slug ( post_name ) .
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param string $post_status No uniqueness checks are made if the post is still draft or pending .
* @ param string $post_type Post type .
* @ param int $post_parent Post parent ID .
* @ return string Unique slug for the post , based on $post_name ( with a - 1 , - 2 , etc . suffix )
*/
2023-04-26 17:39:43 +02:00
function wp_unique_post_slug ( $slug , $post_id , $post_status , $post_type , $post_parent ) {
2020-09-15 14:29:22 +02:00
if ( in_array ( $post_status , array ( 'draft' , 'pending' , 'auto-draft' ), true )
|| ( 'inherit' === $post_status && 'revision' === $post_type ) || 'user_request' === $post_type
) {
2019-11-02 10:38:58 +01:00
return $slug ;
}
/**
* Filters the post slug before it is generated to be unique .
*
* Returning a non - null value will short - circuit the
* unique slug generation , returning the passed value instead .
*
* @ since 5.1 . 0
*
2019-11-15 22:59:44 +01:00
* @ param string | null $override_slug Short - circuit return value .
* @ param string $slug The desired slug ( post_name ) .
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-15 22:59:44 +01:00
* @ param string $post_status The post status .
* @ param string $post_type Post type .
* @ param int $post_parent Post parent ID .
2019-11-02 10:38:58 +01:00
*/
2023-04-26 17:39:43 +02:00
$override_slug = apply_filters ( 'pre_wp_unique_post_slug' , null , $slug , $post_id , $post_status , $post_type , $post_parent );
2019-11-02 10:38:58 +01:00
if ( null !== $override_slug ) {
return $override_slug ;
}
global $wpdb , $wp_rewrite ;
$original_slug = $slug ;
$feeds = $wp_rewrite -> feeds ;
if ( ! is_array ( $feeds ) ) {
$feeds = array ();
}
2020-09-15 14:29:22 +02:00
if ( 'attachment' === $post_type ) {
2019-11-02 10:38:58 +01:00
// Attachment slugs must be unique across all types.
$check_sql = " SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d LIMIT 1 " ;
2023-04-26 17:39:43 +02:00
$post_name_check = $wpdb -> get_var ( $wpdb -> prepare ( $check_sql , $slug , $post_id ) );
2019-11-02 10:38:58 +01:00
/**
* Filters whether the post slug would make a bad attachment slug .
*
* @ since 3.1 . 0
*
* @ param bool $bad_slug Whether the slug would be bad as an attachment slug .
* @ param string $slug The post slug .
*/
2020-09-15 14:29:22 +02:00
$is_bad_attachment_slug = apply_filters ( 'wp_unique_post_slug_is_bad_attachment_slug' , false , $slug );
if ( $post_name_check
|| in_array ( $slug , $feeds , true ) || 'embed' === $slug
|| $is_bad_attachment_slug
) {
2019-11-02 10:38:58 +01:00
$suffix = 2 ;
do {
$alt_post_name = _truncate_post_slug ( $slug , 200 - ( strlen ( $suffix ) + 1 ) ) . " - $suffix " ;
2023-04-26 17:39:43 +02:00
$post_name_check = $wpdb -> get_var ( $wpdb -> prepare ( $check_sql , $alt_post_name , $post_id ) );
2019-11-02 10:38:58 +01:00
$suffix ++ ;
} while ( $post_name_check );
$slug = $alt_post_name ;
}
} elseif ( is_post_type_hierarchical ( $post_type ) ) {
2020-09-15 14:29:22 +02:00
if ( 'nav_menu_item' === $post_type ) {
2019-11-02 10:38:58 +01:00
return $slug ;
}
/*
* Page slugs must be unique within their own trees . Pages are in a separate
* namespace than posts so page slugs are allowed to overlap post slugs .
*/
$check_sql = " SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type IN ( %s, 'attachment' ) AND ID != %d AND post_parent = %d LIMIT 1 " ;
2023-04-26 17:39:43 +02:00
$post_name_check = $wpdb -> get_var ( $wpdb -> prepare ( $check_sql , $slug , $post_type , $post_id , $post_parent ) );
2019-11-02 10:38:58 +01:00
/**
* Filters whether the post slug would make a bad hierarchical post slug .
*
* @ since 3.1 . 0
*
* @ param bool $bad_slug Whether the post slug would be bad in a hierarchical post context .
* @ param string $slug The post slug .
* @ param string $post_type Post type .
* @ param int $post_parent Post parent ID .
*/
2020-09-15 14:29:22 +02:00
$is_bad_hierarchical_slug = apply_filters ( 'wp_unique_post_slug_is_bad_hierarchical_slug' , false , $slug , $post_type , $post_parent );
if ( $post_name_check
|| in_array ( $slug , $feeds , true ) || 'embed' === $slug
|| preg_match ( " @^( $wp_rewrite->pagination_base )? \ d+ $ @ " , $slug )
|| $is_bad_hierarchical_slug
) {
2019-11-02 10:38:58 +01:00
$suffix = 2 ;
do {
$alt_post_name = _truncate_post_slug ( $slug , 200 - ( strlen ( $suffix ) + 1 ) ) . " - $suffix " ;
2023-04-26 17:39:43 +02:00
$post_name_check = $wpdb -> get_var ( $wpdb -> prepare ( $check_sql , $alt_post_name , $post_type , $post_id , $post_parent ) );
2019-11-02 10:38:58 +01:00
$suffix ++ ;
} while ( $post_name_check );
$slug = $alt_post_name ;
}
} else {
// Post slugs must be unique across all posts.
$check_sql = " SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1 " ;
2023-04-26 17:39:43 +02:00
$post_name_check = $wpdb -> get_var ( $wpdb -> prepare ( $check_sql , $slug , $post_type , $post_id ) );
2019-11-02 10:38:58 +01:00
2023-04-26 17:39:43 +02:00
$post = get_post ( $post_id );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
// Prevent new post slugs that could result in URLs that conflict with date archives.
$conflicts_with_date_archive = false ;
2019-11-15 22:59:44 +01:00
if ( 'post' === $post_type && ( ! $post || $post -> post_name !== $slug ) && preg_match ( '/^[0-9]+$/' , $slug ) ) {
2020-12-10 14:06:04 +01:00
$slug_num = ( int ) $slug ;
2019-11-15 22:59:44 +01:00
if ( $slug_num ) {
$permastructs = array_values ( array_filter ( explode ( '/' , get_option ( 'permalink_structure' ) ) ) );
2020-09-15 14:29:22 +02:00
$postname_index = array_search ( '%postname%' , $permastructs , true );
2019-11-15 22:59:44 +01:00
/*
* Potential date clashes are as follows :
*
* - Any integer in the first permastruct position could be a year .
* - An integer between 1 and 12 that follows 'year' conflicts with 'monthnum' .
* - An integer between 1 and 31 that follows 'monthnum' conflicts with 'day' .
*/
if ( 0 === $postname_index ||
( $postname_index && '%year%' === $permastructs [ $postname_index - 1 ] && 13 > $slug_num ) ||
( $postname_index && '%monthnum%' === $permastructs [ $postname_index - 1 ] && 32 > $slug_num )
) {
$conflicts_with_date_archive = true ;
}
2019-11-02 10:38:58 +01:00
}
}
/**
* Filters whether the post slug would be bad as a flat slug .
*
* @ since 3.1 . 0
*
* @ param bool $bad_slug Whether the post slug would be bad as a flat slug .
* @ param string $slug The post slug .
* @ param string $post_type Post type .
*/
2020-09-15 14:29:22 +02:00
$is_bad_flat_slug = apply_filters ( 'wp_unique_post_slug_is_bad_flat_slug' , false , $slug , $post_type );
if ( $post_name_check
|| in_array ( $slug , $feeds , true ) || 'embed' === $slug
|| $conflicts_with_date_archive
|| $is_bad_flat_slug
) {
2019-11-02 10:38:58 +01:00
$suffix = 2 ;
do {
$alt_post_name = _truncate_post_slug ( $slug , 200 - ( strlen ( $suffix ) + 1 ) ) . " - $suffix " ;
2023-04-26 17:39:43 +02:00
$post_name_check = $wpdb -> get_var ( $wpdb -> prepare ( $check_sql , $alt_post_name , $post_type , $post_id ) );
2019-11-02 10:38:58 +01:00
$suffix ++ ;
} while ( $post_name_check );
$slug = $alt_post_name ;
}
}
/**
* Filters the unique post slug .
*
* @ since 3.3 . 0
*
* @ param string $slug The post slug .
2023-04-26 17:39:43 +02:00
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
* @ param string $post_status The post status .
* @ param string $post_type Post type .
* @ param int $post_parent Post parent ID
* @ param string $original_slug The original post slug .
*/
2023-04-26 17:39:43 +02:00
return apply_filters ( 'wp_unique_post_slug' , $slug , $post_id , $post_status , $post_type , $post_parent , $original_slug );
2019-11-02 10:38:58 +01:00
}
/**
2022-12-15 17:47:31 +01:00
* Truncates a post slug .
2019-11-02 10:38:58 +01:00
*
* @ since 3.6 . 0
* @ access private
*
* @ see utf8_uri_encode ()
*
* @ param string $slug The slug to truncate .
* @ param int $length Optional . Max length of the slug . Default 200 ( characters ) .
* @ return string The truncated slug .
*/
function _truncate_post_slug ( $slug , $length = 200 ) {
if ( strlen ( $slug ) > $length ) {
$decoded_slug = urldecode ( $slug );
if ( $decoded_slug === $slug ) {
$slug = substr ( $slug , 0 , $length );
} else {
2022-04-02 10:26:41 +02:00
$slug = utf8_uri_encode ( $decoded_slug , $length , true );
2019-11-02 10:38:58 +01:00
}
}
return rtrim ( $slug , '-' );
}
/**
2022-12-15 17:47:31 +01:00
* Adds tags to a post .
2019-11-02 10:38:58 +01:00
*
* @ see wp_set_post_tags ()
*
* @ since 2.3 . 0
*
* @ param int $post_id Optional . The Post ID . Does not default to the ID of the global $post .
* @ param string | array $tags Optional . An array of tags to set for the post , or a string of tags
* separated by commas . Default empty .
* @ return array | false | WP_Error Array of affected term IDs . WP_Error or false on failure .
*/
function wp_add_post_tags ( $post_id = 0 , $tags = '' ) {
return wp_set_post_tags ( $post_id , $tags , true );
}
/**
2022-12-15 17:47:31 +01:00
* Sets the tags for a post .
2019-11-02 10:38:58 +01:00
*
* @ since 2.3 . 0
*
* @ see wp_set_object_terms ()
*
* @ param int $post_id Optional . The Post ID . Does not default to the ID of the global $post .
* @ param string | array $tags Optional . An array of tags to set for the post , or a string of tags
* separated by commas . Default empty .
* @ param bool $append Optional . If true , don ' t delete existing tags , just add on . If false ,
* replace the tags with the new tags . Default false .
* @ return array | false | WP_Error Array of term taxonomy IDs of affected terms . WP_Error or false on failure .
*/
function wp_set_post_tags ( $post_id = 0 , $tags = '' , $append = false ) {
return wp_set_post_terms ( $post_id , $tags , 'post_tag' , $append );
}
/**
2022-12-15 17:47:31 +01:00
* Sets the terms for a post .
2019-11-02 10:38:58 +01:00
*
* @ since 2.8 . 0
*
* @ see wp_set_object_terms ()
*
* @ param int $post_id Optional . The Post ID . Does not default to the ID of the global $post .
2022-12-15 17:47:31 +01:00
* @ param string | array $terms Optional . An array of terms to set for the post , or a string of terms
2019-11-02 10:38:58 +01:00
* separated by commas . Hierarchical taxonomies must always pass IDs rather
* than names so that children with the same names but different parents
* aren ' t confused . Default empty .
* @ param string $taxonomy Optional . Taxonomy name . Default 'post_tag' .
* @ param bool $append Optional . If true , don ' t delete existing terms , just add on . If false ,
* replace the terms with the new terms . Default false .
* @ return array | false | WP_Error Array of term taxonomy IDs of affected terms . WP_Error or false on failure .
*/
2022-12-15 17:47:31 +01:00
function wp_set_post_terms ( $post_id = 0 , $terms = '' , $taxonomy = 'post_tag' , $append = false ) {
2019-11-02 10:38:58 +01:00
$post_id = ( int ) $post_id ;
if ( ! $post_id ) {
return false ;
}
2022-12-15 17:47:31 +01:00
if ( empty ( $terms ) ) {
$terms = array ();
2019-11-02 10:38:58 +01:00
}
2022-12-15 17:47:31 +01:00
if ( ! is_array ( $terms ) ) {
2019-11-02 10:38:58 +01:00
$comma = _x ( ',' , 'tag delimiter' );
if ( ',' !== $comma ) {
2022-12-15 17:47:31 +01:00
$terms = str_replace ( $comma , ',' , $terms );
2019-11-02 10:38:58 +01:00
}
2022-12-15 17:47:31 +01:00
$terms = explode ( ',' , trim ( $terms , " \n \t \r \0 \x0B , " ) );
2019-11-02 10:38:58 +01:00
}
/*
* Hierarchical taxonomies must always pass IDs rather than names so that
* children with the same names but different parents aren ' t confused .
*/
if ( is_taxonomy_hierarchical ( $taxonomy ) ) {
2022-12-15 17:47:31 +01:00
$terms = array_unique ( array_map ( 'intval' , $terms ) );
2019-11-02 10:38:58 +01:00
}
2022-12-15 17:47:31 +01:00
return wp_set_object_terms ( $post_id , $terms , $taxonomy , $append );
2019-11-02 10:38:58 +01:00
}
/**
2022-12-15 17:47:31 +01:00
* Sets categories for a post .
2019-11-02 10:38:58 +01:00
*
2020-09-15 14:29:22 +02:00
* If no categories are provided , the default category is used .
2019-11-02 10:38:58 +01:00
*
* @ since 2.1 . 0
*
2023-04-26 17:39:43 +02:00
* @ param int $post_id Optional . The Post ID . Does not default to the ID
2019-11-02 10:38:58 +01:00
* of the global $post . Default 0.
2021-04-27 08:32:47 +02:00
* @ param int [] | int $post_categories Optional . List of category IDs , or the ID of a single category .
2019-11-02 10:38:58 +01:00
* Default empty array .
* @ param bool $append If true , don ' t delete existing categories , just add on .
* If false , replace the categories with the new categories .
* @ return array | false | WP_Error Array of term taxonomy IDs of affected categories . WP_Error or false on failure .
*/
2023-04-26 17:39:43 +02:00
function wp_set_post_categories ( $post_id = 0 , $post_categories = array (), $append = false ) {
$post_id = ( int ) $post_id ;
$post_type = get_post_type ( $post_id );
$post_status = get_post_status ( $post_id );
2020-09-15 14:29:22 +02:00
// If $post_categories isn't already an array, make it one.
2019-11-02 10:38:58 +01:00
$post_categories = ( array ) $post_categories ;
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( empty ( $post_categories ) ) {
2020-09-15 14:29:22 +02:00
/**
* Filters post types ( in addition to 'post' ) that require a default category .
*
* @ since 5.5 . 0
*
* @ param string [] $post_types An array of post type names . Default empty array .
*/
$default_category_post_types = apply_filters ( 'default_category_post_types' , array () );
// Regular posts always require a default category.
$default_category_post_types = array_merge ( $default_category_post_types , array ( 'post' ) );
if ( in_array ( $post_type , $default_category_post_types , true )
&& is_object_in_taxonomy ( $post_type , 'category' )
&& 'auto-draft' !== $post_status
) {
2019-11-02 10:38:58 +01:00
$post_categories = array ( get_option ( 'default_category' ) );
$append = false ;
} else {
$post_categories = array ();
}
2020-09-15 14:29:22 +02:00
} elseif ( 1 === count ( $post_categories ) && '' === reset ( $post_categories ) ) {
2019-11-02 10:38:58 +01:00
return true ;
}
2023-04-26 17:39:43 +02:00
return wp_set_post_terms ( $post_id , $post_categories , 'category' , $append );
2019-11-02 10:38:58 +01:00
}
/**
* Fires actions related to the transitioning of a post ' s status .
*
* When a post is saved , the post status is " transitioned " from one status to another ,
* though this does not always mean the status has actually changed before and after
* the save . This function fires a number of action hooks related to that transition :
* the generic { @ see 'transition_post_status' } action , as well as the dynamic hooks
* { @ see '$old_status_to_$new_status' } and { @ see '$new_status_$post->post_type' } . Note
* that the function does not transition the post object in the database .
*
* For instance : When publishing a post for the first time , the post status may transition
* from 'draft' – or some other status – to 'publish' . However , if a post is already
* published and is simply being updated , the " old " and " new " statuses may both be 'publish'
* before and after the transition .
*
* @ since 2.3 . 0
*
* @ param string $new_status Transition to this post status .
* @ param string $old_status Previous post status .
* @ param WP_Post $post Post data .
*/
function wp_transition_post_status ( $new_status , $old_status , $post ) {
/**
* Fires when a post is transitioned from one status to another .
*
* @ since 2.3 . 0
*
* @ param string $new_status New post status .
* @ param string $old_status Old post status .
* @ param WP_Post $post Post object .
*/
do_action ( 'transition_post_status' , $new_status , $old_status , $post );
/**
* Fires when a post is transitioned from one status to another .
*
2020-12-10 14:06:04 +01:00
* The dynamic portions of the hook name , `$new_status` and `$old_status` ,
2019-11-02 10:38:58 +01:00
* refer to the old and new post statuses , respectively .
*
2022-04-02 10:26:41 +02:00
* Possible hook names include :
*
* - `draft_to_publish`
* - `publish_to_trash`
* - `pending_to_draft`
*
2019-11-02 10:38:58 +01:00
* @ since 2.3 . 0
*
* @ param WP_Post $post Post object .
*/
do_action ( " { $old_status } _to_ { $new_status } " , $post );
/**
* Fires when a post is transitioned from one status to another .
*
* The dynamic portions of the hook name , `$new_status` and `$post->post_type` ,
* refer to the new post status and post type , respectively .
*
2021-07-23 11:58:50 +02:00
* Possible hook names include :
*
* - `draft_post`
* - `future_post`
* - `pending_post`
* - `private_post`
* - `publish_post`
* - `trash_post`
* - `draft_page`
* - `future_page`
* - `pending_page`
* - `private_page`
* - `publish_page`
* - `trash_page`
* - `publish_attachment`
* - `trash_attachment`
*
2019-11-02 10:38:58 +01:00
* Please note : When this action is hooked using a particular post status ( like
* 'publish' , as `publish_{$post->post_type}` ), it will fire both when a post is
* first transitioned to that status from something else , as well as upon
* subsequent post updates ( old and new status are both the same ) .
*
* Therefore , if you are looking to only fire a callback when a post is first
* transitioned to a status , use the { @ see 'transition_post_status' } hook instead .
*
* @ since 2.3 . 0
2022-04-02 10:26:41 +02:00
* @ since 5.9 . 0 Added `$old_status` parameter .
2019-11-02 10:38:58 +01:00
*
2022-04-02 10:26:41 +02:00
* @ param int $post_id Post ID .
* @ param WP_Post $post Post object .
* @ param string $old_status Old post status .
2019-11-02 10:38:58 +01:00
*/
2022-04-02 10:26:41 +02:00
do_action ( " { $new_status } _ { $post -> post_type } " , $post -> ID , $post , $old_status );
2019-11-02 10:38:58 +01:00
}
2020-12-10 14:06:04 +01:00
/**
* Fires actions after a post , its terms and meta data has been saved .
*
* @ since 5.6 . 0
*
* @ param int | WP_Post $post The post ID or object that has been saved .
* @ param bool $update Whether this is an existing post being updated .
* @ param null | WP_Post $post_before Null for new posts , the WP_Post object prior
* to the update for updated posts .
*/
function wp_after_insert_post ( $post , $update , $post_before ) {
$post = get_post ( $post );
2022-12-15 17:47:31 +01:00
2020-12-10 14:06:04 +01:00
if ( ! $post ) {
return ;
}
$post_id = $post -> ID ;
/**
* Fires once a post , its terms and meta data has been saved .
*
* @ since 5.6 . 0
*
* @ param int $post_id Post ID .
* @ param WP_Post $post Post object .
* @ param bool $update Whether this is an existing post being updated .
* @ param null | WP_Post $post_before Null for new posts , the WP_Post object prior
* to the update for updated posts .
*/
do_action ( 'wp_after_insert_post' , $post_id , $post , $update , $post_before );
}
2019-11-02 10:38:58 +01:00
//
// Comment, trackback, and pingback functions.
//
/**
2022-12-15 17:47:31 +01:00
* Adds a URL to those already pinged .
2019-11-02 10:38:58 +01:00
*
* @ since 1.5 . 0
2022-12-15 17:47:31 +01:00
* @ since 4.7 . 0 `$post` can be a WP_Post object .
2019-11-02 10:38:58 +01:00
* @ since 4.7 . 0 `$uri` can be an array of URIs .
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
2022-12-15 17:47:31 +01:00
* @ param int | WP_Post $post Post ID or post object .
* @ param string | array $uri Ping URI or array of URIs .
2019-11-02 10:38:58 +01:00
* @ return int | false How many rows were updated .
*/
2022-12-15 17:47:31 +01:00
function add_ping ( $post , $uri ) {
2019-11-02 10:38:58 +01:00
global $wpdb ;
2022-12-15 17:47:31 +01:00
$post = get_post ( $post );
2020-12-10 14:06:04 +01:00
2019-11-02 10:38:58 +01:00
if ( ! $post ) {
return false ;
}
$pung = trim ( $post -> pinged );
$pung = preg_split ( '/\s/' , $pung );
if ( is_array ( $uri ) ) {
$pung = array_merge ( $pung , $uri );
} else {
$pung [] = $uri ;
}
$new = implode ( " \n " , $pung );
/**
* Filters the new ping URL to add for the given post .
*
* @ since 2.0 . 0
*
* @ param string $new New ping URL to add .
*/
$new = apply_filters ( 'add_ping' , $new );
$return = $wpdb -> update ( $wpdb -> posts , array ( 'pinged' => $new ), array ( 'ID' => $post -> ID ) );
clean_post_cache ( $post -> ID );
return $return ;
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves enclosures already enclosed for a post .
2019-11-02 10:38:58 +01:00
*
* @ since 1.5 . 0
*
* @ param int $post_id Post ID .
2020-05-06 17:23:38 +02:00
* @ return string [] Array of enclosures for the given post .
2019-11-02 10:38:58 +01:00
*/
function get_enclosed ( $post_id ) {
$custom_fields = get_post_custom ( $post_id );
$pung = array ();
if ( ! is_array ( $custom_fields ) ) {
return $pung ;
}
foreach ( $custom_fields as $key => $val ) {
2020-09-15 14:29:22 +02:00
if ( 'enclosure' !== $key || ! is_array ( $val ) ) {
2019-11-02 10:38:58 +01:00
continue ;
}
foreach ( $val as $enc ) {
$enclosure = explode ( " \n " , $enc );
$pung [] = trim ( $enclosure [ 0 ] );
}
}
/**
* Filters the list of enclosures already enclosed for the given post .
*
* @ since 2.0 . 0
*
2020-05-06 17:23:38 +02:00
* @ param string [] $pung Array of enclosures for the given post .
* @ param int $post_id Post ID .
2019-11-02 10:38:58 +01:00
*/
return apply_filters ( 'get_enclosed' , $pung , $post_id );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves URLs already pinged for a post .
2019-11-02 10:38:58 +01:00
*
* @ since 1.5 . 0
*
2022-12-15 17:47:31 +01:00
* @ since 4.7 . 0 `$post` can be a WP_Post object .
2019-11-02 10:38:58 +01:00
*
2022-12-15 17:47:31 +01:00
* @ param int | WP_Post $post Post ID or object .
2021-04-27 08:32:47 +02:00
* @ return string [] | false Array of URLs already pinged for the given post , false if the post is not found .
2019-11-02 10:38:58 +01:00
*/
2022-12-15 17:47:31 +01:00
function get_pung ( $post ) {
$post = get_post ( $post );
2020-12-10 14:06:04 +01:00
2019-11-02 10:38:58 +01:00
if ( ! $post ) {
return false ;
}
$pung = trim ( $post -> pinged );
$pung = preg_split ( '/\s/' , $pung );
/**
* Filters the list of already - pinged URLs for the given post .
*
* @ since 2.0 . 0
*
* @ param string [] $pung Array of URLs already pinged for the given post .
*/
return apply_filters ( 'get_pung' , $pung );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves URLs that need to be pinged .
2019-11-02 10:38:58 +01:00
*
* @ since 1.5 . 0
2022-12-15 17:47:31 +01:00
* @ since 4.7 . 0 `$post` can be a WP_Post object .
2019-11-02 10:38:58 +01:00
*
2022-12-15 17:47:31 +01:00
* @ param int | WP_Post $post Post ID or post object .
2020-09-15 14:29:22 +02:00
* @ return string [] | false List of URLs yet to ping .
2019-11-02 10:38:58 +01:00
*/
2022-12-15 17:47:31 +01:00
function get_to_ping ( $post ) {
$post = get_post ( $post );
2019-11-02 10:38:58 +01:00
if ( ! $post ) {
return false ;
}
$to_ping = sanitize_trackback_urls ( $post -> to_ping );
$to_ping = preg_split ( '/\s/' , $to_ping , - 1 , PREG_SPLIT_NO_EMPTY );
/**
* Filters the list of URLs yet to ping for the given post .
*
* @ since 2.0 . 0
*
2020-05-06 17:23:38 +02:00
* @ param string [] $to_ping List of URLs yet to ping .
2019-11-02 10:38:58 +01:00
*/
return apply_filters ( 'get_to_ping' , $to_ping );
}
/**
2022-12-15 17:47:31 +01:00
* Does trackbacks for a list of URLs .
2019-11-02 10:38:58 +01:00
*
* @ since 1.0 . 0
*
* @ param string $tb_list Comma separated list of URLs .
* @ param int $post_id Post ID .
*/
function trackback_url_list ( $tb_list , $post_id ) {
if ( ! empty ( $tb_list ) ) {
// Get post data.
$postdata = get_post ( $post_id , ARRAY_A );
// Form an excerpt.
$excerpt = strip_tags ( $postdata [ 'post_excerpt' ] ? $postdata [ 'post_excerpt' ] : $postdata [ 'post_content' ] );
if ( strlen ( $excerpt ) > 255 ) {
$excerpt = substr ( $excerpt , 0 , 252 ) . '…' ;
}
$trackback_urls = explode ( ',' , $tb_list );
foreach ( ( array ) $trackback_urls as $tb_url ) {
$tb_url = trim ( $tb_url );
trackback ( $tb_url , wp_unslash ( $postdata [ 'post_title' ] ), $excerpt , $post_id );
}
}
}
//
2020-05-06 17:23:38 +02:00
// Page functions.
2019-11-02 10:38:58 +01:00
//
/**
2022-12-15 17:47:31 +01:00
* Gets a list of page IDs .
2019-11-02 10:38:58 +01:00
*
* @ since 2.0 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
2020-05-06 17:23:38 +02:00
* @ return string [] List of page IDs as strings .
2019-11-02 10:38:58 +01:00
*/
function get_all_page_ids () {
global $wpdb ;
$page_ids = wp_cache_get ( 'all_page_ids' , 'posts' );
if ( ! is_array ( $page_ids ) ) {
$page_ids = $wpdb -> get_col ( " SELECT ID FROM $wpdb->posts WHERE post_type = 'page' " );
wp_cache_add ( 'all_page_ids' , $page_ids , 'posts' );
}
return $page_ids ;
}
/**
* Retrieves page data given a page ID or page object .
*
* Use get_post () instead of get_page () .
*
* @ since 1.5 . 1
* @ deprecated 3.5 . 0 Use get_post ()
*
2020-05-06 17:23:38 +02:00
* @ param int | WP_Post $page Page object or page ID . Passed by reference .
2020-09-15 14:29:22 +02:00
* @ param string $output Optional . 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 .
2020-05-06 17:23:38 +02:00
* @ param string $filter Optional . How the return value should be filtered . Accepts 'raw' ,
* 'edit' , 'db' , 'display' . Default 'raw' .
* @ return WP_Post | array | null WP_Post or array on success , null on failure .
2019-11-02 10:38:58 +01:00
*/
function get_page ( $page , $output = OBJECT , $filter = 'raw' ) {
return get_post ( $page , $output , $filter );
}
/**
* Retrieves a page given its path .
*
* @ since 2.1 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param string $page_path Page path .
2020-09-15 14:29:22 +02:00
* @ param string $output Optional . 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 .
2019-11-02 10:38:58 +01:00
* @ param string | array $post_type Optional . Post type or array of post types . Default 'page' .
* @ return WP_Post | array | null WP_Post ( or array ) on success , or null on failure .
*/
function get_page_by_path ( $page_path , $output = OBJECT , $post_type = 'page' ) {
global $wpdb ;
$last_changed = wp_cache_get_last_changed ( 'posts' );
$hash = md5 ( $page_path . serialize ( $post_type ) );
$cache_key = " get_page_by_path: $hash : $last_changed " ;
$cached = wp_cache_get ( $cache_key , 'posts' );
if ( false !== $cached ) {
// Special case: '0' is a bad `$page_path`.
if ( '0' === $cached || 0 === $cached ) {
return ;
} else {
return get_post ( $cached , $output );
}
}
$page_path = rawurlencode ( urldecode ( $page_path ) );
$page_path = str_replace ( '%2F' , '/' , $page_path );
$page_path = str_replace ( '%20' , ' ' , $page_path );
$parts = explode ( '/' , trim ( $page_path , '/' ) );
$parts = array_map ( 'sanitize_title_for_query' , $parts );
$escaped_parts = esc_sql ( $parts );
$in_string = " ' " . implode ( " ',' " , $escaped_parts ) . " ' " ;
if ( is_array ( $post_type ) ) {
$post_types = $post_type ;
} else {
$post_types = array ( $post_type , 'attachment' );
}
$post_types = esc_sql ( $post_types );
$post_type_in_string = " ' " . implode ( " ',' " , $post_types ) . " ' " ;
$sql = "
SELECT ID , post_name , post_parent , post_type
FROM $wpdb -> posts
WHERE post_name IN ( $in_string )
AND post_type IN ( $post_type_in_string )
" ;
$pages = $wpdb -> get_results ( $sql , OBJECT_K );
$revparts = array_reverse ( $parts );
$foundid = 0 ;
foreach ( ( array ) $pages as $page ) {
if ( $page -> post_name == $revparts [ 0 ] ) {
$count = 0 ;
$p = $page ;
/*
* Loop through the given path parts from right to left ,
* ensuring each matches the post ancestry .
*/
2020-05-06 17:23:38 +02:00
while ( 0 != $p -> post_parent && isset ( $pages [ $p -> post_parent ] ) ) {
2019-11-02 10:38:58 +01:00
$count ++ ;
$parent = $pages [ $p -> post_parent ];
if ( ! isset ( $revparts [ $count ] ) || $parent -> post_name != $revparts [ $count ] ) {
break ;
}
$p = $parent ;
}
2020-05-06 17:23:38 +02:00
if ( 0 == $p -> post_parent && count ( $revparts ) == $count + 1 && $p -> post_name == $revparts [ $count ] ) {
2019-11-02 10:38:58 +01:00
$foundid = $page -> ID ;
if ( $page -> post_type == $post_type ) {
break ;
}
}
}
}
// We cache misses as well as hits.
wp_cache_set ( $cache_key , $foundid , 'posts' );
if ( $foundid ) {
return get_post ( $foundid , $output );
}
2022-04-02 10:26:41 +02:00
return null ;
2019-11-02 10:38:58 +01:00
}
/**
2022-12-15 17:47:31 +01:00
* Identifies descendants of a given page ID in a list of page objects .
2019-11-02 10:38:58 +01:00
*
* Descendants are identified from the `$pages` array passed to the function . No database queries are performed .
*
* @ since 1.5 . 1
*
2022-12-15 17:47:31 +01:00
* @ param int $page_id Page ID .
* @ param WP_Post [] $pages List of page objects from which descendants should be identified .
* @ return WP_Post [] List of page children .
2019-11-02 10:38:58 +01:00
*/
function get_page_children ( $page_id , $pages ) {
// Build a hash of ID -> children.
$children = array ();
foreach ( ( array ) $pages as $page ) {
2020-12-10 14:06:04 +01:00
$children [ ( int ) $page -> post_parent ][] = $page ;
2019-11-02 10:38:58 +01:00
}
$page_list = array ();
// Start the search by looking at immediate children.
if ( isset ( $children [ $page_id ] ) ) {
// Always start at the end of the stack in order to preserve original `$pages` order.
$to_look = array_reverse ( $children [ $page_id ] );
while ( $to_look ) {
$p = array_pop ( $to_look );
$page_list [] = $p ;
if ( isset ( $children [ $p -> ID ] ) ) {
foreach ( array_reverse ( $children [ $p -> ID ] ) as $child ) {
// Append to the `$to_look` stack to descend the tree.
$to_look [] = $child ;
}
}
}
}
return $page_list ;
}
/**
2022-12-15 17:47:31 +01:00
* Orders the pages with children under parents in a flat list .
2019-11-02 10:38:58 +01:00
*
* It uses auxiliary structure to hold parent - children relationships and
* runs in O ( N ) complexity
*
* @ since 2.0 . 0
*
2020-05-06 17:23:38 +02:00
* @ param WP_Post [] $pages Posts array ( passed by reference ) .
* @ param int $page_id Optional . Parent page ID . Default 0.
* @ return string [] Array of post names keyed by ID and arranged by hierarchy . Children immediately follow their parents .
2019-11-02 10:38:58 +01:00
*/
function get_page_hierarchy ( & $pages , $page_id = 0 ) {
if ( empty ( $pages ) ) {
return array ();
}
$children = array ();
foreach ( ( array ) $pages as $p ) {
2020-12-10 14:06:04 +01:00
$parent_id = ( int ) $p -> post_parent ;
2019-11-02 10:38:58 +01:00
$children [ $parent_id ][] = $p ;
}
$result = array ();
_page_traverse_name ( $page_id , $children , $result );
return $result ;
}
/**
2022-12-15 17:47:31 +01:00
* Traverses and return all the nested children post names of a root page .
2019-11-02 10:38:58 +01:00
*
* $children contains parent - children relations
*
* @ since 2.9 . 0
* @ access private
*
* @ see _page_traverse_name ()
*
2020-05-06 17:23:38 +02:00
* @ param int $page_id Page ID .
* @ param array $children Parent - children relations ( passed by reference ) .
* @ param string [] $result Array of page names keyed by ID ( passed by reference ) .
2019-11-02 10:38:58 +01:00
*/
function _page_traverse_name ( $page_id , & $children , & $result ) {
if ( isset ( $children [ $page_id ] ) ) {
foreach ( ( array ) $children [ $page_id ] as $child ) {
$result [ $child -> ID ] = $child -> post_name ;
_page_traverse_name ( $child -> ID , $children , $result );
}
}
}
/**
2022-12-15 17:47:31 +01:00
* Builds the URI path for a page .
2019-11-02 10:38:58 +01:00
*
* Sub pages will be in the " directory " under the parent page post name .
*
* @ since 1.5 . 0
2019-11-15 22:59:44 +01:00
* @ since 4.6 . 0 The `$page` parameter was made optional .
2019-11-02 10:38:58 +01:00
*
* @ param WP_Post | object | int $page Optional . Page ID or WP_Post object . Default is global $post .
* @ return string | false Page URI , false on error .
*/
function get_page_uri ( $page = 0 ) {
if ( ! $page instanceof WP_Post ) {
$page = get_post ( $page );
}
if ( ! $page ) {
return false ;
}
$uri = $page -> post_name ;
foreach ( $page -> ancestors as $parent ) {
$parent = get_post ( $parent );
if ( $parent && $parent -> post_name ) {
$uri = $parent -> post_name . '/' . $uri ;
}
}
/**
* Filters the URI for a page .
*
* @ since 4.4 . 0
*
* @ param string $uri Page URI .
* @ param WP_Post $page Page object .
*/
return apply_filters ( 'get_page_uri' , $uri , $page );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves an array of pages ( or hierarchical post type items ) .
2019-11-02 10:38:58 +01:00
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ since 1.5 . 0
*
* @ param array | string $args {
* Optional . Array or string of arguments to retrieve pages .
*
* @ type int $child_of Page ID to return child and grandchild pages of . Note : The value
* of `$hierarchical` has no bearing on whether `$child_of` returns
* hierarchical results . Default 0 , or no restriction .
* @ type string $sort_order How to sort retrieved pages . Accepts 'ASC' , 'DESC' . Default 'ASC' .
* @ type string $sort_column What columns to sort pages by , comma - separated . Accepts 'post_author' ,
* 'post_date' , 'post_title' , 'post_name' , 'post_modified' , 'menu_order' ,
* 'post_modified_gmt' , 'post_parent' , 'ID' , 'rand' , 'comment_count' .
* 'post_' can be omitted for any values that start with it .
* Default 'post_title' .
* @ type bool $hierarchical Whether to return pages hierarchically . If false in conjunction with
* `$child_of` also being false , both arguments will be disregarded .
* Default true .
2021-04-27 08:32:47 +02:00
* @ type int [] $exclude Array of page IDs to exclude . Default empty array .
* @ type int [] $include Array of page IDs to include . Cannot be used with `$child_of` ,
2019-11-02 10:38:58 +01:00
* `$parent` , `$exclude` , `$meta_key` , `$meta_value` , or `$hierarchical` .
* Default empty array .
* @ type string $meta_key Only include pages with this meta key . Default empty .
* @ type string $meta_value Only include pages with this meta value . Requires `$meta_key` .
* Default empty .
* @ type string $authors A comma - separated list of author IDs . Default empty .
* @ type int $parent Page ID to return direct children of . Default - 1 , or no restriction .
2021-04-27 08:32:47 +02:00
* @ type string | int [] $exclude_tree Comma - separated string or array of page IDs to exclude .
2019-11-02 10:38:58 +01:00
* Default empty array .
* @ type int $number The number of pages to return . Default 0 , or all pages .
* @ type int $offset The number of pages to skip before returning . Requires `$number` .
* Default 0.
* @ type string $post_type The post type to query . Default 'page' .
* @ type string | array $post_status A comma - separated list or array of post statuses to include .
* Default 'publish' .
* }
2022-12-15 17:47:31 +01:00
* @ return WP_Post [] | false Array of pages ( or hierarchical post type items ) . Boolean false if the
* specified post type is not hierarchical or the specified status is not
* supported by the post type .
2019-11-02 10:38:58 +01:00
*/
function get_pages ( $args = array () ) {
global $wpdb ;
$defaults = array (
'child_of' => 0 ,
'sort_order' => 'ASC' ,
'sort_column' => 'post_title' ,
'hierarchical' => 1 ,
'exclude' => array (),
'include' => array (),
'meta_key' => '' ,
'meta_value' => '' ,
'authors' => '' ,
'parent' => - 1 ,
'exclude_tree' => array (),
'number' => '' ,
'offset' => 0 ,
'post_type' => 'page' ,
'post_status' => 'publish' ,
);
2019-11-15 22:59:44 +01:00
$parsed_args = wp_parse_args ( $args , $defaults );
2019-11-02 10:38:58 +01:00
2019-11-15 22:59:44 +01:00
$number = ( int ) $parsed_args [ 'number' ];
$offset = ( int ) $parsed_args [ 'offset' ];
$child_of = ( int ) $parsed_args [ 'child_of' ];
$hierarchical = $parsed_args [ 'hierarchical' ];
$exclude = $parsed_args [ 'exclude' ];
$meta_key = $parsed_args [ 'meta_key' ];
$meta_value = $parsed_args [ 'meta_value' ];
$parent = $parsed_args [ 'parent' ];
$post_status = $parsed_args [ 'post_status' ];
2019-11-02 10:38:58 +01:00
// Make sure the post type is hierarchical.
$hierarchical_post_types = get_post_types ( array ( 'hierarchical' => true ) );
2020-09-15 14:29:22 +02:00
if ( ! in_array ( $parsed_args [ 'post_type' ], $hierarchical_post_types , true ) ) {
2019-11-02 10:38:58 +01:00
return false ;
}
if ( $parent > 0 && ! $child_of ) {
$hierarchical = false ;
}
// Make sure we have a valid post status.
if ( ! is_array ( $post_status ) ) {
$post_status = explode ( ',' , $post_status );
}
if ( array_diff ( $post_status , get_post_stati () ) ) {
return false ;
}
// $args can be whatever, only use the args defined in defaults to compute the key.
2019-11-15 22:59:44 +01:00
$key = md5 ( serialize ( wp_array_slice_assoc ( $parsed_args , array_keys ( $defaults ) ) ) );
2019-11-02 10:38:58 +01:00
$last_changed = wp_cache_get_last_changed ( 'posts' );
$cache_key = " get_pages: $key : $last_changed " ;
$cache = wp_cache_get ( $cache_key , 'posts' );
if ( false !== $cache ) {
2021-07-23 11:58:50 +02:00
_prime_post_caches ( $cache , false , false );
2019-11-02 10:38:58 +01:00
// Convert to WP_Post instances.
$pages = array_map ( 'get_post' , $cache );
/** This filter is documented in wp-includes/post.php */
2019-11-15 22:59:44 +01:00
$pages = apply_filters ( 'get_pages' , $pages , $parsed_args );
2021-07-23 11:58:50 +02:00
2019-11-02 10:38:58 +01:00
return $pages ;
}
$inclusions = '' ;
2019-11-15 22:59:44 +01:00
if ( ! empty ( $parsed_args [ 'include' ] ) ) {
2020-05-06 17:23:38 +02:00
$child_of = 0 ; // Ignore child_of, parent, exclude, meta_key, and meta_value params if using include.
2019-11-02 10:38:58 +01:00
$parent = - 1 ;
$exclude = '' ;
$meta_key = '' ;
$meta_value = '' ;
$hierarchical = false ;
2019-11-15 22:59:44 +01:00
$incpages = wp_parse_id_list ( $parsed_args [ 'include' ] );
2019-11-02 10:38:58 +01:00
if ( ! empty ( $incpages ) ) {
$inclusions = ' AND ID IN (' . implode ( ',' , $incpages ) . ')' ;
}
}
$exclusions = '' ;
if ( ! empty ( $exclude ) ) {
$expages = wp_parse_id_list ( $exclude );
if ( ! empty ( $expages ) ) {
$exclusions = ' AND ID NOT IN (' . implode ( ',' , $expages ) . ')' ;
}
}
$author_query = '' ;
2019-11-15 22:59:44 +01:00
if ( ! empty ( $parsed_args [ 'authors' ] ) ) {
$post_authors = wp_parse_list ( $parsed_args [ 'authors' ] );
2019-11-02 10:38:58 +01:00
if ( ! empty ( $post_authors ) ) {
foreach ( $post_authors as $post_author ) {
2020-05-06 17:23:38 +02:00
// Do we have an author id or an author login?
2020-12-10 14:06:04 +01:00
if ( 0 == ( int ) $post_author ) {
2019-11-02 10:38:58 +01:00
$post_author = get_user_by ( 'login' , $post_author );
if ( empty ( $post_author ) ) {
continue ;
}
if ( empty ( $post_author -> ID ) ) {
continue ;
}
$post_author = $post_author -> ID ;
}
2020-09-15 14:29:22 +02:00
if ( '' === $author_query ) {
2019-11-02 10:38:58 +01:00
$author_query = $wpdb -> prepare ( ' post_author = %d ' , $post_author );
} else {
$author_query .= $wpdb -> prepare ( ' OR post_author = %d ' , $post_author );
}
}
2020-09-15 14:29:22 +02:00
if ( '' !== $author_query ) {
2019-11-02 10:38:58 +01:00
$author_query = " AND ( $author_query ) " ;
}
}
}
$join = '' ;
$where = " $exclusions $inclusions " ;
if ( '' !== $meta_key || '' !== $meta_value ) {
$join = " LEFT JOIN $wpdb->postmeta ON ( $wpdb->posts .ID = $wpdb->postmeta .post_id ) " ;
2020-05-06 17:23:38 +02:00
// meta_key and meta_value might be slashed.
2019-11-02 10:38:58 +01:00
$meta_key = wp_unslash ( $meta_key );
$meta_value = wp_unslash ( $meta_value );
if ( '' !== $meta_key ) {
$where .= $wpdb -> prepare ( " AND $wpdb->postmeta .meta_key = %s " , $meta_key );
}
if ( '' !== $meta_value ) {
$where .= $wpdb -> prepare ( " AND $wpdb->postmeta .meta_value = %s " , $meta_value );
}
}
if ( is_array ( $parent ) ) {
$post_parent__in = implode ( ',' , array_map ( 'absint' , ( array ) $parent ) );
if ( ! empty ( $post_parent__in ) ) {
$where .= " AND post_parent IN ( $post_parent__in ) " ;
}
} elseif ( $parent >= 0 ) {
$where .= $wpdb -> prepare ( ' AND post_parent = %d ' , $parent );
}
2020-09-15 14:29:22 +02:00
if ( 1 === count ( $post_status ) ) {
2019-11-15 22:59:44 +01:00
$where_post_type = $wpdb -> prepare ( 'post_type = %s AND post_status = %s' , $parsed_args [ 'post_type' ], reset ( $post_status ) );
2019-11-02 10:38:58 +01:00
} else {
$post_status = implode ( " ', ' " , $post_status );
2019-11-15 22:59:44 +01:00
$where_post_type = $wpdb -> prepare ( " post_type = %s AND post_status IN (' $post_status ') " , $parsed_args [ 'post_type' ] );
2019-11-02 10:38:58 +01:00
}
$orderby_array = array ();
$allowed_keys = array (
'author' ,
'post_author' ,
'date' ,
'post_date' ,
'title' ,
'post_title' ,
'name' ,
'post_name' ,
'modified' ,
'post_modified' ,
'modified_gmt' ,
'post_modified_gmt' ,
'menu_order' ,
'parent' ,
'post_parent' ,
'ID' ,
'rand' ,
'comment_count' ,
);
2019-11-15 22:59:44 +01:00
foreach ( explode ( ',' , $parsed_args [ 'sort_column' ] ) as $orderby ) {
2019-11-02 10:38:58 +01:00
$orderby = trim ( $orderby );
2020-09-15 14:29:22 +02:00
if ( ! in_array ( $orderby , $allowed_keys , true ) ) {
2019-11-02 10:38:58 +01:00
continue ;
}
switch ( $orderby ) {
case 'menu_order' :
break ;
case 'ID' :
$orderby = " $wpdb->posts .ID " ;
break ;
case 'rand' :
$orderby = 'RAND()' ;
break ;
case 'comment_count' :
$orderby = " $wpdb->posts .comment_count " ;
break ;
default :
if ( 0 === strpos ( $orderby , 'post_' ) ) {
$orderby = " $wpdb->posts . " . $orderby ;
} else {
$orderby = " $wpdb->posts .post_ " . $orderby ;
}
}
$orderby_array [] = $orderby ;
}
$sort_column = ! empty ( $orderby_array ) ? implode ( ',' , $orderby_array ) : " $wpdb->posts .post_title " ;
2019-11-15 22:59:44 +01:00
$sort_order = strtoupper ( $parsed_args [ 'sort_order' ] );
2020-09-15 14:29:22 +02:00
if ( '' !== $sort_order && ! in_array ( $sort_order , array ( 'ASC' , 'DESC' ), true ) ) {
2019-11-02 10:38:58 +01:00
$sort_order = 'ASC' ;
}
$query = " SELECT * FROM $wpdb->posts $join WHERE ( $where_post_type ) $where " ;
$query .= $author_query ;
$query .= ' ORDER BY ' . $sort_column . ' ' . $sort_order ;
if ( ! empty ( $number ) ) {
$query .= ' LIMIT ' . $offset . ',' . $number ;
}
$pages = $wpdb -> get_results ( $query );
if ( empty ( $pages ) ) {
wp_cache_set ( $cache_key , array (), 'posts' );
/** This filter is documented in wp-includes/post.php */
2019-11-15 22:59:44 +01:00
$pages = apply_filters ( 'get_pages' , array (), $parsed_args );
2021-07-23 11:58:50 +02:00
2019-11-02 10:38:58 +01:00
return $pages ;
}
// Sanitize before caching so it'll only get done once.
$num_pages = count ( $pages );
for ( $i = 0 ; $i < $num_pages ; $i ++ ) {
$pages [ $i ] = sanitize_post ( $pages [ $i ], 'raw' );
}
// Update cache.
update_post_cache ( $pages );
if ( $child_of || $hierarchical ) {
$pages = get_page_children ( $child_of , $pages );
}
2019-11-15 22:59:44 +01:00
if ( ! empty ( $parsed_args [ 'exclude_tree' ] ) ) {
$exclude = wp_parse_id_list ( $parsed_args [ 'exclude_tree' ] );
2019-11-02 10:38:58 +01:00
foreach ( $exclude as $id ) {
$children = get_page_children ( $id , $pages );
foreach ( $children as $child ) {
$exclude [] = $child -> ID ;
}
}
$num_pages = count ( $pages );
for ( $i = 0 ; $i < $num_pages ; $i ++ ) {
2020-09-15 14:29:22 +02:00
if ( in_array ( $pages [ $i ] -> ID , $exclude , true ) ) {
2019-11-02 10:38:58 +01:00
unset ( $pages [ $i ] );
}
}
}
$page_structure = array ();
foreach ( $pages as $page ) {
$page_structure [] = $page -> ID ;
}
wp_cache_set ( $cache_key , $page_structure , 'posts' );
2020-05-06 17:23:38 +02:00
// Convert to WP_Post instances.
2019-11-02 10:38:58 +01:00
$pages = array_map ( 'get_post' , $pages );
/**
* Filters the retrieved list of pages .
*
* @ since 2.1 . 0
*
2020-05-06 17:23:38 +02:00
* @ param WP_Post [] $pages Array of page objects .
* @ param array $parsed_args Array of get_pages () arguments .
2019-11-02 10:38:58 +01:00
*/
2019-11-15 22:59:44 +01:00
return apply_filters ( 'get_pages' , $pages , $parsed_args );
2019-11-02 10:38:58 +01:00
}
//
2020-05-06 17:23:38 +02:00
// Attachment functions.
2019-11-02 10:38:58 +01:00
//
/**
* Determines whether an attachment URI is local and really an attachment .
*
* 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 .
*
* @ since 2.0 . 0
*
* @ param string $url URL to check
* @ return bool True on success , false on failure .
*/
function is_local_attachment ( $url ) {
if ( strpos ( $url , home_url () ) === false ) {
return false ;
}
if ( strpos ( $url , home_url ( '/?attachment_id=' ) ) !== false ) {
return true ;
}
2019-11-15 22:59:44 +01:00
$id = url_to_postid ( $url );
if ( $id ) {
2019-11-02 10:38:58 +01:00
$post = get_post ( $id );
2020-09-15 14:29:22 +02:00
if ( 'attachment' === $post -> post_type ) {
2019-11-02 10:38:58 +01:00
return true ;
}
}
return false ;
}
/**
2022-12-15 17:47:31 +01:00
* Inserts an attachment .
2019-11-02 10:38:58 +01:00
*
* If you set the 'ID' in the $args parameter , it will mean that you are
* updating and attempt to update the attachment . You can also set the
* attachment name or title by setting the key 'post_name' or 'post_title' .
*
* You can set the dates for the attachment manually by setting the 'post_date'
* and 'post_date_gmt' keys ' values .
*
* By default , the comments will use the default settings for whether the
* comments are allowed . You can close them manually or keep them open by
* setting the value for the 'comment_status' key .
*
* @ since 2.0 . 0
* @ since 4.7 . 0 Added the `$wp_error` parameter to allow a WP_Error to be returned on failure .
2020-12-10 14:06:04 +01:00
* @ since 5.6 . 0 Added the `$fire_after_hooks` parameter .
2019-11-02 10:38:58 +01:00
*
* @ see wp_insert_post ()
*
2020-12-10 14:06:04 +01:00
* @ param string | array $args Arguments for inserting an attachment .
2021-04-27 08:32:47 +02:00
* @ param string | false $file Optional . Filename .
2023-04-26 17:39:43 +02:00
* @ param int $parent_post_id Optional . Parent post ID .
2020-12-10 14:06:04 +01:00
* @ param bool $wp_error Optional . Whether to return a WP_Error on failure . Default false .
* @ param bool $fire_after_hooks Optional . Whether to fire the after insert hooks . Default true .
2019-11-02 10:38:58 +01:00
* @ return int | WP_Error The attachment ID on success . The value 0 or WP_Error on failure .
*/
2023-04-26 17:39:43 +02:00
function wp_insert_attachment ( $args , $file = false , $parent_post_id = 0 , $wp_error = false , $fire_after_hooks = true ) {
2019-11-02 10:38:58 +01:00
$defaults = array (
'file' => $file ,
'post_parent' => 0 ,
);
$data = wp_parse_args ( $args , $defaults );
2023-04-26 17:39:43 +02:00
if ( ! empty ( $parent_post_id ) ) {
$data [ 'post_parent' ] = $parent_post_id ;
2019-11-02 10:38:58 +01:00
}
$data [ 'post_type' ] = 'attachment' ;
2020-12-10 14:06:04 +01:00
return wp_insert_post ( $data , $wp_error , $fire_after_hooks );
2019-11-02 10:38:58 +01:00
}
/**
2022-12-15 17:47:31 +01:00
* Trashes or deletes an attachment .
2019-11-02 10:38:58 +01:00
*
* When an attachment is permanently deleted , the file will also be removed .
* Deletion removes all post meta fields , taxonomy , comments , etc . associated
* with the attachment ( except the main post ) .
*
2020-05-06 17:23:38 +02:00
* The attachment is moved to the Trash instead of permanently deleted unless Trash
* for media is disabled , item is already in the Trash , or $force_delete is true .
2019-11-02 10:38:58 +01:00
*
* @ since 2.0 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param int $post_id Attachment ID .
2020-05-06 17:23:38 +02:00
* @ param bool $force_delete Optional . Whether to bypass Trash and force deletion .
2019-11-02 10:38:58 +01:00
* Default false .
* @ return WP_Post | false | null Post data on success , false or null on failure .
*/
function wp_delete_attachment ( $post_id , $force_delete = false ) {
global $wpdb ;
$post = $wpdb -> get_row ( $wpdb -> prepare ( " SELECT * FROM $wpdb->posts WHERE ID = %d " , $post_id ) );
if ( ! $post ) {
return $post ;
}
$post = get_post ( $post );
if ( 'attachment' !== $post -> post_type ) {
return false ;
}
if ( ! $force_delete && EMPTY_TRASH_DAYS && MEDIA_TRASH && 'trash' !== $post -> post_status ) {
return wp_trash_post ( $post_id );
}
2020-09-15 14:29:22 +02:00
/**
* Filters whether an attachment deletion should take place .
*
* @ since 5.5 . 0
*
2022-12-15 17:47:31 +01:00
* @ param WP_Post | false | null $delete Whether to go forward with deletion .
2022-06-16 14:03:35 +02:00
* @ param WP_Post $post Post object .
* @ param bool $force_delete Whether to bypass the Trash .
2020-09-15 14:29:22 +02:00
*/
$check = apply_filters ( 'pre_delete_attachment' , null , $post , $force_delete );
if ( null !== $check ) {
return $check ;
}
2019-11-02 10:38:58 +01:00
delete_post_meta ( $post_id , '_wp_trash_meta_status' );
delete_post_meta ( $post_id , '_wp_trash_meta_time' );
$meta = wp_get_attachment_metadata ( $post_id );
$backup_sizes = get_post_meta ( $post -> ID , '_wp_attachment_backup_sizes' , true );
$file = get_attached_file ( $post_id );
2022-04-02 10:26:41 +02:00
if ( is_multisite () && is_string ( $file ) && ! empty ( $file ) ) {
2020-12-10 14:06:04 +01:00
clean_dirsize_cache ( $file );
2019-11-02 10:38:58 +01:00
}
/**
* Fires before an attachment is deleted , at the start of wp_delete_attachment () .
*
* @ since 2.0 . 0
2020-09-15 14:29:22 +02:00
* @ since 5.5 . 0 Added the `$post` parameter .
2019-11-02 10:38:58 +01:00
*
2020-09-15 14:29:22 +02:00
* @ param int $post_id Attachment ID .
* @ param WP_Post $post Post object .
2019-11-02 10:38:58 +01:00
*/
2020-09-15 14:29:22 +02:00
do_action ( 'delete_attachment' , $post_id , $post );
2019-11-02 10:38:58 +01:00
wp_delete_object_term_relationships ( $post_id , array ( 'category' , 'post_tag' ) );
wp_delete_object_term_relationships ( $post_id , get_object_taxonomies ( $post -> post_type ) );
// Delete all for any posts.
delete_metadata ( 'post' , null , '_thumbnail_id' , $post_id , true );
wp_defer_comment_counting ( true );
2022-04-02 10:26:41 +02:00
$comment_ids = $wpdb -> get_col ( $wpdb -> prepare ( " SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d ORDER BY comment_ID DESC " , $post_id ) );
2019-11-02 10:38:58 +01:00
foreach ( $comment_ids as $comment_id ) {
wp_delete_comment ( $comment_id , true );
}
wp_defer_comment_counting ( false );
$post_meta_ids = $wpdb -> get_col ( $wpdb -> prepare ( " SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d " , $post_id ) );
foreach ( $post_meta_ids as $mid ) {
delete_metadata_by_mid ( 'post' , $mid );
}
/** This action is documented in wp-includes/post.php */
2020-09-15 14:29:22 +02:00
do_action ( 'delete_post' , $post_id , $post );
2019-11-02 10:38:58 +01:00
$result = $wpdb -> delete ( $wpdb -> posts , array ( 'ID' => $post_id ) );
if ( ! $result ) {
return false ;
}
/** This action is documented in wp-includes/post.php */
2020-09-15 14:29:22 +02:00
do_action ( 'deleted_post' , $post_id , $post );
2019-11-02 10:38:58 +01:00
wp_delete_attachment_files ( $post_id , $meta , $backup_sizes , $file );
clean_post_cache ( $post );
return $post ;
}
/**
* Deletes all files that belong to the given attachment .
*
* @ since 4.9 . 7
*
2020-12-10 14:06:04 +01:00
* @ global wpdb $wpdb WordPress database abstraction object .
*
2019-11-02 10:38:58 +01:00
* @ param int $post_id Attachment ID .
* @ param array $meta The attachment ' s meta data .
* @ param array $backup_sizes The meta data for the attachment ' s backup images .
* @ param string $file Absolute path to the attachment ' s file .
* @ return bool True on success , false on failure .
*/
function wp_delete_attachment_files ( $post_id , $meta , $backup_sizes , $file ) {
global $wpdb ;
$uploadpath = wp_get_upload_dir ();
$deleted = true ;
if ( ! empty ( $meta [ 'thumb' ] ) ) {
// Don't delete the thumb if another attachment uses it.
if ( ! $wpdb -> get_row ( $wpdb -> prepare ( " SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s AND post_id <> %d " , '%' . $wpdb -> esc_like ( $meta [ 'thumb' ] ) . '%' , $post_id ) ) ) {
$thumbfile = str_replace ( wp_basename ( $file ), $meta [ 'thumb' ], $file );
2019-11-15 22:59:44 +01:00
2019-11-02 10:38:58 +01:00
if ( ! empty ( $thumbfile ) ) {
$thumbfile = path_join ( $uploadpath [ 'basedir' ], $thumbfile );
$thumbdir = path_join ( $uploadpath [ 'basedir' ], dirname ( $file ) );
if ( ! wp_delete_file_from_directory ( $thumbfile , $thumbdir ) ) {
$deleted = false ;
}
}
}
}
// Remove intermediate and backup images if there are any.
if ( isset ( $meta [ 'sizes' ] ) && is_array ( $meta [ 'sizes' ] ) ) {
$intermediate_dir = path_join ( $uploadpath [ 'basedir' ], dirname ( $file ) );
2019-11-15 22:59:44 +01:00
2019-11-02 10:38:58 +01:00
foreach ( $meta [ 'sizes' ] as $size => $sizeinfo ) {
$intermediate_file = str_replace ( wp_basename ( $file ), $sizeinfo [ 'file' ], $file );
2019-11-15 22:59:44 +01:00
2019-11-02 10:38:58 +01:00
if ( ! empty ( $intermediate_file ) ) {
$intermediate_file = path_join ( $uploadpath [ 'basedir' ], $intermediate_file );
if ( ! wp_delete_file_from_directory ( $intermediate_file , $intermediate_dir ) ) {
$deleted = false ;
}
}
}
}
2019-11-15 22:59:44 +01:00
if ( ! empty ( $meta [ 'original_image' ] ) ) {
if ( empty ( $intermediate_dir ) ) {
$intermediate_dir = path_join ( $uploadpath [ 'basedir' ], dirname ( $file ) );
}
$original_image = str_replace ( wp_basename ( $file ), $meta [ 'original_image' ], $file );
if ( ! empty ( $original_image ) ) {
$original_image = path_join ( $uploadpath [ 'basedir' ], $original_image );
if ( ! wp_delete_file_from_directory ( $original_image , $intermediate_dir ) ) {
$deleted = false ;
}
}
}
2019-11-02 10:38:58 +01:00
if ( is_array ( $backup_sizes ) ) {
$del_dir = path_join ( $uploadpath [ 'basedir' ], dirname ( $meta [ 'file' ] ) );
2019-11-15 22:59:44 +01:00
2019-11-02 10:38:58 +01:00
foreach ( $backup_sizes as $size ) {
$del_file = path_join ( dirname ( $meta [ 'file' ] ), $size [ 'file' ] );
2019-11-15 22:59:44 +01:00
2019-11-02 10:38:58 +01:00
if ( ! empty ( $del_file ) ) {
$del_file = path_join ( $uploadpath [ 'basedir' ], $del_file );
if ( ! wp_delete_file_from_directory ( $del_file , $del_dir ) ) {
$deleted = false ;
}
}
}
}
if ( ! wp_delete_file_from_directory ( $file , $uploadpath [ 'basedir' ] ) ) {
$deleted = false ;
}
return $deleted ;
}
/**
2020-09-15 14:29:22 +02:00
* Retrieves attachment metadata for attachment ID .
2019-11-02 10:38:58 +01:00
*
* @ since 2.1 . 0
2022-12-15 17:47:31 +01:00
* @ since 6.0 . 0 The `$filesize` value was added to the returned array .
2019-11-02 10:38:58 +01:00
*
* @ param int $attachment_id Attachment post ID . Defaults to global $post .
* @ param bool $unfiltered Optional . If true , filters are not run . Default false .
2020-09-15 14:29:22 +02:00
* @ return array | false {
* Attachment metadata . False on failure .
*
* @ type int $width The width of the attachment .
* @ type int $height The height of the attachment .
* @ type string $file The file path relative to `wp-content/uploads` .
* @ type array $sizes Keys are size slugs , each value is an array containing
* 'file' , 'width' , 'height' , and 'mime-type' .
* @ type array $image_meta Image metadata .
2022-06-16 14:03:35 +02:00
* @ type int $filesize File size of the attachment .
2020-09-15 14:29:22 +02:00
* }
2019-11-02 10:38:58 +01:00
*/
function wp_get_attachment_metadata ( $attachment_id = 0 , $unfiltered = false ) {
$attachment_id = ( int ) $attachment_id ;
2020-09-15 14:29:22 +02:00
2021-04-27 08:32:47 +02:00
if ( ! $attachment_id ) {
$post = get_post ();
if ( ! $post ) {
return false ;
}
$attachment_id = $post -> ID ;
}
2020-12-10 14:06:04 +01:00
$data = get_post_meta ( $attachment_id , '_wp_attachment_metadata' , true );
if ( ! $data ) {
2019-11-02 10:38:58 +01:00
return false ;
}
if ( $unfiltered ) {
return $data ;
}
/**
* Filters the attachment meta data .
*
* @ since 2.1 . 0
*
2021-04-27 08:32:47 +02:00
* @ param array $data Array of meta data for the given attachment .
* @ param int $attachment_id Attachment post ID .
2019-11-02 10:38:58 +01:00
*/
2020-12-10 14:06:04 +01:00
return apply_filters ( 'wp_get_attachment_metadata' , $data , $attachment_id );
2019-11-02 10:38:58 +01:00
}
/**
2020-09-15 14:29:22 +02:00
* Updates metadata for an attachment .
2019-11-02 10:38:58 +01:00
*
* @ since 2.1 . 0
*
* @ param int $attachment_id Attachment post ID .
* @ param array $data Attachment meta data .
2021-04-27 08:32:47 +02:00
* @ return int | false False if $post is invalid .
2019-11-02 10:38:58 +01:00
*/
function wp_update_attachment_metadata ( $attachment_id , $data ) {
$attachment_id = ( int ) $attachment_id ;
2020-09-15 14:29:22 +02:00
$post = get_post ( $attachment_id );
2020-12-10 14:06:04 +01:00
2019-11-15 22:59:44 +01:00
if ( ! $post ) {
2019-11-02 10:38:58 +01:00
return false ;
}
/**
* Filters the updated attachment meta data .
*
* @ since 2.1 . 0
*
* @ param array $data Array of updated attachment meta data .
* @ param int $attachment_id Attachment post ID .
*/
2019-11-15 22:59:44 +01:00
$data = apply_filters ( 'wp_update_attachment_metadata' , $data , $post -> ID );
if ( $data ) {
2019-11-02 10:38:58 +01:00
return update_post_meta ( $post -> ID , '_wp_attachment_metadata' , $data );
} else {
return delete_post_meta ( $post -> ID , '_wp_attachment_metadata' );
}
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves the URL for an attachment .
2019-11-02 10:38:58 +01:00
*
* @ since 2.1 . 0
*
2022-06-16 14:03:35 +02:00
* @ global string $pagenow The filename of the current screen .
2019-11-02 10:38:58 +01:00
*
* @ param int $attachment_id Optional . Attachment post ID . Defaults to global $post .
* @ return string | false Attachment URL , otherwise false .
*/
function wp_get_attachment_url ( $attachment_id = 0 ) {
2021-04-27 08:32:47 +02:00
global $pagenow ;
2019-11-02 10:38:58 +01:00
$attachment_id = ( int ) $attachment_id ;
2020-09-15 14:29:22 +02:00
$post = get_post ( $attachment_id );
2020-12-10 14:06:04 +01:00
2019-11-15 22:59:44 +01:00
if ( ! $post ) {
2019-11-02 10:38:58 +01:00
return false ;
}
2020-09-15 14:29:22 +02:00
if ( 'attachment' !== $post -> post_type ) {
2019-11-02 10:38:58 +01:00
return false ;
}
$url = '' ;
// Get attached file.
2019-11-15 22:59:44 +01:00
$file = get_post_meta ( $post -> ID , '_wp_attached_file' , true );
if ( $file ) {
2019-11-02 10:38:58 +01:00
// Get upload directory.
2019-11-15 22:59:44 +01:00
$uploads = wp_get_upload_dir ();
if ( $uploads && false === $uploads [ 'error' ] ) {
2019-11-02 10:38:58 +01:00
// Check that the upload base exists in the file location.
if ( 0 === strpos ( $file , $uploads [ 'basedir' ] ) ) {
// Replace file location with url location.
$url = str_replace ( $uploads [ 'basedir' ], $uploads [ 'baseurl' ], $file );
} elseif ( false !== strpos ( $file , 'wp-content/uploads' ) ) {
2020-05-06 17:23:38 +02:00
// Get the directory name relative to the basedir (back compat for pre-2.7 uploads).
2019-11-02 10:38:58 +01:00
$url = trailingslashit ( $uploads [ 'baseurl' ] . '/' . _wp_get_attachment_relative_path ( $file ) ) . wp_basename ( $file );
} else {
// It's a newly-uploaded file, therefore $file is relative to the basedir.
$url = $uploads [ 'baseurl' ] . " / $file " ;
}
}
}
/*
* If any of the above options failed , Fallback on the GUID as used pre - 2.7 ,
* not recommended to rely upon this .
*/
2020-12-10 14:06:04 +01:00
if ( ! $url ) {
2019-11-02 10:38:58 +01:00
$url = get_the_guid ( $post -> ID );
}
// On SSL front end, URLs should be HTTPS.
2021-04-27 08:32:47 +02:00
if ( is_ssl () && ! is_admin () && 'wp-login.php' !== $pagenow ) {
2019-11-02 10:38:58 +01:00
$url = set_url_scheme ( $url );
}
/**
* Filters the attachment URL .
*
* @ since 2.1 . 0
*
* @ param string $url URL for the given attachment .
* @ param int $attachment_id Attachment post ID .
*/
$url = apply_filters ( 'wp_get_attachment_url' , $url , $post -> ID );
2020-12-10 14:06:04 +01:00
if ( ! $url ) {
2019-11-02 10:38:58 +01:00
return false ;
}
return $url ;
}
/**
* Retrieves the caption for an attachment .
*
* @ since 4.6 . 0
*
* @ param int $post_id Optional . Attachment ID . Default is the ID of the global `$post` .
2021-04-27 08:32:47 +02:00
* @ return string | false Attachment caption on success , false on failure .
2019-11-02 10:38:58 +01:00
*/
function wp_get_attachment_caption ( $post_id = 0 ) {
$post_id = ( int ) $post_id ;
2019-11-15 22:59:44 +01:00
$post = get_post ( $post_id );
2020-12-10 14:06:04 +01:00
2019-11-15 22:59:44 +01:00
if ( ! $post ) {
2019-11-02 10:38:58 +01:00
return false ;
}
if ( 'attachment' !== $post -> post_type ) {
return false ;
}
$caption = $post -> post_excerpt ;
/**
* Filters the attachment caption .
*
* @ since 4.6 . 0
*
* @ param string $caption Caption for the given attachment .
* @ param int $post_id Attachment ID .
*/
return apply_filters ( 'wp_get_attachment_caption' , $caption , $post -> ID );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves URL for an attachment thumbnail .
2019-11-02 10:38:58 +01:00
*
* @ since 2.1 . 0
2022-12-15 17:47:31 +01:00
* @ since 6.1 . 0 Changed to use wp_get_attachment_image_url () .
2019-11-02 10:38:58 +01:00
*
2022-04-02 10:26:41 +02:00
* @ param int $post_id Optional . Attachment ID . Default is the ID of the global `$post` .
2021-04-27 08:32:47 +02:00
* @ return string | false Thumbnail URL on success , false on failure .
2019-11-02 10:38:58 +01:00
*/
function wp_get_attachment_thumb_url ( $post_id = 0 ) {
$post_id = ( int ) $post_id ;
2022-12-15 17:47:31 +01:00
// This uses image_downsize() which also looks for the (very) old format $image_meta['thumb']
// when the newer format $image_meta['sizes']['thumbnail'] doesn't exist.
$thumbnail_url = wp_get_attachment_image_url ( $post_id , 'thumbnail' );
2019-11-02 10:38:58 +01:00
2022-12-15 17:47:31 +01:00
if ( empty ( $thumbnail_url ) ) {
2019-11-02 10:38:58 +01:00
return false ;
}
/**
* Filters the attachment thumbnail URL .
*
* @ since 2.1 . 0
*
2022-12-15 17:47:31 +01:00
* @ param string $thumbnail_url URL for the attachment thumbnail .
* @ param int $post_id Attachment ID .
2019-11-02 10:38:58 +01:00
*/
2022-12-15 17:47:31 +01:00
return apply_filters ( 'wp_get_attachment_thumb_url' , $thumbnail_url , $post_id );
2019-11-02 10:38:58 +01:00
}
/**
* Verifies an attachment is of a given type .
*
* @ since 4.2 . 0
*
* @ param string $type Attachment type . Accepts 'image' , 'audio' , or 'video' .
* @ param int | WP_Post $post Optional . Attachment ID or object . Default is global $post .
* @ return bool True if one of the accepted types , false otherwise .
*/
function wp_attachment_is ( $type , $post = null ) {
2019-11-15 22:59:44 +01:00
$post = get_post ( $post );
2020-12-10 14:06:04 +01:00
2019-11-15 22:59:44 +01:00
if ( ! $post ) {
2019-11-02 10:38:58 +01:00
return false ;
}
2019-11-15 22:59:44 +01:00
$file = get_attached_file ( $post -> ID );
2020-12-10 14:06:04 +01:00
2019-11-15 22:59:44 +01:00
if ( ! $file ) {
2019-11-02 10:38:58 +01:00
return false ;
}
if ( 0 === strpos ( $post -> post_mime_type , $type . '/' ) ) {
return true ;
}
$check = wp_check_filetype ( $file );
2020-12-10 14:06:04 +01:00
2019-11-02 10:38:58 +01:00
if ( empty ( $check [ 'ext' ] ) ) {
return false ;
}
$ext = $check [ 'ext' ];
if ( 'import' !== $post -> post_mime_type ) {
return $type === $ext ;
}
switch ( $type ) {
case 'image' :
2021-07-23 11:58:50 +02:00
$image_exts = array ( 'jpg' , 'jpeg' , 'jpe' , 'gif' , 'png' , 'webp' );
2020-09-15 14:29:22 +02:00
return in_array ( $ext , $image_exts , true );
2019-11-02 10:38:58 +01:00
case 'audio' :
2020-09-15 14:29:22 +02:00
return in_array ( $ext , wp_get_audio_extensions (), true );
2019-11-02 10:38:58 +01:00
case 'video' :
2020-09-15 14:29:22 +02:00
return in_array ( $ext , wp_get_video_extensions (), true );
2019-11-02 10:38:58 +01:00
default :
return $type === $ext ;
}
}
/**
* Determines whether an attachment is an image .
*
* 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 .
*
* @ since 2.1 . 0
* @ since 4.2 . 0 Modified into wrapper for wp_attachment_is () and
* allowed WP_Post object to be passed .
*
* @ param int | WP_Post $post Optional . Attachment ID or object . Default is global $post .
* @ return bool Whether the attachment is an image .
*/
function wp_attachment_is_image ( $post = null ) {
return wp_attachment_is ( 'image' , $post );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves the icon for a MIME type or attachment .
2019-11-02 10:38:58 +01:00
*
* @ since 2.1 . 0
*
* @ param string | int $mime MIME type or attachment ID .
* @ return string | false Icon , false otherwise .
*/
function wp_mime_type_icon ( $mime = 0 ) {
if ( ! is_numeric ( $mime ) ) {
$icon = wp_cache_get ( " mime_type_icon_ $mime " );
}
$post_id = 0 ;
if ( empty ( $icon ) ) {
$post_mimes = array ();
if ( is_numeric ( $mime ) ) {
$mime = ( int ) $mime ;
2019-11-15 22:59:44 +01:00
$post = get_post ( $mime );
if ( $post ) {
2019-11-02 10:38:58 +01:00
$post_id = ( int ) $post -> ID ;
$file = get_attached_file ( $post_id );
$ext = preg_replace ( '/^.+?\.([^.]+)$/' , '$1' , $file );
if ( ! empty ( $ext ) ) {
$post_mimes [] = $ext ;
2019-11-15 22:59:44 +01:00
$ext_type = wp_ext2type ( $ext );
if ( $ext_type ) {
2019-11-02 10:38:58 +01:00
$post_mimes [] = $ext_type ;
}
}
$mime = $post -> post_mime_type ;
} else {
$mime = 0 ;
}
} else {
$post_mimes [] = $mime ;
}
$icon_files = wp_cache_get ( 'icon_files' );
if ( ! is_array ( $icon_files ) ) {
/**
* Filters the icon directory path .
*
* @ since 2.0 . 0
*
* @ param string $path Icon directory absolute path .
*/
$icon_dir = apply_filters ( 'icon_dir' , ABSPATH . WPINC . '/images/media' );
/**
* Filters the icon directory URI .
*
* @ since 2.0 . 0
*
* @ param string $uri Icon directory URI .
*/
$icon_dir_uri = apply_filters ( 'icon_dir_uri' , includes_url ( 'images/media' ) );
/**
2020-05-06 17:23:38 +02:00
* Filters the array of icon directory URIs .
2019-11-02 10:38:58 +01:00
*
* @ since 2.5 . 0
*
2020-05-06 17:23:38 +02:00
* @ param string [] $uris Array of icon directory URIs keyed by directory absolute path .
2019-11-02 10:38:58 +01:00
*/
$dirs = apply_filters ( 'icon_dirs' , array ( $icon_dir => $icon_dir_uri ) );
$icon_files = array ();
while ( $dirs ) {
$keys = array_keys ( $dirs );
$dir = array_shift ( $keys );
$uri = array_shift ( $dirs );
2019-11-15 22:59:44 +01:00
$dh = opendir ( $dir );
if ( $dh ) {
2019-11-02 10:38:58 +01:00
while ( false !== $file = readdir ( $dh ) ) {
$file = wp_basename ( $file );
2020-09-15 14:29:22 +02:00
if ( '.' === substr ( $file , 0 , 1 ) ) {
2019-11-02 10:38:58 +01:00
continue ;
}
2020-09-15 14:29:22 +02:00
$ext = strtolower ( substr ( $file , - 4 ) );
if ( ! in_array ( $ext , array ( '.png' , '.gif' , '.jpg' ), true ) ) {
2019-11-02 10:38:58 +01:00
if ( is_dir ( " $dir / $file " ) ) {
$dirs [ " $dir / $file " ] = " $uri / $file " ;
}
continue ;
}
$icon_files [ " $dir / $file " ] = " $uri / $file " ;
}
closedir ( $dh );
}
}
wp_cache_add ( 'icon_files' , $icon_files , 'default' , 600 );
}
$types = array ();
// Icon wp_basename - extension = MIME wildcard.
foreach ( $icon_files as $file => $uri ) {
$types [ preg_replace ( '/^([^.]*).*$/' , '$1' , wp_basename ( $file ) ) ] =& $icon_files [ $file ];
}
if ( ! empty ( $mime ) ) {
$post_mimes [] = substr ( $mime , 0 , strpos ( $mime , '/' ) );
$post_mimes [] = substr ( $mime , strpos ( $mime , '/' ) + 1 );
$post_mimes [] = str_replace ( '/' , '_' , $mime );
}
$matches = wp_match_mime_types ( array_keys ( $types ), $post_mimes );
$matches [ 'default' ] = array ( 'default' );
foreach ( $matches as $match => $wilds ) {
foreach ( $wilds as $wild ) {
if ( ! isset ( $types [ $wild ] ) ) {
continue ;
}
$icon = $types [ $wild ];
if ( ! is_numeric ( $mime ) ) {
wp_cache_add ( " mime_type_icon_ $mime " , $icon );
}
break 2 ;
}
}
}
/**
* Filters the mime type icon .
*
* @ since 2.1 . 0
*
* @ param string $icon Path to the mime type icon .
* @ param string $mime Mime type .
* @ param int $post_id Attachment ID . Will equal 0 if the function passed
* the mime type .
*/
return apply_filters ( 'wp_mime_type_icon' , $icon , $mime , $post_id );
}
/**
2022-12-15 17:47:31 +01:00
* Checks for changed slugs for published post objects and save the old slug .
2019-11-02 10:38:58 +01:00
*
* The function is used when a post object of any type is updated ,
* by comparing the current and previous post objects .
*
* If the slug was changed and not already part of the old slugs then it will be
* added to the post meta field ( '_wp_old_slug' ) for storing old slugs for that
* post .
*
* The most logically usage of this function is redirecting changed post objects , so
* that those that linked to an changed post will be redirected to the new post .
*
* @ since 2.1 . 0
*
* @ param int $post_id Post ID .
2022-12-15 17:47:31 +01:00
* @ param WP_Post $post The post object .
* @ param WP_Post $post_before The previous post object .
2019-11-02 10:38:58 +01:00
*/
function wp_check_for_changed_slugs ( $post_id , $post , $post_before ) {
// Don't bother if it hasn't changed.
if ( $post -> post_name == $post_before -> post_name ) {
return ;
}
// We're only concerned with published, non-hierarchical objects.
if ( ! ( 'publish' === $post -> post_status || ( 'attachment' === get_post_type ( $post ) && 'inherit' === $post -> post_status ) ) || is_post_type_hierarchical ( $post -> post_type ) ) {
return ;
}
$old_slugs = ( array ) get_post_meta ( $post_id , '_wp_old_slug' );
// If we haven't added this old slug before, add it now.
2020-09-15 14:29:22 +02:00
if ( ! empty ( $post_before -> post_name ) && ! in_array ( $post_before -> post_name , $old_slugs , true ) ) {
2019-11-02 10:38:58 +01:00
add_post_meta ( $post_id , '_wp_old_slug' , $post_before -> post_name );
}
// If the new slug was used previously, delete it from the list.
2020-09-15 14:29:22 +02:00
if ( in_array ( $post -> post_name , $old_slugs , true ) ) {
2019-11-02 10:38:58 +01:00
delete_post_meta ( $post_id , '_wp_old_slug' , $post -> post_name );
}
}
/**
2022-12-15 17:47:31 +01:00
* Checks for changed dates for published post objects and save the old date .
2019-11-02 10:38:58 +01:00
*
* The function is used when a post object of any type is updated ,
* by comparing the current and previous post objects .
*
* If the date was changed and not already part of the old dates then it will be
* added to the post meta field ( '_wp_old_date' ) for storing old dates for that
* post .
*
* The most logically usage of this function is redirecting changed post objects , so
* that those that linked to an changed post will be redirected to the new post .
*
* @ since 4.9 . 3
*
* @ param int $post_id Post ID .
2022-12-15 17:47:31 +01:00
* @ param WP_Post $post The post object .
* @ param WP_Post $post_before The previous post object .
2019-11-02 10:38:58 +01:00
*/
function wp_check_for_changed_dates ( $post_id , $post , $post_before ) {
2019-11-15 22:59:44 +01:00
$previous_date = gmdate ( 'Y-m-d' , strtotime ( $post_before -> post_date ) );
$new_date = gmdate ( 'Y-m-d' , strtotime ( $post -> post_date ) );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
// Don't bother if it hasn't changed.
if ( $new_date == $previous_date ) {
return ;
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
// We're only concerned with published, non-hierarchical objects.
if ( ! ( 'publish' === $post -> post_status || ( 'attachment' === get_post_type ( $post ) && 'inherit' === $post -> post_status ) ) || is_post_type_hierarchical ( $post -> post_type ) ) {
return ;
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
$old_dates = ( array ) get_post_meta ( $post_id , '_wp_old_date' );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
// If we haven't added this old date before, add it now.
2020-09-15 14:29:22 +02:00
if ( ! empty ( $previous_date ) && ! in_array ( $previous_date , $old_dates , true ) ) {
2019-11-02 10:38:58 +01:00
add_post_meta ( $post_id , '_wp_old_date' , $previous_date );
}
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
// If the new slug was used previously, delete it from the list.
2020-09-15 14:29:22 +02:00
if ( in_array ( $new_date , $old_dates , true ) ) {
2019-11-02 10:38:58 +01:00
delete_post_meta ( $post_id , '_wp_old_date' , $new_date );
}
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves the private post SQL based on capability .
2019-11-02 10:38:58 +01:00
*
* This function provides a standardized way to appropriately select on the
* post_status of a post type . The function will return a piece of SQL code
* that can be added to a WHERE clause ; this SQL is constructed to allow all
* published posts , and all private posts to which the user has access .
*
* @ since 2.2 . 0
* @ since 4.3 . 0 Added the ability to pass an array to `$post_type` .
*
* @ param string | array $post_type Single post type or an array of post types . Currently only supports 'post' or 'page' .
* @ return string SQL code that can be added to a where clause .
*/
function get_private_posts_cap_sql ( $post_type ) {
return get_posts_by_author_sql ( $post_type , false );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves the post SQL based on capability , author , and type .
2019-11-02 10:38:58 +01:00
*
* @ since 3.0 . 0
* @ since 4.3 . 0 Introduced the ability to pass an array of post types to `$post_type` .
*
* @ see get_private_posts_cap_sql ()
* @ global wpdb $wpdb WordPress database abstraction object .
*
2020-05-06 17:23:38 +02:00
* @ param string | string [] $post_type Single post type or an array of post types .
* @ param bool $full Optional . Returns a full WHERE statement instead of just
* an 'andalso' term . Default true .
* @ param int $post_author Optional . Query posts having a single author ID . Default null .
* @ param bool $public_only Optional . Only return public posts . Skips cap checks for
* $current_user . Default false .
2019-11-02 10:38:58 +01:00
* @ return string SQL WHERE code that can be added to a query .
*/
function get_posts_by_author_sql ( $post_type , $full = true , $post_author = null , $public_only = false ) {
global $wpdb ;
if ( is_array ( $post_type ) ) {
$post_types = $post_type ;
} else {
$post_types = array ( $post_type );
}
$post_type_clauses = array ();
foreach ( $post_types as $post_type ) {
$post_type_obj = get_post_type_object ( $post_type );
2022-12-15 17:47:31 +01:00
2019-11-02 10:38:58 +01:00
if ( ! $post_type_obj ) {
continue ;
}
/**
* Filters the capability to read private posts for a custom post type
* when generating SQL for getting posts by author .
*
* @ since 2.2 . 0
* @ deprecated 3.2 . 0 The hook transitioned from " somewhat useless " to " totally useless " .
*
* @ param string $cap Capability .
*/
2020-05-06 17:23:38 +02:00
$cap = apply_filters_deprecated ( 'pub_priv_sql_capability' , array ( '' ), '3.2.0' );
2022-12-15 17:47:31 +01:00
2019-11-15 22:59:44 +01:00
if ( ! $cap ) {
2019-11-02 10:38:58 +01:00
$cap = current_user_can ( $post_type_obj -> cap -> read_private_posts );
}
// Only need to check the cap if $public_only is false.
$post_status_sql = " post_status = 'publish' " ;
2022-12-15 17:47:31 +01:00
2019-11-02 10:38:58 +01:00
if ( false === $public_only ) {
if ( $cap ) {
// Does the user have the capability to view private posts? Guess so.
$post_status_sql .= " OR post_status = 'private' " ;
} elseif ( is_user_logged_in () ) {
// Users can view their own private posts.
$id = get_current_user_id ();
if ( null === $post_author || ! $full ) {
$post_status_sql .= " OR post_status = 'private' AND post_author = $id " ;
} elseif ( $id == ( int ) $post_author ) {
$post_status_sql .= " OR post_status = 'private' " ;
2020-05-06 17:23:38 +02:00
} // Else none.
} // Else none.
2019-11-02 10:38:58 +01:00
}
$post_type_clauses [] = " ( post_type = ' " . $post_type . " ' AND ( $post_status_sql ) ) " ;
}
if ( empty ( $post_type_clauses ) ) {
return $full ? 'WHERE 1 = 0' : '1 = 0' ;
}
$sql = '( ' . implode ( ' OR ' , $post_type_clauses ) . ' )' ;
if ( null !== $post_author ) {
$sql .= $wpdb -> prepare ( ' AND post_author = %d' , $post_author );
}
if ( $full ) {
$sql = 'WHERE ' . $sql ;
}
return $sql ;
}
/**
2019-11-15 22:59:44 +01:00
* Retrieves the most recent time that a post on the site was published .
2019-11-02 10:38:58 +01:00
*
* The server timezone is the default and is the difference between GMT and
2020-09-15 14:29:22 +02:00
* server time . The 'blog' value is the date when the last post was posted .
* The 'gmt' is when the last post was posted in GMT formatted date .
2019-11-02 10:38:58 +01:00
*
* @ since 0.71
* @ since 4.4 . 0 The `$post_type` argument was added .
*
* @ param string $timezone Optional . The timezone for the timestamp . Accepts 'server' , 'blog' , or 'gmt' .
* 'server' uses the server ' s internal timezone .
2019-11-15 22:59:44 +01:00
* 'blog' uses the `post_date` field , which proxies to the timezone set for the site .
* 'gmt' uses the `post_date_gmt` field .
2019-11-02 10:38:58 +01:00
* Default 'server' .
* @ param string $post_type Optional . The post type to check . Default 'any' .
2020-01-26 12:53:20 +01:00
* @ return string The date of the last post , or false on failure .
2019-11-02 10:38:58 +01:00
*/
function get_lastpostdate ( $timezone = 'server' , $post_type = 'any' ) {
2020-09-15 14:29:22 +02:00
$lastpostdate = _get_last_post_time ( $timezone , 'date' , $post_type );
2019-11-02 10:38:58 +01:00
/**
2019-11-15 22:59:44 +01:00
* Filters the most recent time that a post on the site was published .
2019-11-02 10:38:58 +01:00
*
* @ since 2.3 . 0
2020-09-15 14:29:22 +02:00
* @ since 5.5 . 0 Added the `$post_type` parameter .
2019-11-02 10:38:58 +01:00
*
2020-09-15 14:29:22 +02:00
* @ param string | false $lastpostdate The most recent time that a post was published ,
* in 'Y-m-d H:i:s' format . False on failure .
* @ param string $timezone Location to use for getting the post published date .
* See get_lastpostdate () for accepted `$timezone` values .
* @ param string $post_type The post type to check .
2019-11-02 10:38:58 +01:00
*/
2020-09-15 14:29:22 +02:00
return apply_filters ( 'get_lastpostdate' , $lastpostdate , $timezone , $post_type );
2019-11-02 10:38:58 +01:00
}
/**
2022-12-15 17:47:31 +01:00
* Gets the most recent time that a post on the site was modified .
2019-11-02 10:38:58 +01:00
*
* The server timezone is the default and is the difference between GMT and
2020-09-15 14:29:22 +02:00
* server time . The 'blog' value is just when the last post was modified .
* The 'gmt' is when the last post was modified in GMT time .
2019-11-02 10:38:58 +01:00
*
* @ since 1.2 . 0
* @ since 4.4 . 0 The `$post_type` argument was added .
*
* @ param string $timezone Optional . The timezone for the timestamp . See get_lastpostdate ()
* for information on accepted values .
* Default 'server' .
* @ param string $post_type Optional . The post type to check . Default 'any' .
2020-01-26 12:53:20 +01:00
* @ return string The timestamp in 'Y-m-d H:i:s' format , or false on failure .
2019-11-02 10:38:58 +01:00
*/
function get_lastpostmodified ( $timezone = 'server' , $post_type = 'any' ) {
/**
* Pre - filter the return value of get_lastpostmodified () before the query is run .
*
* @ since 4.4 . 0
*
2020-09-15 14:29:22 +02:00
* @ param string | false $lastpostmodified The most recent time that a post was modified ,
* in 'Y-m-d H:i:s' format , or false . Returning anything
* other than false will short - circuit the function .
2019-11-15 22:59:44 +01:00
* @ param string $timezone Location to use for getting the post modified date .
* See get_lastpostdate () for accepted `$timezone` values .
* @ param string $post_type The post type to check .
2019-11-02 10:38:58 +01:00
*/
$lastpostmodified = apply_filters ( 'pre_get_lastpostmodified' , false , $timezone , $post_type );
2020-09-15 14:29:22 +02:00
2019-11-02 10:38:58 +01:00
if ( false !== $lastpostmodified ) {
return $lastpostmodified ;
}
$lastpostmodified = _get_last_post_time ( $timezone , 'modified' , $post_type );
2020-09-15 14:29:22 +02:00
$lastpostdate = get_lastpostdate ( $timezone , $post_type );
2019-11-02 10:38:58 +01:00
if ( $lastpostdate > $lastpostmodified ) {
$lastpostmodified = $lastpostdate ;
}
/**
2020-09-15 14:29:22 +02:00
* Filters the most recent time that a post on the site was modified .
2019-11-02 10:38:58 +01:00
*
* @ since 2.3 . 0
2020-09-15 14:29:22 +02:00
* @ since 5.5 . 0 Added the `$post_type` parameter .
2019-11-02 10:38:58 +01:00
*
2020-09-15 14:29:22 +02:00
* @ param string | false $lastpostmodified The most recent time that a post was modified ,
* in 'Y-m-d H:i:s' format . False on failure .
2020-01-26 12:53:20 +01:00
* @ param string $timezone Location to use for getting the post modified date .
* See get_lastpostdate () for accepted `$timezone` values .
2020-09-15 14:29:22 +02:00
* @ param string $post_type The post type to check .
2019-11-02 10:38:58 +01:00
*/
2020-09-15 14:29:22 +02:00
return apply_filters ( 'get_lastpostmodified' , $lastpostmodified , $timezone , $post_type );
2019-11-02 10:38:58 +01:00
}
/**
2019-11-15 22:59:44 +01:00
* Gets the timestamp of the last time any post was modified or published .
2019-11-02 10:38:58 +01:00
*
* @ since 3.1 . 0
* @ since 4.4 . 0 The `$post_type` argument was added .
* @ access private
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param string $timezone The timezone for the timestamp . See get_lastpostdate () .
* for information on accepted values .
* @ param string $field Post field to check . Accepts 'date' or 'modified' .
* @ param string $post_type Optional . The post type to check . Default 'any' .
2020-01-26 12:53:20 +01:00
* @ return string | false The timestamp in 'Y-m-d H:i:s' format , or false on failure .
2019-11-02 10:38:58 +01:00
*/
function _get_last_post_time ( $timezone , $field , $post_type = 'any' ) {
global $wpdb ;
2020-09-15 14:29:22 +02:00
if ( ! in_array ( $field , array ( 'date' , 'modified' ), true ) ) {
2019-11-02 10:38:58 +01:00
return false ;
}
$timezone = strtolower ( $timezone );
$key = " lastpost { $field } : $timezone " ;
if ( 'any' !== $post_type ) {
$key .= ':' . sanitize_key ( $post_type );
}
$date = wp_cache_get ( $key , 'timeinfo' );
if ( false !== $date ) {
return $date ;
}
if ( 'any' === $post_type ) {
$post_types = get_post_types ( array ( 'public' => true ) );
array_walk ( $post_types , array ( $wpdb , 'escape_by_ref' ) );
$post_types = " ' " . implode ( " ', ' " , $post_types ) . " ' " ;
} else {
$post_types = " ' " . sanitize_key ( $post_type ) . " ' " ;
}
switch ( $timezone ) {
case 'gmt' :
$date = $wpdb -> get_var ( " SELECT post_ { $field } _gmt FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ( { $post_types } ) ORDER BY post_ { $field } _gmt DESC LIMIT 1 " );
break ;
case 'blog' :
$date = $wpdb -> get_var ( " SELECT post_ { $field } FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ( { $post_types } ) ORDER BY post_ { $field } _gmt DESC LIMIT 1 " );
break ;
case 'server' :
2019-11-15 22:59:44 +01:00
$add_seconds_server = gmdate ( 'Z' );
2019-11-02 10:38:58 +01:00
$date = $wpdb -> get_var ( " SELECT DATE_ADD(post_ { $field } _gmt, INTERVAL ' $add_seconds_server ' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ( { $post_types } ) ORDER BY post_ { $field } _gmt DESC LIMIT 1 " );
break ;
}
if ( $date ) {
wp_cache_set ( $key , $date , 'timeinfo' );
return $date ;
}
return false ;
}
/**
* Updates posts in cache .
*
* @ since 1.5 . 1
*
2019-11-15 22:59:44 +01:00
* @ param WP_Post [] $posts Array of post objects ( passed by reference ) .
2019-11-02 10:38:58 +01:00
*/
function update_post_cache ( & $posts ) {
if ( ! $posts ) {
return ;
}
2022-06-16 14:03:35 +02:00
$data = array ();
2019-11-02 10:38:58 +01:00
foreach ( $posts as $post ) {
2022-06-16 14:03:35 +02:00
if ( empty ( $post -> filter ) || 'raw' !== $post -> filter ) {
$post = sanitize_post ( $post , 'raw' );
}
$data [ $post -> ID ] = $post ;
2019-11-02 10:38:58 +01:00
}
2022-06-16 14:03:35 +02:00
wp_cache_add_multiple ( $data , 'posts' );
2019-11-02 10:38:58 +01:00
}
/**
* Will clean the post in the cache .
*
* Cleaning means delete from the cache of the post . Will call to clean the term
* object cache associated with the post ID .
*
* This function not run if $_wp_suspend_cache_invalidation is not empty . See
* wp_suspend_cache_invalidation () .
*
* @ since 2.0 . 0
*
* @ global bool $_wp_suspend_cache_invalidation
*
* @ param int | WP_Post $post Post ID or post object to remove from the cache .
*/
function clean_post_cache ( $post ) {
global $_wp_suspend_cache_invalidation ;
if ( ! empty ( $_wp_suspend_cache_invalidation ) ) {
return ;
}
$post = get_post ( $post );
2020-12-10 14:06:04 +01:00
if ( ! $post ) {
2019-11-02 10:38:58 +01:00
return ;
}
wp_cache_delete ( $post -> ID , 'posts' );
wp_cache_delete ( $post -> ID , 'post_meta' );
clean_object_term_cache ( $post -> ID , $post -> post_type );
wp_cache_delete ( 'wp_get_archives' , 'general' );
/**
* Fires immediately after the given post ' s cache is cleaned .
*
* @ since 2.5 . 0
*
* @ param int $post_id Post ID .
* @ param WP_Post $post Post object .
*/
do_action ( 'clean_post_cache' , $post -> ID , $post );
2020-09-15 14:29:22 +02:00
if ( 'page' === $post -> post_type ) {
2019-11-02 10:38:58 +01:00
wp_cache_delete ( 'all_page_ids' , 'posts' );
/**
* Fires immediately after the given page ' s cache is cleaned .
*
* @ since 2.5 . 0
*
* @ param int $post_id Post ID .
*/
do_action ( 'clean_page_cache' , $post -> ID );
}
wp_cache_set ( 'last_changed' , microtime (), 'posts' );
}
/**
2022-12-15 17:47:31 +01:00
* Updates post , term , and metadata caches for a list of post objects .
2019-11-02 10:38:58 +01:00
*
* @ since 1.5 . 0
*
2022-12-15 17:47:31 +01:00
* @ param WP_Post [] $posts Array of post objects ( passed by reference ) .
2019-11-15 22:59:44 +01:00
* @ param string $post_type Optional . Post type . Default 'post' .
* @ param bool $update_term_cache Optional . Whether to update the term cache . Default true .
* @ param bool $update_meta_cache Optional . Whether to update the meta cache . Default true .
2019-11-02 10:38:58 +01:00
*/
function update_post_caches ( & $posts , $post_type = 'post' , $update_term_cache = true , $update_meta_cache = true ) {
// No point in doing all this work if we didn't match any posts.
if ( ! $posts ) {
return ;
}
update_post_cache ( $posts );
$post_ids = array ();
foreach ( $posts as $post ) {
$post_ids [] = $post -> ID ;
}
if ( ! $post_type ) {
$post_type = 'any' ;
}
if ( $update_term_cache ) {
if ( is_array ( $post_type ) ) {
$ptypes = $post_type ;
2020-09-15 14:29:22 +02:00
} elseif ( 'any' === $post_type ) {
2019-11-02 10:38:58 +01:00
$ptypes = array ();
// Just use the post_types in the supplied posts.
foreach ( $posts as $post ) {
$ptypes [] = $post -> post_type ;
}
$ptypes = array_unique ( $ptypes );
} else {
$ptypes = array ( $post_type );
}
if ( ! empty ( $ptypes ) ) {
update_object_term_cache ( $post_ids , $ptypes );
}
}
if ( $update_meta_cache ) {
update_postmeta_cache ( $post_ids );
}
}
/**
2022-12-15 17:47:31 +01:00
* Updates post author user caches for a list of post objects .
*
* @ since 6.1 . 0
*
* @ param WP_Post [] $posts Array of post objects .
*/
function update_post_author_caches ( $posts ) {
/*
* cache_users () is a pluggable function so is not available prior
* to the `plugins_loaded` hook firing . This is to ensure against
* fatal errors when the function is not available .
*/
if ( ! function_exists ( 'cache_users' ) ) {
return ;
}
$author_ids = wp_list_pluck ( $posts , 'post_author' );
$author_ids = array_map ( 'absint' , $author_ids );
$author_ids = array_unique ( array_filter ( $author_ids ) );
cache_users ( $author_ids );
}
/**
* Updates parent post caches for a list of post objects .
*
* @ since 6.1 . 0
*
* @ param WP_Post [] $posts Array of post objects .
*/
function update_post_parent_caches ( $posts ) {
$parent_ids = wp_list_pluck ( $posts , 'post_parent' );
$parent_ids = array_map ( 'absint' , $parent_ids );
$parent_ids = array_unique ( array_filter ( $parent_ids ) );
if ( ! empty ( $parent_ids ) ) {
_prime_post_caches ( $parent_ids , false );
}
}
/**
* Updates metadata cache for a list of post IDs .
2019-11-02 10:38:58 +01:00
*
* Performs SQL query to retrieve the metadata for the post IDs and updates the
* metadata cache for the posts . Therefore , the functions , which call this
* function , do not need to perform SQL queries on their own .
*
* @ since 2.1 . 0
*
2019-11-15 22:59:44 +01:00
* @ param int [] $post_ids Array of post IDs .
2020-09-15 14:29:22 +02:00
* @ return array | false An array of metadata on success , false if there is nothing to update .
2019-11-02 10:38:58 +01:00
*/
function update_postmeta_cache ( $post_ids ) {
return update_meta_cache ( 'post' , $post_ids );
}
/**
* Will clean the attachment in the cache .
*
* Cleaning means delete from the cache . Optionally will clean the term
* object cache associated with the attachment ID .
*
* This function will not run if $_wp_suspend_cache_invalidation is not empty .
*
* @ since 3.0 . 0
*
* @ global bool $_wp_suspend_cache_invalidation
*
* @ param int $id The attachment ID in the cache to clean .
* @ param bool $clean_terms Optional . Whether to clean terms cache . Default false .
*/
function clean_attachment_cache ( $id , $clean_terms = false ) {
global $_wp_suspend_cache_invalidation ;
if ( ! empty ( $_wp_suspend_cache_invalidation ) ) {
return ;
}
$id = ( int ) $id ;
wp_cache_delete ( $id , 'posts' );
wp_cache_delete ( $id , 'post_meta' );
if ( $clean_terms ) {
clean_object_term_cache ( $id , 'attachment' );
}
/**
* Fires after the given attachment ' s cache is cleaned .
*
* @ since 3.0 . 0
*
* @ param int $id Attachment ID .
*/
do_action ( 'clean_attachment_cache' , $id );
}
//
2020-05-06 17:23:38 +02:00
// Hooks.
2019-11-02 10:38:58 +01:00
//
/**
* Hook for managing future post transitions to published .
*
* @ since 2.3 . 0
* @ access private
*
* @ see wp_clear_scheduled_hook ()
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param string $new_status New post status .
* @ param string $old_status Previous post status .
* @ param WP_Post $post Post object .
*/
function _transition_post_status ( $new_status , $old_status , $post ) {
global $wpdb ;
2020-05-06 17:23:38 +02:00
if ( 'publish' !== $old_status && 'publish' === $new_status ) {
2019-11-02 10:38:58 +01:00
// Reset GUID if transitioning to publish and it is empty.
2020-09-15 14:29:22 +02:00
if ( '' === get_the_guid ( $post -> ID ) ) {
2019-11-02 10:38:58 +01:00
$wpdb -> update ( $wpdb -> posts , array ( 'guid' => get_permalink ( $post -> ID ) ), array ( 'ID' => $post -> ID ) );
}
/**
* Fires when a post ' s status is transitioned from private to published .
*
* @ since 1.5 . 0
2020-05-06 17:23:38 +02:00
* @ deprecated 2.3 . 0 Use { @ see 'private_to_publish' } instead .
2019-11-02 10:38:58 +01:00
*
* @ param int $post_id Post ID .
*/
2020-05-06 17:23:38 +02:00
do_action_deprecated ( 'private_to_published' , array ( $post -> ID ), '2.3.0' , 'private_to_publish' );
2019-11-02 10:38:58 +01:00
}
// If published posts changed clear the lastpostmodified cache.
2020-09-15 14:29:22 +02:00
if ( 'publish' === $new_status || 'publish' === $old_status ) {
2019-11-02 10:38:58 +01:00
foreach ( array ( 'server' , 'gmt' , 'blog' ) as $timezone ) {
wp_cache_delete ( " lastpostmodified: $timezone " , 'timeinfo' );
wp_cache_delete ( " lastpostdate: $timezone " , 'timeinfo' );
wp_cache_delete ( " lastpostdate: $timezone : { $post -> post_type } " , 'timeinfo' );
}
}
if ( $new_status !== $old_status ) {
wp_cache_delete ( _count_posts_cache_key ( $post -> post_type ), 'counts' );
wp_cache_delete ( _count_posts_cache_key ( $post -> post_type , 'readable' ), 'counts' );
}
// Always clears the hook in case the post status bounced from future to draft.
wp_clear_scheduled_hook ( 'publish_future_post' , array ( $post -> ID ) );
}
/**
* Hook used to schedule publication for a post marked for the future .
*
* The $post properties used and must exist are 'ID' and 'post_date_gmt' .
*
* @ since 2.3 . 0
* @ access private
*
* @ param int $deprecated Not used . Can be set to null . Never implemented . Not marked
* as deprecated with _deprecated_argument () as it conflicts with
* wp_transition_post_status () and the default filter for _future_post_hook () .
* @ param WP_Post $post Post object .
*/
function _future_post_hook ( $deprecated , $post ) {
wp_clear_scheduled_hook ( 'publish_future_post' , array ( $post -> ID ) );
wp_schedule_single_event ( strtotime ( get_gmt_from_date ( $post -> post_date ) . ' GMT' ), 'publish_future_post' , array ( $post -> ID ) );
}
/**
* Hook to schedule pings and enclosures when a post is published .
*
* Uses XMLRPC_REQUEST and WP_IMPORTING constants .
*
* @ since 2.3 . 0
* @ access private
*
2022-04-02 10:26:41 +02:00
* @ param int $post_id The ID of the post being published .
2019-11-02 10:38:58 +01:00
*/
function _publish_post_hook ( $post_id ) {
if ( defined ( 'XMLRPC_REQUEST' ) ) {
/**
* Fires when _publish_post_hook () is called during an XML - RPC request .
*
* @ since 2.1 . 0
*
* @ param int $post_id Post ID .
*/
do_action ( 'xmlrpc_publish_post' , $post_id );
}
if ( defined ( 'WP_IMPORTING' ) ) {
return ;
}
if ( get_option ( 'default_pingback_flag' ) ) {
2019-11-15 22:59:44 +01:00
add_post_meta ( $post_id , '_pingme' , '1' , true );
}
add_post_meta ( $post_id , '_encloseme' , '1' , true );
$to_ping = get_to_ping ( $post_id );
if ( ! empty ( $to_ping ) ) {
add_post_meta ( $post_id , '_trackbackme' , '1' );
2019-11-02 10:38:58 +01:00
}
if ( ! wp_next_scheduled ( 'do_pings' ) ) {
wp_schedule_single_event ( time (), 'do_pings' );
}
}
/**
* Returns the ID of the post ' s parent .
*
* @ since 3.1 . 0
2022-04-02 10:26:41 +02:00
* @ since 5.9 . 0 The `$post` parameter was made optional .
2019-11-02 10:38:58 +01:00
*
2022-04-02 10:26:41 +02:00
* @ param int | WP_Post | null $post Optional . Post ID or post object . Defaults to global $post .
2020-09-15 14:29:22 +02:00
* @ return int | false Post parent ID ( which can be 0 if there is no parent ),
* or false if the post does not exist .
2019-11-02 10:38:58 +01:00
*/
2022-04-02 10:26:41 +02:00
function wp_get_post_parent_id ( $post = null ) {
2019-11-02 10:38:58 +01:00
$post = get_post ( $post );
2022-12-15 17:47:31 +01:00
2019-11-02 10:38:58 +01:00
if ( ! $post || is_wp_error ( $post ) ) {
return false ;
}
2022-12-15 17:47:31 +01:00
2019-11-02 10:38:58 +01:00
return ( int ) $post -> post_parent ;
}
/**
2022-12-15 17:47:31 +01:00
* Checks the given subset of the post hierarchy for hierarchy loops .
2019-11-02 10:38:58 +01:00
*
* Prevents loops from forming and breaks those that it finds . Attached
* to the { @ see 'wp_insert_post_parent' } filter .
*
* @ since 3.1 . 0
*
* @ see wp_find_hierarchy_loop ()
*
* @ param int $post_parent ID of the parent for the post we ' re checking .
2023-04-26 17:39:43 +02:00
* @ param int $post_id ID of the post we ' re checking .
2019-11-02 10:38:58 +01:00
* @ return int The new post_parent for the post , 0 otherwise .
*/
2023-04-26 17:39:43 +02:00
function wp_check_post_hierarchy_for_loops ( $post_parent , $post_id ) {
2019-11-02 10:38:58 +01:00
// Nothing fancy here - bail.
if ( ! $post_parent ) {
return 0 ;
}
// New post can't cause a loop.
2023-04-26 17:39:43 +02:00
if ( ! $post_id ) {
2019-11-02 10:38:58 +01:00
return $post_parent ;
}
// Can't be its own parent.
2023-04-26 17:39:43 +02:00
if ( $post_parent == $post_id ) {
2019-11-02 10:38:58 +01:00
return 0 ;
}
// Now look for larger loops.
2023-04-26 17:39:43 +02:00
$loop = wp_find_hierarchy_loop ( 'wp_get_post_parent_id' , $post_id , $post_parent );
2019-11-15 22:59:44 +01:00
if ( ! $loop ) {
2020-05-06 17:23:38 +02:00
return $post_parent ; // No loop.
2019-11-02 10:38:58 +01:00
}
// Setting $post_parent to the given value causes a loop.
2023-04-26 17:39:43 +02:00
if ( isset ( $loop [ $post_id ] ) ) {
2019-11-02 10:38:58 +01:00
return 0 ;
}
2023-04-26 17:39:43 +02:00
// There's a loop, but it doesn't contain $post_id. Break the loop.
2019-11-02 10:38:58 +01:00
foreach ( array_keys ( $loop ) as $loop_member ) {
wp_update_post (
array (
'ID' => $loop_member ,
'post_parent' => 0 ,
)
);
}
return $post_parent ;
}
/**
* Sets the post thumbnail ( featured image ) for the given post .
*
* @ since 3.1 . 0
*
* @ param int | WP_Post $post Post ID or post object where thumbnail should be attached .
* @ param int $thumbnail_id Thumbnail to attach .
* @ return int | bool True on success , false on failure .
*/
function set_post_thumbnail ( $post , $thumbnail_id ) {
$post = get_post ( $post );
$thumbnail_id = absint ( $thumbnail_id );
if ( $post && $thumbnail_id && get_post ( $thumbnail_id ) ) {
if ( wp_get_attachment_image ( $thumbnail_id , 'thumbnail' ) ) {
return update_post_meta ( $post -> ID , '_thumbnail_id' , $thumbnail_id );
} else {
return delete_post_meta ( $post -> ID , '_thumbnail_id' );
}
}
return false ;
}
/**
* Removes the thumbnail ( featured image ) from the given post .
*
* @ since 3.3 . 0
*
* @ param int | WP_Post $post Post ID or post object from which the thumbnail should be removed .
* @ return bool True on success , false on failure .
*/
function delete_post_thumbnail ( $post ) {
$post = get_post ( $post );
if ( $post ) {
return delete_post_meta ( $post -> ID , '_thumbnail_id' );
}
return false ;
}
/**
2022-12-15 17:47:31 +01:00
* Deletes auto - drafts for new posts that are > 7 days old .
2019-11-02 10:38:58 +01:00
*
* @ since 3.4 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*/
function wp_delete_auto_drafts () {
global $wpdb ;
// Cleanup old auto-drafts more than 7 days old.
$old_posts = $wpdb -> get_col ( " SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft' AND DATE_SUB( NOW(), INTERVAL 7 DAY ) > post_date " );
foreach ( ( array ) $old_posts as $delete ) {
// Force delete.
wp_delete_post ( $delete , true );
}
}
/**
* Queues posts for lazy - loading of term meta .
*
* @ since 4.5 . 0
*
2022-12-15 17:47:31 +01:00
* @ param WP_Post [] $posts Array of WP_Post objects .
2019-11-02 10:38:58 +01:00
*/
function wp_queue_posts_for_term_meta_lazyload ( $posts ) {
2019-11-15 22:59:44 +01:00
$post_type_taxonomies = array ();
2023-04-26 17:39:43 +02:00
$prime_post_terms = array ();
2019-11-02 10:38:58 +01:00
foreach ( $posts as $post ) {
if ( ! ( $post instanceof WP_Post ) ) {
continue ;
}
if ( ! isset ( $post_type_taxonomies [ $post -> post_type ] ) ) {
$post_type_taxonomies [ $post -> post_type ] = get_object_taxonomies ( $post -> post_type );
}
foreach ( $post_type_taxonomies [ $post -> post_type ] as $taxonomy ) {
2023-04-26 17:39:43 +02:00
$prime_post_terms [ $taxonomy ][] = $post -> ID ;
}
}
$term_ids = array ();
if ( $prime_post_terms ) {
$prime_term_ids = array ();
$prime_taxonomy_ids = array ();
foreach ( $prime_post_terms as $taxonomy => $post_ids ) {
$cached_term_ids = wp_cache_get_multiple ( $post_ids , " { $taxonomy } _relationships " );
if ( is_array ( $cached_term_ids ) ) {
$cached_term_ids = array_filter ( $cached_term_ids );
foreach ( $cached_term_ids as $_term_ids ) {
// Backward compatibility for if a plugin is putting objects into the cache, rather than IDs.
foreach ( $_term_ids as $term_id ) {
if ( is_numeric ( $term_id ) ) {
$prime_term_ids [] = ( int ) $term_id ;
$prime_taxonomy_ids [ $taxonomy ][] = ( int ) $term_id ;
} elseif ( isset ( $term_id -> term_id ) ) {
$prime_taxonomy_ids [ $taxonomy ][] = ( int ) $term_id -> term_id ;
$prime_term_ids [] = ( int ) $term_id -> term_id ;
}
}
}
}
}
if ( $prime_term_ids ) {
$prime_term_ids = array_unique ( $prime_term_ids );
// Do not prime term meta at this point, let the lazy loader take care of that.
_prime_term_caches ( $prime_term_ids , false );
foreach ( $prime_taxonomy_ids as $taxonomy => $_term_ids ) {
foreach ( $_term_ids as $term_id ) {
if ( in_array ( $term_id , $term_ids , true ) ) {
continue ;
}
$term = get_term ( $term_id , $taxonomy );
if ( is_wp_error ( $term ) ) {
continue ;
2019-11-02 10:38:58 +01:00
}
2023-04-26 17:39:43 +02:00
$term_ids [] = $term_id ;
2019-11-02 10:38:58 +01:00
}
}
}
}
if ( $term_ids ) {
$lazyloader = wp_metadata_lazyloader ();
$lazyloader -> queue_objects ( 'term' , $term_ids );
}
}
/**
2022-12-15 17:47:31 +01:00
* Updates the custom taxonomies ' term counts when a post' s status is changed .
2019-11-02 10:38:58 +01:00
*
* For example , default posts term counts ( for custom taxonomies ) don ' t include
* private / draft posts .
*
* @ since 3.3 . 0
* @ access private
*
* @ param string $new_status New post status .
* @ param string $old_status Old post status .
* @ param WP_Post $post Post object .
*/
function _update_term_count_on_transition_post_status ( $new_status , $old_status , $post ) {
// Update counts for the post's terms.
foreach ( ( array ) get_object_taxonomies ( $post -> post_type ) as $taxonomy ) {
$tt_ids = wp_get_object_terms ( $post -> ID , $taxonomy , array ( 'fields' => 'tt_ids' ) );
wp_update_term_count ( $tt_ids , $taxonomy );
}
}
/**
2021-07-23 11:58:50 +02:00
* Adds any posts from the given IDs to the cache that do not already exist in cache .
2019-11-02 10:38:58 +01:00
*
* @ since 3.4 . 0
2022-12-15 17:47:31 +01:00
* @ since 6.1 . 0 This function is no longer marked as " private " .
2019-11-02 10:38:58 +01:00
*
2023-04-26 17:39:43 +02:00
* @ see update_post_cache ()
* @ see update_postmeta_cache ()
* @ see update_object_term_cache ()
2019-11-02 10:38:58 +01:00
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
2022-12-15 17:47:31 +01:00
* @ param int [] $ids ID list .
2019-11-02 10:38:58 +01:00
* @ param bool $update_term_cache Optional . Whether to update the term cache . Default true .
* @ param bool $update_meta_cache Optional . Whether to update the meta cache . Default true .
*/
function _prime_post_caches ( $ids , $update_term_cache = true , $update_meta_cache = true ) {
global $wpdb ;
$non_cached_ids = _get_non_cached_ids ( $ids , 'posts' );
if ( ! empty ( $non_cached_ids ) ) {
2020-12-10 14:06:04 +01:00
$fresh_posts = $wpdb -> get_results ( sprintf ( " SELECT $wpdb->posts .* FROM $wpdb->posts WHERE ID IN (%s) " , implode ( ',' , $non_cached_ids ) ) );
2019-11-02 10:38:58 +01:00
2023-04-26 17:39:43 +02:00
if ( $fresh_posts ) {
// Despite the name, update_post_cache() expects an array rather than a single post.
update_post_cache ( $fresh_posts );
}
}
if ( $update_meta_cache ) {
update_postmeta_cache ( $ids );
}
if ( $update_term_cache ) {
$post_types = array_map ( 'get_post_type' , $ids );
$post_types = array_unique ( $post_types );
update_object_term_cache ( $ids , $post_types );
2019-11-02 10:38:58 +01:00
}
}
/**
* Adds a suffix if any trashed posts have a given slug .
*
* Store its desired ( i . e . current ) slug so it can try to reclaim it
* if the post is untrashed .
*
* For internal use .
*
* @ since 4.5 . 0
* @ access private
*
2022-04-02 10:26:41 +02:00
* @ param string $post_name Post slug .
2023-04-26 17:39:43 +02:00
* @ param int $post_id Optional . Post ID that should be ignored . Default 0.
2019-11-02 10:38:58 +01:00
*/
2023-04-26 17:39:43 +02:00
function wp_add_trashed_suffix_to_post_name_for_trashed_posts ( $post_name , $post_id = 0 ) {
2019-11-02 10:38:58 +01:00
$trashed_posts_with_desired_slug = get_posts (
array (
'name' => $post_name ,
'post_status' => 'trash' ,
'post_type' => 'any' ,
'nopaging' => true ,
2023-04-26 17:39:43 +02:00
'post__not_in' => array ( $post_id ),
2019-11-02 10:38:58 +01:00
)
);
if ( ! empty ( $trashed_posts_with_desired_slug ) ) {
foreach ( $trashed_posts_with_desired_slug as $_post ) {
wp_add_trashed_suffix_to_post_name_for_post ( $_post );
}
}
}
/**
* Adds a trashed suffix for a given post .
*
* Store its desired ( i . e . current ) slug so it can try to reclaim it
* if the post is untrashed .
*
* For internal use .
*
* @ since 4.5 . 0
* @ access private
*
2023-04-26 17:39:43 +02:00
* @ global wpdb $wpdb WordPress database abstraction object .
*
2019-11-02 10:38:58 +01:00
* @ param WP_Post $post The post .
* @ return string New slug for the post .
*/
function wp_add_trashed_suffix_to_post_name_for_post ( $post ) {
global $wpdb ;
$post = get_post ( $post );
if ( '__trashed' === substr ( $post -> post_name , - 9 ) ) {
return $post -> post_name ;
}
add_post_meta ( $post -> ID , '_wp_desired_post_slug' , $post -> post_name );
$post_name = _truncate_post_slug ( $post -> post_name , 191 ) . '__trashed' ;
$wpdb -> update ( $wpdb -> posts , array ( 'post_name' => $post_name ), array ( 'ID' => $post -> ID ) );
clean_post_cache ( $post -> ID );
return $post_name ;
}
/**
* Sets the last changed time for the 'posts' cache group .
*
* @ since 5.0 . 0
*/
function wp_cache_set_posts_last_changed () {
wp_cache_set ( 'last_changed' , microtime (), 'posts' );
}
/**
2022-12-15 17:47:31 +01:00
* Gets all available post MIME types for a given post type .
2019-11-02 10:38:58 +01:00
*
* @ since 2.5 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param string $type
2022-12-15 17:47:31 +01:00
* @ return string [] An array of MIME types .
2019-11-02 10:38:58 +01:00
*/
function get_available_post_mime_types ( $type = 'attachment' ) {
global $wpdb ;
$types = $wpdb -> get_col ( $wpdb -> prepare ( " SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s " , $type ) );
return $types ;
}
2019-11-15 22:59:44 +01:00
/**
* Retrieves the path to an uploaded image file .
*
* Similar to `get_attached_file()` however some images may have been processed after uploading
* to make them suitable for web use . In this case the attached " full " size file is usually replaced
* with a scaled down version of the original image . This function always returns the path
* to the originally uploaded image file .
*
* @ since 5.3 . 0
2020-05-06 17:23:38 +02:00
* @ since 5.4 . 0 Added the `$unfiltered` parameter .
2019-11-15 22:59:44 +01:00
*
2020-05-06 17:23:38 +02:00
* @ param int $attachment_id Attachment ID .
* @ param bool $unfiltered Optional . Passed through to `get_attached_file()` . Default false .
2019-11-15 22:59:44 +01:00
* @ return string | false Path to the original image file or false if the attachment is not an image .
*/
2020-05-06 17:23:38 +02:00
function wp_get_original_image_path ( $attachment_id , $unfiltered = false ) {
2019-11-15 22:59:44 +01:00
if ( ! wp_attachment_is_image ( $attachment_id ) ) {
return false ;
}
$image_meta = wp_get_attachment_metadata ( $attachment_id );
2020-05-06 17:23:38 +02:00
$image_file = get_attached_file ( $attachment_id , $unfiltered );
2019-11-15 22:59:44 +01:00
if ( empty ( $image_meta [ 'original_image' ] ) ) {
$original_image = $image_file ;
} else {
$original_image = path_join ( dirname ( $image_file ), $image_meta [ 'original_image' ] );
}
/**
* Filters the path to the original image .
*
* @ since 5.3 . 0
*
* @ param string $original_image Path to original image file .
* @ param int $attachment_id Attachment ID .
*/
return apply_filters ( 'wp_get_original_image_path' , $original_image , $attachment_id );
}
/**
2022-12-15 17:47:31 +01:00
* Retrieves the URL to an original attachment image .
2019-11-15 22:59:44 +01:00
*
* Similar to `wp_get_attachment_url()` however some images may have been
* processed after uploading . In this case this function returns the URL
* to the originally uploaded image file .
*
* @ since 5.3 . 0
*
* @ param int $attachment_id Attachment post ID .
* @ return string | false Attachment image URL , false on error or if the attachment is not an image .
*/
function wp_get_original_image_url ( $attachment_id ) {
if ( ! wp_attachment_is_image ( $attachment_id ) ) {
return false ;
}
$image_url = wp_get_attachment_url ( $attachment_id );
2020-12-10 14:06:04 +01:00
if ( ! $image_url ) {
2019-11-15 22:59:44 +01:00
return false ;
}
$image_meta = wp_get_attachment_metadata ( $attachment_id );
if ( empty ( $image_meta [ 'original_image' ] ) ) {
$original_image_url = $image_url ;
} else {
$original_image_url = path_join ( dirname ( $image_url ), $image_meta [ 'original_image' ] );
}
/**
* Filters the URL to the original attachment image .
*
* @ since 5.3 . 0
*
* @ param string $original_image_url URL to original image .
* @ param int $attachment_id Attachment ID .
*/
return apply_filters ( 'wp_get_original_image_url' , $original_image_url , $attachment_id );
}
2020-12-10 14:06:04 +01:00
/**
2022-12-15 17:47:31 +01:00
* Filters callback which sets the status of an untrashed post to its previous status .
2020-12-10 14:06:04 +01:00
*
* This can be used as a callback on the `wp_untrash_post_status` filter .
*
* @ since 5.6 . 0
*
* @ param string $new_status The new status of the post being restored .
* @ param int $post_id The ID of the post being restored .
* @ param string $previous_status The status of the post at the point where it was trashed .
* @ return string The new status of the post .
*/
function wp_untrash_post_set_previous_status ( $new_status , $post_id , $previous_status ) {
return $previous_status ;
}
2022-12-15 17:47:31 +01:00
/**
* Returns whether the post can be edited in the block editor .
*
* @ since 5.0 . 0
* @ since 6.1 . 0 Moved to wp - includes from wp - admin .
*
* @ param int | WP_Post $post Post ID or WP_Post object .
* @ return bool Whether the post can be edited in the block editor .
*/
function use_block_editor_for_post ( $post ) {
$post = get_post ( $post );
if ( ! $post ) {
return false ;
}
// We're in the meta box loader, so don't use the block editor.
if ( is_admin () && isset ( $_GET [ 'meta-box-loader' ] ) ) {
check_admin_referer ( 'meta-box-loader' , 'meta-box-loader-nonce' );
return false ;
}
$use_block_editor = use_block_editor_for_post_type ( $post -> post_type );
/**
* Filters whether a post is able to be edited in the block editor .
*
* @ since 5.0 . 0
*
* @ param bool $use_block_editor Whether the post can be edited or not .
* @ param WP_Post $post The post being checked .
*/
return apply_filters ( 'use_block_editor_for_post' , $use_block_editor , $post );
}
/**
* Returns whether a post type is compatible with the block editor .
*
* The block editor depends on the REST API , and if the post type is not shown in the
* REST API , then it won ' t work with the block editor .
*
* @ since 5.0 . 0
* @ since 6.1 . 0 Moved to wp - includes from wp - admin .
*
* @ param string $post_type The post type .
* @ return bool Whether the post type can be edited with the block editor .
*/
function use_block_editor_for_post_type ( $post_type ) {
if ( ! post_type_exists ( $post_type ) ) {
return false ;
}
if ( ! post_type_supports ( $post_type , 'editor' ) ) {
return false ;
}
$post_type_object = get_post_type_object ( $post_type );
if ( $post_type_object && ! $post_type_object -> show_in_rest ) {
return false ;
}
/**
* Filters whether a post is able to be edited in the block editor .
*
* @ since 5.0 . 0
*
* @ param bool $use_block_editor Whether the post type can be edited or not . Default true .
* @ param string $post_type The post type being checked .
*/
return apply_filters ( 'use_block_editor_for_post_type' , true , $post_type );
}