';
$upload_iframe_src = get_upload_iframe_src( 'image', $post->ID );
$content = sprintf(
$set_thumbnail_link,
esc_url( $upload_iframe_src ),
'', // Empty when there's no featured image set, `aria-describedby` attribute otherwise.
esc_html( $post_type_object->labels->set_featured_image )
);
if ( $thumbnail_id && get_post( $thumbnail_id ) ) {
$size = isset( $_wp_additional_image_sizes['post-thumbnail'] ) ? 'post-thumbnail' : array( 266, 266 );
/**
* Filters the size used to display the post thumbnail image in the 'Featured Image' meta box.
*
* Note: When a theme adds 'post-thumbnail' support, a special 'post-thumbnail'
* image size is registered, which differs from the 'thumbnail' image size
* managed via the Settings > Media screen. See the `$size` parameter description
* for more information on default values.
*
* @since 4.4.0
*
* @param string|array $size Post thumbnail image size to display in the meta box. Accepts any valid
* image size, or an array of width and height values in pixels (in that order).
* If the 'post-thumbnail' size is set, default is 'post-thumbnail'. Otherwise,
* default is an array with 266 as both the height and width values.
* @param int $thumbnail_id Post thumbnail attachment ID.
* @param WP_Post $post The post object associated with the thumbnail.
*/
$size = apply_filters( 'admin_post_thumbnail_size', $size, $thumbnail_id, $post );
$thumbnail_html = wp_get_attachment_image( $thumbnail_id, $size );
if ( ! empty( $thumbnail_html ) ) {
$content = sprintf(
$set_thumbnail_link,
esc_url( $upload_iframe_src ),
' aria-describedby="set-post-thumbnail-desc"',
$thumbnail_html
);
$content .= '
';
}
}
$content .= '';
/**
* Filters the admin post thumbnail HTML markup to return.
*
* @since 2.9.0
* @since 3.5.0 Added the `$post_id` parameter.
* @since 4.6.0 Added the `$thumbnail_id` parameter.
*
* @param string $content Admin post thumbnail HTML markup.
* @param int $post_id Post ID.
* @param int|null $thumbnail_id Thumbnail attachment ID, or null if there isn't one.
*/
return apply_filters( 'admin_post_thumbnail_html', $content, $post->ID, $thumbnail_id );
}
/**
* Check to see if the post is currently being edited by another user.
*
* @since 2.5.0
*
* @param int $post_id ID of the post to check for editing.
* @return int|false ID of the user with lock. False if the post does not exist, post is not locked,
* the user with lock does not exist, or the post is locked by current user.
*/
function wp_check_post_lock( $post_id ) {
if ( ! $post = get_post( $post_id ) ) {
return false;
}
if ( ! $lock = get_post_meta( $post->ID, '_edit_lock', true ) ) {
return false;
}
$lock = explode( ':', $lock );
$time = $lock[0];
$user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
if ( ! get_userdata( $user ) ) {
return false;
}
/** This filter is documented in wp-admin/includes/ajax-actions.php */
$time_window = apply_filters( 'wp_check_post_lock_window', 150 );
if ( $time && $time > time() - $time_window && $user != get_current_user_id() ) {
return $user;
}
return false;
}
/**
* Mark the post as currently being edited by the current user
*
* @since 2.5.0
*
* @param int $post_id ID of the post being edited.
* @return array|false Array of the lock time and user ID. False if the post does not exist, or
* there is no current user.
*/
function wp_set_post_lock( $post_id ) {
if ( ! $post = get_post( $post_id ) ) {
return false;
}
if ( 0 == ( $user_id = get_current_user_id() ) ) {
return false;
}
$now = time();
$lock = "$now:$user_id";
update_post_meta( $post->ID, '_edit_lock', $lock );
return array( $now, $user_id );
}
/**
* Outputs the HTML for the notice to say that someone else is editing or has taken over editing of this post.
*
* @since 2.8.5
* @return none
*/
function _admin_notice_post_locked() {
if ( ! $post = get_post() ) {
return;
}
$user = null;
if ( $user_id = wp_check_post_lock( $post->ID ) ) {
$user = get_userdata( $user_id );
}
if ( $user ) {
/**
* Filters whether to show the post locked dialog.
*
* Returning a falsey value to the filter will short-circuit displaying the dialog.
*
* @since 3.6.0
*
* @param bool $display Whether to display the dialog. Default true.
* @param WP_Post $post Post object.
* @param WP_User|bool $user WP_User object on success, false otherwise.
*/
if ( ! apply_filters( 'show_post_locked_dialog', true, $post, $user ) ) {
return;
}
$locked = true;
} else {
$locked = false;
}
if ( $locked && ( $sendback = wp_get_referer() ) &&
false === strpos( $sendback, 'post.php' ) && false === strpos( $sendback, 'post-new.php' ) ) {
$sendback_text = __( 'Go back' );
} else {
$sendback = admin_url( 'edit.php' );
if ( 'post' != $post->post_type ) {
$sendback = add_query_arg( 'post_type', $post->post_type, $sendback );
}
$sendback_text = get_post_type_object( $post->post_type )->labels->all_items;
}
$hidden = $locked ? '' : ' hidden';
?>
post_type )->public ) {
if ( 'publish' == $post->post_status || $user->ID != $post->post_author ) {
// Latest content is in autosave
$nonce = wp_create_nonce( 'post_preview_' . $post->ID );
$query_args['preview_id'] = $post->ID;
$query_args['preview_nonce'] = $nonce;
}
}
$preview_link = get_preview_post_link( $post->ID, $query_args );
/**
* Filters whether to allow the post lock to be overridden.
*
* Returning a falsey value to the filter will disable the ability
* to override the post lock.
*
* @since 3.6.0
*
* @param bool $override Whether to allow overriding post locks. Default true.
* @param WP_Post $post Post object.
* @param WP_User $user User object.
*/
$override = apply_filters( 'override_post_lock', true, $post, $user );
$tab_last = $override ? '' : ' wp-tab-last';
?>
ID, 64 ); ?>
display_name ) );
} else {
/* translators: %s: user's display name */
printf( __( '%s is already editing this post.' ), esc_html( $user->display_name ) );
}
?>
ID;
$new_autosave['post_author'] = $post_author;
// If the new autosave has the same content as the post, delete the autosave.
$post = get_post( $post_id );
$autosave_is_different = false;
foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) {
if ( normalize_whitespace( $new_autosave[ $field ] ) != normalize_whitespace( $post->$field ) ) {
$autosave_is_different = true;
break;
}
}
if ( ! $autosave_is_different ) {
wp_delete_post_revision( $old_autosave->ID );
return 0;
}
/**
* Fires before an autosave is stored.
*
* @since 4.1.0
*
* @param array $new_autosave Post array - the autosave that is about to be saved.
*/
do_action( 'wp_creating_autosave', $new_autosave );
return wp_update_post( $new_autosave );
}
// _wp_put_post_revision() expects unescaped.
$post_data = wp_unslash( $post_data );
// Otherwise create the new autosave as a special post revision
return _wp_put_post_revision( $post_data, true );
}
/**
* Saves a draft or manually autosaves for the purpose of showing a post preview.
*
* @since 2.7.0
*
* @return string URL to redirect to show the preview.
*/
function post_preview() {
$post_ID = (int) $_POST['post_ID'];
$_POST['ID'] = $post_ID;
if ( ! $post = get_post( $post_ID ) ) {
wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
}
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
}
$is_autosave = false;
if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author && ( 'draft' == $post->post_status || 'auto-draft' == $post->post_status ) ) {
$saved_post_id = edit_post();
} else {
$is_autosave = true;
if ( isset( $_POST['post_status'] ) && 'auto-draft' == $_POST['post_status'] ) {
$_POST['post_status'] = 'draft';
}
$saved_post_id = wp_create_post_autosave( $post->ID );
}
if ( is_wp_error( $saved_post_id ) ) {
wp_die( $saved_post_id->get_error_message() );
}
$query_args = array();
if ( $is_autosave && $saved_post_id ) {
$query_args['preview_id'] = $post->ID;
$query_args['preview_nonce'] = wp_create_nonce( 'post_preview_' . $post->ID );
if ( isset( $_POST['post_format'] ) ) {
$query_args['post_format'] = empty( $_POST['post_format'] ) ? 'standard' : sanitize_key( $_POST['post_format'] );
}
if ( isset( $_POST['_thumbnail_id'] ) ) {
$query_args['_thumbnail_id'] = ( intval( $_POST['_thumbnail_id'] ) <= 0 ) ? '-1' : intval( $_POST['_thumbnail_id'] );
}
}
return get_preview_post_link( $post, $query_args );
}
/**
* Save a post submitted with XHR
*
* Intended for use with heartbeat and autosave.js
*
* @since 3.9.0
*
* @param array $post_data Associative array of the submitted post data.
* @return mixed The value 0 or WP_Error on failure. The saved post ID on success.
* The ID can be the draft post_id or the autosave revision post_id.
*/
function wp_autosave( $post_data ) {
// Back-compat
if ( ! defined( 'DOING_AUTOSAVE' ) ) {
define( 'DOING_AUTOSAVE', true );
}
$post_id = (int) $post_data['post_id'];
$post_data['ID'] = $post_data['post_ID'] = $post_id;
if ( false === wp_verify_nonce( $post_data['_wpnonce'], 'update-post_' . $post_id ) ) {
return new WP_Error( 'invalid_nonce', __( 'Error while saving.' ) );
}
$post = get_post( $post_id );
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
return new WP_Error( 'edit_posts', __( 'Sorry, you are not allowed to edit this item.' ) );
}
if ( 'auto-draft' == $post->post_status ) {
$post_data['post_status'] = 'draft';
}
if ( $post_data['post_type'] != 'page' && ! empty( $post_data['catslist'] ) ) {
$post_data['post_category'] = explode( ',', $post_data['catslist'] );
}
if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author && ( 'auto-draft' == $post->post_status || 'draft' == $post->post_status ) ) {
// Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked
return edit_post( wp_slash( $post_data ) );
} else {
// Non drafts or other users drafts are not overwritten. The autosave is stored in a special post revision for each user.
return wp_create_post_autosave( wp_slash( $post_data ) );
}
}
/**
* Redirect to previous page.
*
* @param int $post_id Optional. Post ID.
*/
function redirect_post( $post_id = '' ) {
if ( isset( $_POST['save'] ) || isset( $_POST['publish'] ) ) {
$status = get_post_status( $post_id );
if ( isset( $_POST['publish'] ) ) {
switch ( $status ) {
case 'pending':
$message = 8;
break;
case 'future':
$message = 9;
break;
default:
$message = 6;
}
} else {
$message = 'draft' == $status ? 10 : 1;
}
$location = add_query_arg( 'message', $message, get_edit_post_link( $post_id, 'url' ) );
} elseif ( isset( $_POST['addmeta'] ) && $_POST['addmeta'] ) {
$location = add_query_arg( 'message', 2, wp_get_referer() );
$location = explode( '#', $location );
$location = $location[0] . '#postcustom';
} elseif ( isset( $_POST['deletemeta'] ) && $_POST['deletemeta'] ) {
$location = add_query_arg( 'message', 3, wp_get_referer() );
$location = explode( '#', $location );
$location = $location[0] . '#postcustom';
} else {
$location = add_query_arg( 'message', 4, get_edit_post_link( $post_id, 'url' ) );
}
/**
* Filters the post redirect destination URL.
*
* @since 2.9.0
*
* @param string $location The destination URL.
* @param int $post_id The post ID.
*/
wp_redirect( apply_filters( 'redirect_post_location', $location, $post_id ) );
exit;
}
/**
* Sanitizes POST values from a checkbox taxonomy metabox.
*
* @since 5.1.0
*
* @param mixed $terms Raw term data from the 'tax_input' field.
* @return array
*/
function taxonomy_meta_box_sanitize_cb_checkboxes( $taxonomy, $terms ) {
return array_map( 'intval', $terms );
}
/**
* Sanitizes POST values from an input taxonomy metabox.
*
* @since 5.1.0
*
* @param mixed $terms Raw term data from the 'tax_input' field.
* @return array
*/
function taxonomy_meta_box_sanitize_cb_input( $taxonomy, $terms ) {
/*
* Assume that a 'tax_input' string is a comma-separated list of term names.
* Some languages may use a character other than a comma as a delimiter, so we standardize on
* commas before parsing the list.
*/
if ( ! is_array( $terms ) ) {
$comma = _x( ',', 'tag delimiter' );
if ( ',' !== $comma ) {
$terms = str_replace( $comma, ',', $terms );
}
$terms = explode( ',', trim( $terms, " \n\t\r\0\x0B," ) );
}
$clean_terms = array();
foreach ( $terms as $term ) {
// Empty terms are invalid input.
if ( empty( $term ) ) {
continue;
}
$_term = get_terms(
$taxonomy,
array(
'name' => $term,
'fields' => 'ids',
'hide_empty' => false,
)
);
if ( ! empty( $_term ) ) {
$clean_terms[] = intval( $_term[0] );
} else {
// No existing term was found, so pass the string. A new term will be created.
$clean_terms[] = $term;
}
}
return $clean_terms;
}
/**
* Return whether the post can be edited in the block editor.
*
* @since 5.0.0
*
* @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 ( isset( $_GET['meta-box-loader'] ) ) {
check_admin_referer( 'meta-box-loader', 'meta-box-loader-nonce' );
return false;
}
// The posts page can't be edited in the block editor.
if ( absint( get_option( 'page_for_posts' ) ) === $post->ID && empty( $post->post_content ) ) {
return false;
}
$use_block_editor = use_block_editor_for_post_type( $post->post_type );
/**
* Filter 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 );
}
/**
* Return 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
*
* @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;
}
/**
* Filter 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 );
}
/**
* Returns all the block categories that will be shown in the block editor.
*
* @since 5.0.0
*
* @param WP_Post $post Post object.
* @return array Array of block categories.
*/
function get_block_categories( $post ) {
$default_categories = array(
array(
'slug' => 'common',
'title' => __( 'Common Blocks' ),
'icon' => null,
),
array(
'slug' => 'formatting',
'title' => __( 'Formatting' ),
'icon' => null,
),
array(
'slug' => 'layout',
'title' => __( 'Layout Elements' ),
'icon' => null,
),
array(
'slug' => 'widgets',
'title' => __( 'Widgets' ),
'icon' => null,
),
array(
'slug' => 'embed',
'title' => __( 'Embeds' ),
'icon' => null,
),
array(
'slug' => 'reusable',
'title' => __( 'Reusable Blocks' ),
'icon' => null,
),
);
/**
* Filter the default array of block categories.
*
* @since 5.0.0
*
* @param array $default_categories Array of block categories.
* @param WP_Post $post Post being loaded.
*/
return apply_filters( 'block_categories', $default_categories, $post );
}
/**
* Prepares server-registered blocks for the block editor.
*
* Returns an associative array of registered block data keyed by block name. Data includes properties
* of a block relevant for client registration.
*
* @since 5.0.0
*
* @return array An associative array of registered block data.
*/
function get_block_editor_server_block_settings() {
$block_registry = WP_Block_Type_Registry::get_instance();
$blocks = array();
$keys_to_pick = array( 'title', 'description', 'icon', 'category', 'keywords', 'supports', 'attributes' );
foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
foreach ( $keys_to_pick as $key ) {
if ( ! isset( $block_type->{ $key } ) ) {
continue;
}
if ( ! isset( $blocks[ $block_name ] ) ) {
$blocks[ $block_name ] = array();
}
$blocks[ $block_name ][ $key ] = $block_type->{ $key };
}
}
return $blocks;
}
/**
* Renders the meta boxes forms.
*
* @since 5.0.0
*/
function the_block_editor_meta_boxes() {
global $post, $current_screen, $wp_meta_boxes;
// Handle meta box state.
$_original_meta_boxes = $wp_meta_boxes;
/**
* Fires right before the meta boxes are rendered.
*
* This allows for the filtering of meta box data, that should already be
* present by this point. Do not use as a means of adding meta box data.
*
* @since 5.0.0
*
* @param array $wp_meta_boxes Global meta box state.
*/
$wp_meta_boxes = apply_filters( 'filter_block_editor_meta_boxes', $wp_meta_boxes );
$locations = array( 'side', 'normal', 'advanced' );
$priorities = array( 'high', 'sorted', 'core', 'default', 'low' );
// Render meta boxes.
?>
id ][ $location ] ) ) {
continue;
}
foreach ( $priorities as $priority ) {
if ( ! isset( $wp_meta_boxes[ $current_screen->id ][ $location ][ $priority ] ) ) {
continue;
}
$meta_boxes = (array) $wp_meta_boxes[ $current_screen->id ][ $location ][ $priority ];
foreach ( $meta_boxes as $meta_box ) {
if ( false == $meta_box || ! $meta_box['title'] ) {
continue;
}
// If a meta box is just here for back compat, don't show it in the block editor.
if ( isset( $meta_box['args']['__back_compat_meta_box'] ) && $meta_box['args']['__back_compat_meta_box'] ) {
continue;
}
$meta_boxes_per_location[ $location ][] = array(
'id' => $meta_box['id'],
'title' => $meta_box['title'],
);
}
}
}
/**
* Sadly we probably can not add this data directly into editor settings.
*
* Some meta boxes need admin_head to fire for meta box registry.
* admin_head fires after admin_enqueue_scripts, which is where we create our
* editor instance.
*/
$script = 'window._wpLoadBlockEditor.then( function() {
wp.data.dispatch( \'core/edit-post\' ).setAvailableMetaBoxesPerLocation( ' . wp_json_encode( $meta_boxes_per_location ) . ' );
} );';
wp_add_inline_script( 'wp-edit-post', $script );
/**
* When `wp-edit-post` is output in the ``, the inline script needs to be manually printed. Otherwise,
* meta boxes will not display because inline scripts for `wp-edit-post` will not be printed again after this point.
*/
if ( wp_script_is( 'wp-edit-post', 'done' ) ) {
printf( "\n", trim( $script ) );
}
/**
* If the 'postcustom' meta box is enabled, then we need to perform some
* extra initialization on it.
*/
$enable_custom_fields = (bool) get_user_meta( get_current_user_id(), 'enable_custom_fields', true );
if ( $enable_custom_fields ) {
$script = "( function( $ ) {
if ( $('#postcustom').length ) {
$( '#the-list' ).wpList( {
addBefore: function( s ) {
s.data += '&post_id=$post->ID';
return s;
},
addAfter: function() {
$('table#list-table').show();
}
});
}
} )( jQuery );";
wp_enqueue_script( 'wp-lists' );
wp_add_inline_script( 'wp-lists', $script );
}
// Reset meta box data.
$wp_meta_boxes = $_original_meta_boxes;
}
/**
* Renders the hidden form required for the meta boxes form.
*
* @since 5.0.0
*
* @param WP_Post $post Current post object.
*/
function the_block_editor_meta_box_post_form_hidden_fields( $post ) {
$form_extra = '';
if ( 'auto-draft' === $post->post_status ) {
$form_extra .= "";
}
$form_action = 'editpost';
$nonce_action = 'update-post_' . $post->ID;
$form_extra .= "";
$referer = wp_get_referer();
$current_user = wp_get_current_user();
$user_id = $current_user->ID;
wp_nonce_field( $nonce_action );
/*
* Some meta boxes hook into these actions to add hidden input fields in the classic post form. For backwards
* compatibility, we can capture the output from these actions, and extract the hidden input fields.
*/
ob_start();
/** This filter is documented in wp-admin/edit-form-advanced.php */
do_action( 'edit_form_after_title', $post );
/** This filter is documented in wp-admin/edit-form-advanced.php */
do_action( 'edit_form_advanced', $post );
$classic_output = ob_get_clean();
$classic_elements = wp_html_split( $classic_output );
$hidden_inputs = '';
foreach ( $classic_elements as $element ) {
if ( 0 !== strpos( $element, '
` fields, which will be POSTed back to
* the server when meta boxes are saved.
*
* @since 5.0.0
*
* @params WP_Post $post The post that is being edited.
*/
do_action( 'block_editor_meta_box_hidden_fields', $post );
}