: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$permalink = str_replace( '%pagename%', "{$uri}%pagename%", $permalink );
/** This filter is documented in wp-admin/edit-tag-form.php */
$permalink = array( $permalink, apply_filters( 'editable_slug', $post->post_name, $post ) );
$post->post_status = $original_status;
$post->post_date = $original_date;
$post->post_name = $original_name;
$post->filter = $original_filter;
* Filters the sample permalink.
* @param array $permalink {
* Array containing the sample permalink with placeholder for the post name, and the post name.
* @type string $0 The permalink with placeholder for the post name.
* @type string $1 The post name.
* @param int $post_id Post ID.
* @param string $title Post title.
* @param string $name Post name (slug).
* @param WP_Post $post Post object.
return apply_filters( 'get_sample_permalink', $permalink, $post->ID, $title, $name, $post );
* Returns the HTML of the sample permalink slug editor.
* @param int|WP_Post $post Post ID or post object.
* @param string|null $new_title Optional. New title. Default null.
* @param string|null $new_slug Optional. New slug. Default null.
* @return string The HTML of the sample permalink slug editor.
function get_sample_permalink_html( $post, $new_title = null, $new_slug = null ) {
$post = get_post( $post );
list($permalink, $post_name) = get_sample_permalink( $post->ID, $new_title, $new_slug );
if ( current_user_can( 'read_post', $post->ID ) ) {
if ( 'draft' === $post->post_status || empty( $post->post_name ) ) {
$view_link = get_preview_post_link( $post );
$preview_target = " target='wp-preview-{$post->ID}'";
if ( 'publish' === $post->post_status || 'attachment' === $post->post_type ) {
$view_link = get_permalink( $post );
// Allow non-published (private, future) to be viewed at a pretty permalink, in case $post->post_name is set.
$view_link = str_replace( array( '%pagename%', '%postname%' ), $post->post_name, $permalink );
// Permalinks without a post/page name placeholder don't have anything to edit.
if ( ! str_contains( $permalink, '%postname%' ) && ! str_contains( $permalink, '%pagename%' ) ) {
$return = '<strong>' . __( 'Permalink:' ) . "</strong>\n";
if ( false !== $view_link ) {
$display_link = urldecode( $view_link );
$return .= '<a id="sample-permalink" href="' . esc_url( $view_link ) . '"' . $preview_target . '>' . esc_html( $display_link ) . "</a>\n";
$return .= '<span id="sample-permalink">' . $permalink . "</span>\n";
// Encourage a pretty permalink setting.
if ( ! get_option( 'permalink_structure' ) && current_user_can( 'manage_options' )
&& ! ( 'page' === get_option( 'show_on_front' ) && (int) get_option( 'page_on_front' ) === $post->ID )
$return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button button-small">' . __( 'Change Permalink Structure' ) . "</a></span>\n";
if ( mb_strlen( $post_name ) > 34 ) {
$post_name_abridged = mb_substr( $post_name, 0, 16 ) . '…' . mb_substr( $post_name, -16 );
$post_name_abridged = $post_name;
$post_name_html = '<span id="editable-post-name">' . esc_html( $post_name_abridged ) . '</span>';
$display_link = str_replace( array( '%pagename%', '%postname%' ), $post_name_html, esc_html( urldecode( $permalink ) ) );
$return = '<strong>' . __( 'Permalink:' ) . "</strong>\n";
$return .= '<span id="sample-permalink"><a href="' . esc_url( $view_link ) . '"' . $preview_target . '>' . $display_link . "</a></span>\n";
$return .= '‎'; // Fix bi-directional text display defect in RTL languages.
$return .= '<span id="edit-slug-buttons"><button type="button" class="edit-slug button button-small hide-if-no-js" aria-label="' . __( 'Edit permalink' ) . '">' . __( 'Edit' ) . "</button></span>\n";
$return .= '<span id="editable-post-name-full">' . esc_html( $post_name ) . "</span>\n";
* Filters the sample permalink HTML markup.
* @since 4.4.0 Added `$post` parameter.
* @param string $return Sample permalink HTML markup.
* @param int $post_id Post ID.
* @param string|null $new_title New sample permalink title.
* @param string|null $new_slug New sample permalink slug.
* @param WP_Post $post Post object.
$return = apply_filters( 'get_sample_permalink_html', $return, $post->ID, $new_title, $new_slug, $post );
* Returns HTML for the post thumbnail meta box.
* @param int|null $thumbnail_id Optional. Thumbnail attachment ID. Default null.
* @param int|WP_Post|null $post Optional. The post ID or object associated
* with the thumbnail. Defaults to global $post.
* @return string The post thumbnail HTML.
function _wp_post_thumbnail_html( $thumbnail_id = null, $post = null ) {
$_wp_additional_image_sizes = wp_get_additional_image_sizes();
$post = get_post( $post );
$post_type_object = get_post_type_object( $post->post_type );
$set_thumbnail_link = '<p class="hide-if-no-js"><a href="%s" id="set-post-thumbnail"%s class="thickbox">%s</a></p>';
$upload_iframe_src = get_upload_iframe_src( 'image', $post->ID );
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.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
* @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 ) ) {
esc_url( $upload_iframe_src ),
' aria-describedby="set-post-thumbnail-desc"',
$content .= '<p class="hide-if-no-js howto" id="set-post-thumbnail-desc">' . __( 'Click the image to edit or update' ) . '</p>';
$content .= '<p class="hide-if-no-js"><a href="#" id="remove-post-thumbnail">' . esc_html( $post_type_object->labels->remove_featured_image ) . '</a></p>';
$content .= '<input type="hidden" id="_thumbnail_id" name="_thumbnail_id" value="' . esc_attr( $thumbnail_id ? $thumbnail_id : '-1' ) . '" />';
* Filters the admin post thumbnail HTML markup to return.
* @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 );
* Determines whether the post is currently being edited by another user.
* @param int|WP_Post $post ID or object 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 ) {
$post = get_post( $post );
$lock = get_post_meta( $post->ID, '_edit_lock', true );
$lock = explode( ':', $lock );
$user = isset( $lock[1] ) ? (int) $lock[1] : (int) get_post_meta( $post->ID, '_edit_last', true );
if ( ! get_userdata( $user ) ) {
/** 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 && get_current_user_id() !== $user ) {
* Marks the post as currently being edited by the current user.
* @param int|WP_Post $post ID or object of the post being edited.
* Array of the lock time and user ID. False if the post does not exist, or there
* @type int $0 The current time as a Unix timestamp.
* @type int $1 The ID of the current user.
function wp_set_post_lock( $post ) {
$post = get_post( $post );
$user_id = get_current_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.
function _admin_notice_post_locked() {
$user_id = wp_check_post_lock( $post->ID );
$user = get_userdata( $user_id );
* Filters whether to show the post locked dialog.
* Returning false from the filter will prevent the dialog from being displayed.
* @param bool $display Whether to display the dialog. Default true.
* @param WP_Post $post Post object.
* @param WP_User $user The user with the lock for the post.
if ( ! apply_filters( 'show_post_locked_dialog', true, $post, $user ) ) {
$sendback = wp_get_referer();
if ( $locked && $sendback && ! str_contains( $sendback, 'post.php' ) && ! str_contains( $sendback, 'post-new.php' ) ) {
$sendback_text = __( 'Go back' );
$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';
<div id="post-lock-dialog" class="notification-dialog-wrap<?php echo $hidden; ?>">
<div class="notification-dialog-background"></div>
<div class="notification-dialog">
if ( get_post_type_object( $post->post_type )->public ) {
if ( 'publish' === $post->post_status || $user->ID !== (int) $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 false from the filter will disable the ability
* to override the post lock.
* @param bool $override Whether to allow the post lock to be overridden. Default true.
* @param WP_Post $post Post object.
* @param WP_User $user The user with the lock for the post.
$override = apply_filters( 'override_post_lock', true, $post, $user );
$tab_last = $override ? '' : ' wp-tab-last';
<div class="post-locked-message">
<div class="post-locked-avatar"><?php echo get_avatar( $user->ID, 64 ); ?></div>
<p class="currently-editing wp-tab-first" tabindex="0">
/* translators: %s: User's display name. */
printf( __( '%s is currently editing this post. Do you want to take over?' ), esc_html( $user->display_name ) );
/* translators: %s: User's display name. */
printf( __( '%s is currently editing this post.' ), esc_html( $user->display_name ) );
* Fires inside the post locked dialog before the buttons are displayed.
* @since 5.4.0 The $user parameter was added.
* @param WP_Post $post Post object.
* @param WP_User $user The user with the lock for the post.
do_action( 'post_locked_dialog', $post, $user );
<a class="button" href="<?php echo esc_url( $sendback ); ?>"><?php echo $sendback_text; ?></a>
<?php if ( $preview_link ) { ?>
<a class="button<?php echo $tab_last; ?>" href="<?php echo esc_url( $preview_link ); ?>"><?php _e( 'Preview' ); ?></a>
// Allow plugins to prevent some users overriding the post lock.
<a class="button button-primary wp-tab-last" href="<?php echo esc_url( add_query_arg( 'get-post-lock', '1', wp_nonce_url( get_edit_post_link( $post->ID, 'url' ), 'lock-post_' . $post->ID ) ) ); ?>"><?php _e( 'Take over' ); ?></a>
<div class="post-taken-over">
<div class="post-locked-avatar"></div>
<p class="wp-tab-first" tabindex="0">
<span class="currently-editing"></span><br />
<span class="locked-saving hidden"><img src="<?php echo esc_url( admin_url( 'images/spinner-2x.gif' ) ); ?>" width="16" height="16" alt="" /> <?php _e( 'Saving revision…' ); ?></span>
<span class="locked-saved hidden"><?php _e( 'Your latest changes were saved as a revision.' ); ?></span>
* Fires inside the dialog displayed when a user has lost the post lock.
* @param WP_Post $post Post object.
do_action( 'post_lock_lost_dialog', $post );
<p><a class="button button-primary wp-tab-last" href="<?php echo esc_url( $sendback ); ?>"><?php echo $sendback_text; ?></a></p>
* Creates autosave data for the specified post from `$_POST` data.
* @param array|int $post_data Associative array containing the post data, or integer post ID.
* If a numeric post ID is provided, will use the `$_POST` superglobal.
* @return int|WP_Error The autosave revision ID. WP_Error or 0 on error.
function wp_create_post_autosave( $post_data ) {
if ( is_numeric( $post_data ) ) {
$post_id = (int) $post_data['post_ID'];
$post_data = _wp_translate_postdata( true, $post_data );
if ( is_wp_error( $post_data ) ) {
$post_data = _wp_get_allowed_postdata( $post_data );
$post_author = get_current_user_id();
// Store one autosave per author. If there is already an autosave, overwrite it.
$old_autosave = wp_get_post_autosave( $post_id, $post_author );
$new_autosave = _wp_post_revision_data( $post_data, true );
$new_autosave['ID'] = $old_autosave->ID;
$new_autosave['post_author'] = $post_author;
$post = get_post( $post_id );
// If the new autosave has the same content as the post, delete the autosave.
$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;
if ( ! $autosave_is_different ) {
wp_delete_post_revision( $old_autosave->ID );
* Fires before an autosave is stored.
* @since 6.4.0 The `$is_update` parameter was added to indicate if the autosave is being updated or was newly created.
* @param array $new_autosave Post array - the autosave that is about to be saved.
* @param bool $is_update Whether this is an existing autosave.
do_action( 'wp_creating_autosave', $new_autosave, true );
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.
$revision = _wp_put_post_revision( $post_data, true );
if ( ! is_wp_error( $revision ) && 0 !== $revision ) {
/** This action is documented in wp-admin/includes/post.php */