ru-se.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

post.php (74884B)


      1 <?php
      2 /**
      3  * WordPress Post Administration API.
      4  *
      5  * @package WordPress
      6  * @subpackage Administration
      7  */
      8 
      9 /**
     10  * Rename $_POST data from form names to DB post columns.
     11  *
     12  * Manipulates $_POST directly.
     13  *
     14  * @since 2.6.0
     15  *
     16  * @param bool  $update    Are we updating a pre-existing post?
     17  * @param array $post_data Array of post data. Defaults to the contents of $_POST.
     18  * @return array|WP_Error Array of post data on success, WP_Error on failure.
     19  */
     20 function _wp_translate_postdata( $update = false, $post_data = null ) {
     21 
     22 	if ( empty( $post_data ) ) {
     23 		$post_data = &$_POST;
     24 	}
     25 
     26 	if ( $update ) {
     27 		$post_data['ID'] = (int) $post_data['post_ID'];
     28 	}
     29 
     30 	$ptype = get_post_type_object( $post_data['post_type'] );
     31 
     32 	if ( $update && ! current_user_can( 'edit_post', $post_data['ID'] ) ) {
     33 		if ( 'page' === $post_data['post_type'] ) {
     34 			return new WP_Error( 'edit_others_pages', __( 'Sorry, you are not allowed to edit pages as this user.' ) );
     35 		} else {
     36 			return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to edit posts as this user.' ) );
     37 		}
     38 	} elseif ( ! $update && ! current_user_can( $ptype->cap->create_posts ) ) {
     39 		if ( 'page' === $post_data['post_type'] ) {
     40 			return new WP_Error( 'edit_others_pages', __( 'Sorry, you are not allowed to create pages as this user.' ) );
     41 		} else {
     42 			return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to create posts as this user.' ) );
     43 		}
     44 	}
     45 
     46 	if ( isset( $post_data['content'] ) ) {
     47 		$post_data['post_content'] = $post_data['content'];
     48 	}
     49 
     50 	if ( isset( $post_data['excerpt'] ) ) {
     51 		$post_data['post_excerpt'] = $post_data['excerpt'];
     52 	}
     53 
     54 	if ( isset( $post_data['parent_id'] ) ) {
     55 		$post_data['post_parent'] = (int) $post_data['parent_id'];
     56 	}
     57 
     58 	if ( isset( $post_data['trackback_url'] ) ) {
     59 		$post_data['to_ping'] = $post_data['trackback_url'];
     60 	}
     61 
     62 	$post_data['user_ID'] = get_current_user_id();
     63 
     64 	if ( ! empty( $post_data['post_author_override'] ) ) {
     65 		$post_data['post_author'] = (int) $post_data['post_author_override'];
     66 	} else {
     67 		if ( ! empty( $post_data['post_author'] ) ) {
     68 			$post_data['post_author'] = (int) $post_data['post_author'];
     69 		} else {
     70 			$post_data['post_author'] = (int) $post_data['user_ID'];
     71 		}
     72 	}
     73 
     74 	if ( isset( $post_data['user_ID'] ) && ( $post_data['post_author'] != $post_data['user_ID'] )
     75 		&& ! current_user_can( $ptype->cap->edit_others_posts ) ) {
     76 
     77 		if ( $update ) {
     78 			if ( 'page' === $post_data['post_type'] ) {
     79 				return new WP_Error( 'edit_others_pages', __( 'Sorry, you are not allowed to edit pages as this user.' ) );
     80 			} else {
     81 				return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to edit posts as this user.' ) );
     82 			}
     83 		} else {
     84 			if ( 'page' === $post_data['post_type'] ) {
     85 				return new WP_Error( 'edit_others_pages', __( 'Sorry, you are not allowed to create pages as this user.' ) );
     86 			} else {
     87 				return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to create posts as this user.' ) );
     88 			}
     89 		}
     90 	}
     91 
     92 	if ( ! empty( $post_data['post_status'] ) ) {
     93 		$post_data['post_status'] = sanitize_key( $post_data['post_status'] );
     94 
     95 		// No longer an auto-draft.
     96 		if ( 'auto-draft' === $post_data['post_status'] ) {
     97 			$post_data['post_status'] = 'draft';
     98 		}
     99 
    100 		if ( ! get_post_status_object( $post_data['post_status'] ) ) {
    101 			unset( $post_data['post_status'] );
    102 		}
    103 	}
    104 
    105 	// What to do based on which button they pressed.
    106 	if ( isset( $post_data['saveasdraft'] ) && '' !== $post_data['saveasdraft'] ) {
    107 		$post_data['post_status'] = 'draft';
    108 	}
    109 	if ( isset( $post_data['saveasprivate'] ) && '' !== $post_data['saveasprivate'] ) {
    110 		$post_data['post_status'] = 'private';
    111 	}
    112 	if ( isset( $post_data['publish'] ) && ( '' !== $post_data['publish'] )
    113 		&& ( ! isset( $post_data['post_status'] ) || 'private' !== $post_data['post_status'] )
    114 	) {
    115 		$post_data['post_status'] = 'publish';
    116 	}
    117 	if ( isset( $post_data['advanced'] ) && '' !== $post_data['advanced'] ) {
    118 		$post_data['post_status'] = 'draft';
    119 	}
    120 	if ( isset( $post_data['pending'] ) && '' !== $post_data['pending'] ) {
    121 		$post_data['post_status'] = 'pending';
    122 	}
    123 
    124 	if ( isset( $post_data['ID'] ) ) {
    125 		$post_id = $post_data['ID'];
    126 	} else {
    127 		$post_id = false;
    128 	}
    129 	$previous_status = $post_id ? get_post_field( 'post_status', $post_id ) : false;
    130 
    131 	if ( isset( $post_data['post_status'] ) && 'private' === $post_data['post_status'] && ! current_user_can( $ptype->cap->publish_posts ) ) {
    132 		$post_data['post_status'] = $previous_status ? $previous_status : 'pending';
    133 	}
    134 
    135 	$published_statuses = array( 'publish', 'future' );
    136 
    137 	// Posts 'submitted for approval' are submitted to $_POST the same as if they were being published.
    138 	// Change status from 'publish' to 'pending' if user lacks permissions to publish or to resave published posts.
    139 	if ( isset( $post_data['post_status'] )
    140 		&& ( in_array( $post_data['post_status'], $published_statuses, true )
    141 		&& ! current_user_can( $ptype->cap->publish_posts ) )
    142 	) {
    143 		if ( ! in_array( $previous_status, $published_statuses, true ) || ! current_user_can( 'edit_post', $post_id ) ) {
    144 			$post_data['post_status'] = 'pending';
    145 		}
    146 	}
    147 
    148 	if ( ! isset( $post_data['post_status'] ) ) {
    149 		$post_data['post_status'] = 'auto-draft' === $previous_status ? 'draft' : $previous_status;
    150 	}
    151 
    152 	if ( isset( $post_data['post_password'] ) && ! current_user_can( $ptype->cap->publish_posts ) ) {
    153 		unset( $post_data['post_password'] );
    154 	}
    155 
    156 	if ( ! isset( $post_data['comment_status'] ) ) {
    157 		$post_data['comment_status'] = 'closed';
    158 	}
    159 
    160 	if ( ! isset( $post_data['ping_status'] ) ) {
    161 		$post_data['ping_status'] = 'closed';
    162 	}
    163 
    164 	foreach ( array( 'aa', 'mm', 'jj', 'hh', 'mn' ) as $timeunit ) {
    165 		if ( ! empty( $post_data[ 'hidden_' . $timeunit ] ) && $post_data[ 'hidden_' . $timeunit ] != $post_data[ $timeunit ] ) {
    166 			$post_data['edit_date'] = '1';
    167 			break;
    168 		}
    169 	}
    170 
    171 	if ( ! empty( $post_data['edit_date'] ) ) {
    172 		$aa = $post_data['aa'];
    173 		$mm = $post_data['mm'];
    174 		$jj = $post_data['jj'];
    175 		$hh = $post_data['hh'];
    176 		$mn = $post_data['mn'];
    177 		$ss = $post_data['ss'];
    178 		$aa = ( $aa <= 0 ) ? gmdate( 'Y' ) : $aa;
    179 		$mm = ( $mm <= 0 ) ? gmdate( 'n' ) : $mm;
    180 		$jj = ( $jj > 31 ) ? 31 : $jj;
    181 		$jj = ( $jj <= 0 ) ? gmdate( 'j' ) : $jj;
    182 		$hh = ( $hh > 23 ) ? $hh - 24 : $hh;
    183 		$mn = ( $mn > 59 ) ? $mn - 60 : $mn;
    184 		$ss = ( $ss > 59 ) ? $ss - 60 : $ss;
    185 
    186 		$post_data['post_date'] = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $aa, $mm, $jj, $hh, $mn, $ss );
    187 
    188 		$valid_date = wp_checkdate( $mm, $jj, $aa, $post_data['post_date'] );
    189 		if ( ! $valid_date ) {
    190 			return new WP_Error( 'invalid_date', __( 'Invalid date.' ) );
    191 		}
    192 
    193 		$post_data['post_date_gmt'] = get_gmt_from_date( $post_data['post_date'] );
    194 	}
    195 
    196 	if ( isset( $post_data['post_category'] ) ) {
    197 		$category_object = get_taxonomy( 'category' );
    198 		if ( ! current_user_can( $category_object->cap->assign_terms ) ) {
    199 			unset( $post_data['post_category'] );
    200 		}
    201 	}
    202 
    203 	return $post_data;
    204 }
    205 
    206 /**
    207  * Returns only allowed post data fields
    208  *
    209  * @since 5.0.1
    210  *
    211  * @param array $post_data Array of post data. Defaults to the contents of $_POST.
    212  * @return array|WP_Error Array of post data on success, WP_Error on failure.
    213  */
    214 function _wp_get_allowed_postdata( $post_data = null ) {
    215 	if ( empty( $post_data ) ) {
    216 		$post_data = $_POST;
    217 	}
    218 
    219 	// Pass through errors.
    220 	if ( is_wp_error( $post_data ) ) {
    221 		return $post_data;
    222 	}
    223 
    224 	return array_diff_key( $post_data, array_flip( array( 'meta_input', 'file', 'guid' ) ) );
    225 }
    226 
    227 /**
    228  * Update an existing post with values provided in $_POST.
    229  *
    230  * If post data is passed as an argument, it is treated as an array of data
    231  * keyed appropriately for turning into a post object.
    232  *
    233  * If post data is not passed, the $_POST global variable is used instead.
    234  *
    235  * @since 1.5.0
    236  *
    237  * @global wpdb $wpdb WordPress database abstraction object.
    238  *
    239  * @param array $post_data Optional. Defaults to the $_POST global.
    240  * @return int Post ID.
    241  */
    242 function edit_post( $post_data = null ) {
    243 	global $wpdb;
    244 
    245 	if ( empty( $post_data ) ) {
    246 		$post_data = &$_POST;
    247 	}
    248 
    249 	// Clear out any data in internal vars.
    250 	unset( $post_data['filter'] );
    251 
    252 	$post_ID = (int) $post_data['post_ID'];
    253 	$post    = get_post( $post_ID );
    254 
    255 	$post_data['post_type']      = $post->post_type;
    256 	$post_data['post_mime_type'] = $post->post_mime_type;
    257 
    258 	if ( ! empty( $post_data['post_status'] ) ) {
    259 		$post_data['post_status'] = sanitize_key( $post_data['post_status'] );
    260 
    261 		if ( 'inherit' === $post_data['post_status'] ) {
    262 			unset( $post_data['post_status'] );
    263 		}
    264 	}
    265 
    266 	$ptype = get_post_type_object( $post_data['post_type'] );
    267 	if ( ! current_user_can( 'edit_post', $post_ID ) ) {
    268 		if ( 'page' === $post_data['post_type'] ) {
    269 			wp_die( __( 'Sorry, you are not allowed to edit this page.' ) );
    270 		} else {
    271 			wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
    272 		}
    273 	}
    274 
    275 	if ( post_type_supports( $ptype->name, 'revisions' ) ) {
    276 		$revisions = wp_get_post_revisions(
    277 			$post_ID,
    278 			array(
    279 				'order'          => 'ASC',
    280 				'posts_per_page' => 1,
    281 			)
    282 		);
    283 		$revision  = current( $revisions );
    284 
    285 		// Check if the revisions have been upgraded.
    286 		if ( $revisions && _wp_get_post_revision_version( $revision ) < 1 ) {
    287 			_wp_upgrade_revisions_of_post( $post, wp_get_post_revisions( $post_ID ) );
    288 		}
    289 	}
    290 
    291 	if ( isset( $post_data['visibility'] ) ) {
    292 		switch ( $post_data['visibility'] ) {
    293 			case 'public':
    294 				$post_data['post_password'] = '';
    295 				break;
    296 			case 'password':
    297 				unset( $post_data['sticky'] );
    298 				break;
    299 			case 'private':
    300 				$post_data['post_status']   = 'private';
    301 				$post_data['post_password'] = '';
    302 				unset( $post_data['sticky'] );
    303 				break;
    304 		}
    305 	}
    306 
    307 	$post_data = _wp_translate_postdata( true, $post_data );
    308 	if ( is_wp_error( $post_data ) ) {
    309 		wp_die( $post_data->get_error_message() );
    310 	}
    311 	$translated = _wp_get_allowed_postdata( $post_data );
    312 
    313 	// Post formats.
    314 	if ( isset( $post_data['post_format'] ) ) {
    315 		set_post_format( $post_ID, $post_data['post_format'] );
    316 	}
    317 
    318 	$format_meta_urls = array( 'url', 'link_url', 'quote_source_url' );
    319 	foreach ( $format_meta_urls as $format_meta_url ) {
    320 		$keyed = '_format_' . $format_meta_url;
    321 		if ( isset( $post_data[ $keyed ] ) ) {
    322 			update_post_meta( $post_ID, $keyed, wp_slash( esc_url_raw( wp_unslash( $post_data[ $keyed ] ) ) ) );
    323 		}
    324 	}
    325 
    326 	$format_keys = array( 'quote', 'quote_source_name', 'image', 'gallery', 'audio_embed', 'video_embed' );
    327 
    328 	foreach ( $format_keys as $key ) {
    329 		$keyed = '_format_' . $key;
    330 		if ( isset( $post_data[ $keyed ] ) ) {
    331 			if ( current_user_can( 'unfiltered_html' ) ) {
    332 				update_post_meta( $post_ID, $keyed, $post_data[ $keyed ] );
    333 			} else {
    334 				update_post_meta( $post_ID, $keyed, wp_filter_post_kses( $post_data[ $keyed ] ) );
    335 			}
    336 		}
    337 	}
    338 
    339 	if ( 'attachment' === $post_data['post_type'] && preg_match( '#^(audio|video)/#', $post_data['post_mime_type'] ) ) {
    340 		$id3data = wp_get_attachment_metadata( $post_ID );
    341 		if ( ! is_array( $id3data ) ) {
    342 			$id3data = array();
    343 		}
    344 
    345 		foreach ( wp_get_attachment_id3_keys( $post, 'edit' ) as $key => $label ) {
    346 			if ( isset( $post_data[ 'id3_' . $key ] ) ) {
    347 				$id3data[ $key ] = sanitize_text_field( wp_unslash( $post_data[ 'id3_' . $key ] ) );
    348 			}
    349 		}
    350 		wp_update_attachment_metadata( $post_ID, $id3data );
    351 	}
    352 
    353 	// Meta stuff.
    354 	if ( isset( $post_data['meta'] ) && $post_data['meta'] ) {
    355 		foreach ( $post_data['meta'] as $key => $value ) {
    356 			$meta = get_post_meta_by_id( $key );
    357 			if ( ! $meta ) {
    358 				continue;
    359 			}
    360 			if ( $meta->post_id != $post_ID ) {
    361 				continue;
    362 			}
    363 			if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'edit_post_meta', $post_ID, $meta->meta_key ) ) {
    364 				continue;
    365 			}
    366 			if ( is_protected_meta( $value['key'], 'post' ) || ! current_user_can( 'edit_post_meta', $post_ID, $value['key'] ) ) {
    367 				continue;
    368 			}
    369 			update_meta( $key, $value['key'], $value['value'] );
    370 		}
    371 	}
    372 
    373 	if ( isset( $post_data['deletemeta'] ) && $post_data['deletemeta'] ) {
    374 		foreach ( $post_data['deletemeta'] as $key => $value ) {
    375 			$meta = get_post_meta_by_id( $key );
    376 			if ( ! $meta ) {
    377 				continue;
    378 			}
    379 			if ( $meta->post_id != $post_ID ) {
    380 				continue;
    381 			}
    382 			if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $post_ID, $meta->meta_key ) ) {
    383 				continue;
    384 			}
    385 			delete_meta( $key );
    386 		}
    387 	}
    388 
    389 	// Attachment stuff.
    390 	if ( 'attachment' === $post_data['post_type'] ) {
    391 		if ( isset( $post_data['_wp_attachment_image_alt'] ) ) {
    392 			$image_alt = wp_unslash( $post_data['_wp_attachment_image_alt'] );
    393 
    394 			if ( get_post_meta( $post_ID, '_wp_attachment_image_alt', true ) !== $image_alt ) {
    395 				$image_alt = wp_strip_all_tags( $image_alt, true );
    396 
    397 				// update_post_meta() expects slashed.
    398 				update_post_meta( $post_ID, '_wp_attachment_image_alt', wp_slash( $image_alt ) );
    399 			}
    400 		}
    401 
    402 		$attachment_data = isset( $post_data['attachments'][ $post_ID ] ) ? $post_data['attachments'][ $post_ID ] : array();
    403 
    404 		/** This filter is documented in wp-admin/includes/media.php */
    405 		$translated = apply_filters( 'attachment_fields_to_save', $translated, $attachment_data );
    406 	}
    407 
    408 	// Convert taxonomy input to term IDs, to avoid ambiguity.
    409 	if ( isset( $post_data['tax_input'] ) ) {
    410 		foreach ( (array) $post_data['tax_input'] as $taxonomy => $terms ) {
    411 			$tax_object = get_taxonomy( $taxonomy );
    412 
    413 			if ( $tax_object && isset( $tax_object->meta_box_sanitize_cb ) ) {
    414 				$translated['tax_input'][ $taxonomy ] = call_user_func_array( $tax_object->meta_box_sanitize_cb, array( $taxonomy, $terms ) );
    415 			}
    416 		}
    417 	}
    418 
    419 	add_meta( $post_ID );
    420 
    421 	update_post_meta( $post_ID, '_edit_last', get_current_user_id() );
    422 
    423 	$success = wp_update_post( $translated );
    424 
    425 	// If the save failed, see if we can sanity check the main fields and try again.
    426 	if ( ! $success && is_callable( array( $wpdb, 'strip_invalid_text_for_column' ) ) ) {
    427 		$fields = array( 'post_title', 'post_content', 'post_excerpt' );
    428 
    429 		foreach ( $fields as $field ) {
    430 			if ( isset( $translated[ $field ] ) ) {
    431 				$translated[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->posts, $field, $translated[ $field ] );
    432 			}
    433 		}
    434 
    435 		wp_update_post( $translated );
    436 	}
    437 
    438 	// Now that we have an ID we can fix any attachment anchor hrefs.
    439 	_fix_attachment_links( $post_ID );
    440 
    441 	wp_set_post_lock( $post_ID );
    442 
    443 	if ( current_user_can( $ptype->cap->edit_others_posts ) && current_user_can( $ptype->cap->publish_posts ) ) {
    444 		if ( ! empty( $post_data['sticky'] ) ) {
    445 			stick_post( $post_ID );
    446 		} else {
    447 			unstick_post( $post_ID );
    448 		}
    449 	}
    450 
    451 	return $post_ID;
    452 }
    453 
    454 /**
    455  * Process the post data for the bulk editing of posts.
    456  *
    457  * Updates all bulk edited posts/pages, adding (but not removing) tags and
    458  * categories. Skips pages when they would be their own parent or child.
    459  *
    460  * @since 2.7.0
    461  *
    462  * @global wpdb $wpdb WordPress database abstraction object.
    463  *
    464  * @param array $post_data Optional, the array of post data to process if not provided will use $_POST superglobal.
    465  * @return array
    466  */
    467 function bulk_edit_posts( $post_data = null ) {
    468 	global $wpdb;
    469 
    470 	if ( empty( $post_data ) ) {
    471 		$post_data = &$_POST;
    472 	}
    473 
    474 	if ( isset( $post_data['post_type'] ) ) {
    475 		$ptype = get_post_type_object( $post_data['post_type'] );
    476 	} else {
    477 		$ptype = get_post_type_object( 'post' );
    478 	}
    479 
    480 	if ( ! current_user_can( $ptype->cap->edit_posts ) ) {
    481 		if ( 'page' === $ptype->name ) {
    482 			wp_die( __( 'Sorry, you are not allowed to edit pages.' ) );
    483 		} else {
    484 			wp_die( __( 'Sorry, you are not allowed to edit posts.' ) );
    485 		}
    486 	}
    487 
    488 	if ( -1 == $post_data['_status'] ) {
    489 		$post_data['post_status'] = null;
    490 		unset( $post_data['post_status'] );
    491 	} else {
    492 		$post_data['post_status'] = $post_data['_status'];
    493 	}
    494 	unset( $post_data['_status'] );
    495 
    496 	if ( ! empty( $post_data['post_status'] ) ) {
    497 		$post_data['post_status'] = sanitize_key( $post_data['post_status'] );
    498 
    499 		if ( 'inherit' === $post_data['post_status'] ) {
    500 			unset( $post_data['post_status'] );
    501 		}
    502 	}
    503 
    504 	$post_IDs = array_map( 'intval', (array) $post_data['post'] );
    505 
    506 	$reset = array(
    507 		'post_author',
    508 		'post_status',
    509 		'post_password',
    510 		'post_parent',
    511 		'page_template',
    512 		'comment_status',
    513 		'ping_status',
    514 		'keep_private',
    515 		'tax_input',
    516 		'post_category',
    517 		'sticky',
    518 		'post_format',
    519 	);
    520 
    521 	foreach ( $reset as $field ) {
    522 		if ( isset( $post_data[ $field ] ) && ( '' === $post_data[ $field ] || -1 == $post_data[ $field ] ) ) {
    523 			unset( $post_data[ $field ] );
    524 		}
    525 	}
    526 
    527 	if ( isset( $post_data['post_category'] ) ) {
    528 		if ( is_array( $post_data['post_category'] ) && ! empty( $post_data['post_category'] ) ) {
    529 			$new_cats = array_map( 'absint', $post_data['post_category'] );
    530 		} else {
    531 			unset( $post_data['post_category'] );
    532 		}
    533 	}
    534 
    535 	$tax_input = array();
    536 	if ( isset( $post_data['tax_input'] ) ) {
    537 		foreach ( $post_data['tax_input'] as $tax_name => $terms ) {
    538 			if ( empty( $terms ) ) {
    539 				continue;
    540 			}
    541 			if ( is_taxonomy_hierarchical( $tax_name ) ) {
    542 				$tax_input[ $tax_name ] = array_map( 'absint', $terms );
    543 			} else {
    544 				$comma = _x( ',', 'tag delimiter' );
    545 				if ( ',' !== $comma ) {
    546 					$terms = str_replace( $comma, ',', $terms );
    547 				}
    548 				$tax_input[ $tax_name ] = explode( ',', trim( $terms, " \n\t\r\0\x0B," ) );
    549 			}
    550 		}
    551 	}
    552 
    553 	if ( isset( $post_data['post_parent'] ) && (int) $post_data['post_parent'] ) {
    554 		$parent   = (int) $post_data['post_parent'];
    555 		$pages    = $wpdb->get_results( "SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'" );
    556 		$children = array();
    557 
    558 		for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
    559 			$children[] = $parent;
    560 
    561 			foreach ( $pages as $page ) {
    562 				if ( (int) $page->ID === $parent ) {
    563 					$parent = (int) $page->post_parent;
    564 					break;
    565 				}
    566 			}
    567 		}
    568 	}
    569 
    570 	$updated          = array();
    571 	$skipped          = array();
    572 	$locked           = array();
    573 	$shared_post_data = $post_data;
    574 
    575 	foreach ( $post_IDs as $post_ID ) {
    576 		// Start with fresh post data with each iteration.
    577 		$post_data = $shared_post_data;
    578 
    579 		$post_type_object = get_post_type_object( get_post_type( $post_ID ) );
    580 
    581 		if ( ! isset( $post_type_object )
    582 			|| ( isset( $children ) && in_array( $post_ID, $children, true ) )
    583 			|| ! current_user_can( 'edit_post', $post_ID )
    584 		) {
    585 			$skipped[] = $post_ID;
    586 			continue;
    587 		}
    588 
    589 		if ( wp_check_post_lock( $post_ID ) ) {
    590 			$locked[] = $post_ID;
    591 			continue;
    592 		}
    593 
    594 		$post      = get_post( $post_ID );
    595 		$tax_names = get_object_taxonomies( $post );
    596 		foreach ( $tax_names as $tax_name ) {
    597 			$taxonomy_obj = get_taxonomy( $tax_name );
    598 			if ( isset( $tax_input[ $tax_name ] ) && current_user_can( $taxonomy_obj->cap->assign_terms ) ) {
    599 				$new_terms = $tax_input[ $tax_name ];
    600 			} else {
    601 				$new_terms = array();
    602 			}
    603 
    604 			if ( $taxonomy_obj->hierarchical ) {
    605 				$current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array( 'fields' => 'ids' ) );
    606 			} else {
    607 				$current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array( 'fields' => 'names' ) );
    608 			}
    609 
    610 			$post_data['tax_input'][ $tax_name ] = array_merge( $current_terms, $new_terms );
    611 		}
    612 
    613 		if ( isset( $new_cats ) && in_array( 'category', $tax_names, true ) ) {
    614 			$cats                       = (array) wp_get_post_categories( $post_ID );
    615 			$post_data['post_category'] = array_unique( array_merge( $cats, $new_cats ) );
    616 			unset( $post_data['tax_input']['category'] );
    617 		}
    618 
    619 		$post_data['post_ID']        = $post_ID;
    620 		$post_data['post_type']      = $post->post_type;
    621 		$post_data['post_mime_type'] = $post->post_mime_type;
    622 
    623 		foreach ( array( 'comment_status', 'ping_status', 'post_author' ) as $field ) {
    624 			if ( ! isset( $post_data[ $field ] ) ) {
    625 				$post_data[ $field ] = $post->$field;
    626 			}
    627 		}
    628 
    629 		$post_data = _wp_translate_postdata( true, $post_data );
    630 		if ( is_wp_error( $post_data ) ) {
    631 			$skipped[] = $post_ID;
    632 			continue;
    633 		}
    634 		$post_data = _wp_get_allowed_postdata( $post_data );
    635 
    636 		if ( isset( $shared_post_data['post_format'] ) ) {
    637 			set_post_format( $post_ID, $shared_post_data['post_format'] );
    638 		}
    639 
    640 		// Prevent wp_insert_post() from overwriting post format with the old data.
    641 		unset( $post_data['tax_input']['post_format'] );
    642 
    643 		$updated[] = wp_update_post( $post_data );
    644 
    645 		if ( isset( $post_data['sticky'] ) && current_user_can( $ptype->cap->edit_others_posts ) ) {
    646 			if ( 'sticky' === $post_data['sticky'] ) {
    647 				stick_post( $post_ID );
    648 			} else {
    649 				unstick_post( $post_ID );
    650 			}
    651 		}
    652 	}
    653 
    654 	return array(
    655 		'updated' => $updated,
    656 		'skipped' => $skipped,
    657 		'locked'  => $locked,
    658 	);
    659 }
    660 
    661 /**
    662  * Default post information to use when populating the "Write Post" form.
    663  *
    664  * @since 2.0.0
    665  *
    666  * @param string $post_type    Optional. A post type string. Default 'post'.
    667  * @param bool   $create_in_db Optional. Whether to insert the post into database. Default false.
    668  * @return WP_Post Post object containing all the default post data as attributes
    669  */
    670 function get_default_post_to_edit( $post_type = 'post', $create_in_db = false ) {
    671 	$post_title = '';
    672 	if ( ! empty( $_REQUEST['post_title'] ) ) {
    673 		$post_title = esc_html( wp_unslash( $_REQUEST['post_title'] ) );
    674 	}
    675 
    676 	$post_content = '';
    677 	if ( ! empty( $_REQUEST['content'] ) ) {
    678 		$post_content = esc_html( wp_unslash( $_REQUEST['content'] ) );
    679 	}
    680 
    681 	$post_excerpt = '';
    682 	if ( ! empty( $_REQUEST['excerpt'] ) ) {
    683 		$post_excerpt = esc_html( wp_unslash( $_REQUEST['excerpt'] ) );
    684 	}
    685 
    686 	if ( $create_in_db ) {
    687 		$post_id = wp_insert_post(
    688 			array(
    689 				'post_title'  => __( 'Auto Draft' ),
    690 				'post_type'   => $post_type,
    691 				'post_status' => 'auto-draft',
    692 			),
    693 			false,
    694 			false
    695 		);
    696 		$post    = get_post( $post_id );
    697 		if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) && get_option( 'default_post_format' ) ) {
    698 			set_post_format( $post, get_option( 'default_post_format' ) );
    699 		}
    700 		wp_after_insert_post( $post, false, null );
    701 
    702 		// Schedule auto-draft cleanup.
    703 		if ( ! wp_next_scheduled( 'wp_scheduled_auto_draft_delete' ) ) {
    704 			wp_schedule_event( time(), 'daily', 'wp_scheduled_auto_draft_delete' );
    705 		}
    706 	} else {
    707 		$post                 = new stdClass;
    708 		$post->ID             = 0;
    709 		$post->post_author    = '';
    710 		$post->post_date      = '';
    711 		$post->post_date_gmt  = '';
    712 		$post->post_password  = '';
    713 		$post->post_name      = '';
    714 		$post->post_type      = $post_type;
    715 		$post->post_status    = 'draft';
    716 		$post->to_ping        = '';
    717 		$post->pinged         = '';
    718 		$post->comment_status = get_default_comment_status( $post_type );
    719 		$post->ping_status    = get_default_comment_status( $post_type, 'pingback' );
    720 		$post->post_pingback  = get_option( 'default_pingback_flag' );
    721 		$post->post_category  = get_option( 'default_category' );
    722 		$post->page_template  = 'default';
    723 		$post->post_parent    = 0;
    724 		$post->menu_order     = 0;
    725 		$post                 = new WP_Post( $post );
    726 	}
    727 
    728 	/**
    729 	 * Filters the default post content initially used in the "Write Post" form.
    730 	 *
    731 	 * @since 1.5.0
    732 	 *
    733 	 * @param string  $post_content Default post content.
    734 	 * @param WP_Post $post         Post object.
    735 	 */
    736 	$post->post_content = (string) apply_filters( 'default_content', $post_content, $post );
    737 
    738 	/**
    739 	 * Filters the default post title initially used in the "Write Post" form.
    740 	 *
    741 	 * @since 1.5.0
    742 	 *
    743 	 * @param string  $post_title Default post title.
    744 	 * @param WP_Post $post       Post object.
    745 	 */
    746 	$post->post_title = (string) apply_filters( 'default_title', $post_title, $post );
    747 
    748 	/**
    749 	 * Filters the default post excerpt initially used in the "Write Post" form.
    750 	 *
    751 	 * @since 1.5.0
    752 	 *
    753 	 * @param string  $post_excerpt Default post excerpt.
    754 	 * @param WP_Post $post         Post object.
    755 	 */
    756 	$post->post_excerpt = (string) apply_filters( 'default_excerpt', $post_excerpt, $post );
    757 
    758 	return $post;
    759 }
    760 
    761 /**
    762  * Determines if a post exists based on title, content, date and type.
    763  *
    764  * @since 2.0.0
    765  * @since 5.2.0 Added the `$type` parameter.
    766  * @since 5.8.0 Added the `$status` parameter.
    767  *
    768  * @global wpdb $wpdb WordPress database abstraction object.
    769  *
    770  * @param string $title   Post title.
    771  * @param string $content Optional post content.
    772  * @param string $date    Optional post date.
    773  * @param string $type    Optional post type.
    774  * @param string $status  Optional post status.
    775  * @return int Post ID if post exists, 0 otherwise.
    776  */
    777 function post_exists( $title, $content = '', $date = '', $type = '', $status = '' ) {
    778 	global $wpdb;
    779 
    780 	$post_title   = wp_unslash( sanitize_post_field( 'post_title', $title, 0, 'db' ) );
    781 	$post_content = wp_unslash( sanitize_post_field( 'post_content', $content, 0, 'db' ) );
    782 	$post_date    = wp_unslash( sanitize_post_field( 'post_date', $date, 0, 'db' ) );
    783 	$post_type    = wp_unslash( sanitize_post_field( 'post_type', $type, 0, 'db' ) );
    784 	$post_status  = wp_unslash( sanitize_post_field( 'post_status', $status, 0, 'db' ) );
    785 
    786 	$query = "SELECT ID FROM $wpdb->posts WHERE 1=1";
    787 	$args  = array();
    788 
    789 	if ( ! empty( $date ) ) {
    790 		$query .= ' AND post_date = %s';
    791 		$args[] = $post_date;
    792 	}
    793 
    794 	if ( ! empty( $title ) ) {
    795 		$query .= ' AND post_title = %s';
    796 		$args[] = $post_title;
    797 	}
    798 
    799 	if ( ! empty( $content ) ) {
    800 		$query .= ' AND post_content = %s';
    801 		$args[] = $post_content;
    802 	}
    803 
    804 	if ( ! empty( $type ) ) {
    805 		$query .= ' AND post_type = %s';
    806 		$args[] = $post_type;
    807 	}
    808 
    809 	if ( ! empty( $status ) ) {
    810 		$query .= ' AND post_status = %s';
    811 		$args[] = $post_status;
    812 	}
    813 
    814 	if ( ! empty( $args ) ) {
    815 		return (int) $wpdb->get_var( $wpdb->prepare( $query, $args ) );
    816 	}
    817 
    818 	return 0;
    819 }
    820 
    821 /**
    822  * Creates a new post from the "Write Post" form using $_POST information.
    823  *
    824  * @since 2.1.0
    825  *
    826  * @global WP_User $current_user
    827  *
    828  * @return int|WP_Error Post ID on success, WP_Error on failure.
    829  */
    830 function wp_write_post() {
    831 	if ( isset( $_POST['post_type'] ) ) {
    832 		$ptype = get_post_type_object( $_POST['post_type'] );
    833 	} else {
    834 		$ptype = get_post_type_object( 'post' );
    835 	}
    836 
    837 	if ( ! current_user_can( $ptype->cap->edit_posts ) ) {
    838 		if ( 'page' === $ptype->name ) {
    839 			return new WP_Error( 'edit_pages', __( 'Sorry, you are not allowed to create pages on this site.' ) );
    840 		} else {
    841 			return new WP_Error( 'edit_posts', __( 'Sorry, you are not allowed to create posts or drafts on this site.' ) );
    842 		}
    843 	}
    844 
    845 	$_POST['post_mime_type'] = '';
    846 
    847 	// Clear out any data in internal vars.
    848 	unset( $_POST['filter'] );
    849 
    850 	// Edit, don't write, if we have a post ID.
    851 	if ( isset( $_POST['post_ID'] ) ) {
    852 		return edit_post();
    853 	}
    854 
    855 	if ( isset( $_POST['visibility'] ) ) {
    856 		switch ( $_POST['visibility'] ) {
    857 			case 'public':
    858 				$_POST['post_password'] = '';
    859 				break;
    860 			case 'password':
    861 				unset( $_POST['sticky'] );
    862 				break;
    863 			case 'private':
    864 				$_POST['post_status']   = 'private';
    865 				$_POST['post_password'] = '';
    866 				unset( $_POST['sticky'] );
    867 				break;
    868 		}
    869 	}
    870 
    871 	$translated = _wp_translate_postdata( false );
    872 	if ( is_wp_error( $translated ) ) {
    873 		return $translated;
    874 	}
    875 	$translated = _wp_get_allowed_postdata( $translated );
    876 
    877 	// Create the post.
    878 	$post_ID = wp_insert_post( $translated );
    879 	if ( is_wp_error( $post_ID ) ) {
    880 		return $post_ID;
    881 	}
    882 
    883 	if ( empty( $post_ID ) ) {
    884 		return 0;
    885 	}
    886 
    887 	add_meta( $post_ID );
    888 
    889 	add_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
    890 
    891 	// Now that we have an ID we can fix any attachment anchor hrefs.
    892 	_fix_attachment_links( $post_ID );
    893 
    894 	wp_set_post_lock( $post_ID );
    895 
    896 	return $post_ID;
    897 }
    898 
    899 /**
    900  * Calls wp_write_post() and handles the errors.
    901  *
    902  * @since 2.0.0
    903  *
    904  * @return int|void Post ID on success, void on failure.
    905  */
    906 function write_post() {
    907 	$result = wp_write_post();
    908 	if ( is_wp_error( $result ) ) {
    909 		wp_die( $result->get_error_message() );
    910 	} else {
    911 		return $result;
    912 	}
    913 }
    914 
    915 //
    916 // Post Meta.
    917 //
    918 
    919 /**
    920  * Add post meta data defined in $_POST superglobal for post with given ID.
    921  *
    922  * @since 1.2.0
    923  *
    924  * @param int $post_ID
    925  * @return int|bool
    926  */
    927 function add_meta( $post_ID ) {
    928 	$post_ID = (int) $post_ID;
    929 
    930 	$metakeyselect = isset( $_POST['metakeyselect'] ) ? wp_unslash( trim( $_POST['metakeyselect'] ) ) : '';
    931 	$metakeyinput  = isset( $_POST['metakeyinput'] ) ? wp_unslash( trim( $_POST['metakeyinput'] ) ) : '';
    932 	$metavalue     = isset( $_POST['metavalue'] ) ? $_POST['metavalue'] : '';
    933 	if ( is_string( $metavalue ) ) {
    934 		$metavalue = trim( $metavalue );
    935 	}
    936 
    937 	if ( ( ( '#NONE#' !== $metakeyselect ) && ! empty( $metakeyselect ) ) || ! empty( $metakeyinput ) ) {
    938 		/*
    939 		 * We have a key/value pair. If both the select and the input
    940 		 * for the key have data, the input takes precedence.
    941 		 */
    942 		if ( '#NONE#' !== $metakeyselect ) {
    943 			$metakey = $metakeyselect;
    944 		}
    945 
    946 		if ( $metakeyinput ) {
    947 			$metakey = $metakeyinput; // Default.
    948 		}
    949 
    950 		if ( is_protected_meta( $metakey, 'post' ) || ! current_user_can( 'add_post_meta', $post_ID, $metakey ) ) {
    951 			return false;
    952 		}
    953 
    954 		$metakey = wp_slash( $metakey );
    955 
    956 		return add_post_meta( $post_ID, $metakey, $metavalue );
    957 	}
    958 
    959 	return false;
    960 }
    961 
    962 /**
    963  * Delete post meta data by meta ID.
    964  *
    965  * @since 1.2.0
    966  *
    967  * @param int $mid
    968  * @return bool
    969  */
    970 function delete_meta( $mid ) {
    971 	return delete_metadata_by_mid( 'post', $mid );
    972 }
    973 
    974 /**
    975  * Get a list of previously defined keys.
    976  *
    977  * @since 1.2.0
    978  *
    979  * @global wpdb $wpdb WordPress database abstraction object.
    980  *
    981  * @return mixed
    982  */
    983 function get_meta_keys() {
    984 	global $wpdb;
    985 
    986 	$keys = $wpdb->get_col(
    987 		"
    988 			SELECT meta_key
    989 			FROM $wpdb->postmeta
    990 			GROUP BY meta_key
    991 			ORDER BY meta_key"
    992 	);
    993 
    994 	return $keys;
    995 }
    996 
    997 /**
    998  * Get post meta data by meta ID.
    999  *
   1000  * @since 2.1.0
   1001  *
   1002  * @param int $mid
   1003  * @return object|bool
   1004  */
   1005 function get_post_meta_by_id( $mid ) {
   1006 	return get_metadata_by_mid( 'post', $mid );
   1007 }
   1008 
   1009 /**
   1010  * Get meta data for the given post ID.
   1011  *
   1012  * @since 1.2.0
   1013  *
   1014  * @global wpdb $wpdb WordPress database abstraction object.
   1015  *
   1016  * @param int $postid
   1017  * @return mixed
   1018  */
   1019 function has_meta( $postid ) {
   1020 	global $wpdb;
   1021 
   1022 	return $wpdb->get_results(
   1023 		$wpdb->prepare(
   1024 			"SELECT meta_key, meta_value, meta_id, post_id
   1025 			FROM $wpdb->postmeta WHERE post_id = %d
   1026 			ORDER BY meta_key,meta_id",
   1027 			$postid
   1028 		),
   1029 		ARRAY_A
   1030 	);
   1031 }
   1032 
   1033 /**
   1034  * Update post meta data by meta ID.
   1035  *
   1036  * @since 1.2.0
   1037  *
   1038  * @param int    $meta_id
   1039  * @param string $meta_key Expect Slashed
   1040  * @param string $meta_value Expect Slashed
   1041  * @return bool
   1042  */
   1043 function update_meta( $meta_id, $meta_key, $meta_value ) {
   1044 	$meta_key   = wp_unslash( $meta_key );
   1045 	$meta_value = wp_unslash( $meta_value );
   1046 
   1047 	return update_metadata_by_mid( 'post', $meta_id, $meta_value, $meta_key );
   1048 }
   1049 
   1050 //
   1051 // Private.
   1052 //
   1053 
   1054 /**
   1055  * Replace hrefs of attachment anchors with up-to-date permalinks.
   1056  *
   1057  * @since 2.3.0
   1058  * @access private
   1059  *
   1060  * @param int|object $post Post ID or post object.
   1061  * @return void|int|WP_Error Void if nothing fixed. 0 or WP_Error on update failure. The post ID on update success.
   1062  */
   1063 function _fix_attachment_links( $post ) {
   1064 	$post    = get_post( $post, ARRAY_A );
   1065 	$content = $post['post_content'];
   1066 
   1067 	// Don't run if no pretty permalinks or post is not published, scheduled, or privately published.
   1068 	if ( ! get_option( 'permalink_structure' ) || ! in_array( $post['post_status'], array( 'publish', 'future', 'private' ), true ) ) {
   1069 		return;
   1070 	}
   1071 
   1072 	// Short if there aren't any links or no '?attachment_id=' strings (strpos cannot be zero).
   1073 	if ( ! strpos( $content, '?attachment_id=' ) || ! preg_match_all( '/<a ([^>]+)>[\s\S]+?<\/a>/', $content, $link_matches ) ) {
   1074 		return;
   1075 	}
   1076 
   1077 	$site_url = get_bloginfo( 'url' );
   1078 	$site_url = substr( $site_url, (int) strpos( $site_url, '://' ) ); // Remove the http(s).
   1079 	$replace  = '';
   1080 
   1081 	foreach ( $link_matches[1] as $key => $value ) {
   1082 		if ( ! strpos( $value, '?attachment_id=' ) || ! strpos( $value, 'wp-att-' )
   1083 			|| ! preg_match( '/href=(["\'])[^"\']*\?attachment_id=(\d+)[^"\']*\\1/', $value, $url_match )
   1084 			|| ! preg_match( '/rel=["\'][^"\']*wp-att-(\d+)/', $value, $rel_match ) ) {
   1085 				continue;
   1086 		}
   1087 
   1088 		$quote  = $url_match[1]; // The quote (single or double).
   1089 		$url_id = (int) $url_match[2];
   1090 		$rel_id = (int) $rel_match[1];
   1091 
   1092 		if ( ! $url_id || ! $rel_id || $url_id != $rel_id || strpos( $url_match[0], $site_url ) === false ) {
   1093 			continue;
   1094 		}
   1095 
   1096 		$link    = $link_matches[0][ $key ];
   1097 		$replace = str_replace( $url_match[0], 'href=' . $quote . get_attachment_link( $url_id ) . $quote, $link );
   1098 
   1099 		$content = str_replace( $link, $replace, $content );
   1100 	}
   1101 
   1102 	if ( $replace ) {
   1103 		$post['post_content'] = $content;
   1104 		// Escape data pulled from DB.
   1105 		$post = add_magic_quotes( $post );
   1106 
   1107 		return wp_update_post( $post );
   1108 	}
   1109 }
   1110 
   1111 /**
   1112  * Get all the possible statuses for a post_type
   1113  *
   1114  * @since 2.5.0
   1115  *
   1116  * @param string $type The post_type you want the statuses for. Default 'post'.
   1117  * @return string[] An array of all the statuses for the supplied post type.
   1118  */
   1119 function get_available_post_statuses( $type = 'post' ) {
   1120 	$stati = wp_count_posts( $type );
   1121 
   1122 	return array_keys( get_object_vars( $stati ) );
   1123 }
   1124 
   1125 /**
   1126  * Run the wp query to fetch the posts for listing on the edit posts page
   1127  *
   1128  * @since 2.5.0
   1129  *
   1130  * @param array|false $q Array of query variables to use to build the query or false to use $_GET superglobal.
   1131  * @return array
   1132  */
   1133 function wp_edit_posts_query( $q = false ) {
   1134 	if ( false === $q ) {
   1135 		$q = $_GET;
   1136 	}
   1137 	$q['m']     = isset( $q['m'] ) ? (int) $q['m'] : 0;
   1138 	$q['cat']   = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
   1139 	$post_stati = get_post_stati();
   1140 
   1141 	if ( isset( $q['post_type'] ) && in_array( $q['post_type'], get_post_types(), true ) ) {
   1142 		$post_type = $q['post_type'];
   1143 	} else {
   1144 		$post_type = 'post';
   1145 	}
   1146 
   1147 	$avail_post_stati = get_available_post_statuses( $post_type );
   1148 	$post_status      = '';
   1149 	$perm             = '';
   1150 
   1151 	if ( isset( $q['post_status'] ) && in_array( $q['post_status'], $post_stati, true ) ) {
   1152 		$post_status = $q['post_status'];
   1153 		$perm        = 'readable';
   1154 	}
   1155 
   1156 	$orderby = '';
   1157 
   1158 	if ( isset( $q['orderby'] ) ) {
   1159 		$orderby = $q['orderby'];
   1160 	} elseif ( isset( $q['post_status'] ) && in_array( $q['post_status'], array( 'pending', 'draft' ), true ) ) {
   1161 		$orderby = 'modified';
   1162 	}
   1163 
   1164 	$order = '';
   1165 
   1166 	if ( isset( $q['order'] ) ) {
   1167 		$order = $q['order'];
   1168 	} elseif ( isset( $q['post_status'] ) && 'pending' === $q['post_status'] ) {
   1169 		$order = 'ASC';
   1170 	}
   1171 
   1172 	$per_page       = "edit_{$post_type}_per_page";
   1173 	$posts_per_page = (int) get_user_option( $per_page );
   1174 	if ( empty( $posts_per_page ) || $posts_per_page < 1 ) {
   1175 		$posts_per_page = 20;
   1176 	}
   1177 
   1178 	/**
   1179 	 * Filters the number of items per page to show for a specific 'per_page' type.
   1180 	 *
   1181 	 * The dynamic portion of the hook name, `$post_type`, refers to the post type.
   1182 	 *
   1183 	 * Possible hook names include:
   1184 	 *
   1185 	 *  - `edit_post_per_page`
   1186 	 *  - `edit_page_per_page`
   1187 	 *  - `edit_attachment_per_page`
   1188 	 *
   1189 	 * @since 3.0.0
   1190 	 *
   1191 	 * @param int $posts_per_page Number of posts to display per page for the given post
   1192 	 *                            type. Default 20.
   1193 	 */
   1194 	$posts_per_page = apply_filters( "edit_{$post_type}_per_page", $posts_per_page );
   1195 
   1196 	/**
   1197 	 * Filters the number of posts displayed per page when specifically listing "posts".
   1198 	 *
   1199 	 * @since 2.8.0
   1200 	 *
   1201 	 * @param int    $posts_per_page Number of posts to be displayed. Default 20.
   1202 	 * @param string $post_type      The post type.
   1203 	 */
   1204 	$posts_per_page = apply_filters( 'edit_posts_per_page', $posts_per_page, $post_type );
   1205 
   1206 	$query = compact( 'post_type', 'post_status', 'perm', 'order', 'orderby', 'posts_per_page' );
   1207 
   1208 	// Hierarchical types require special args.
   1209 	if ( is_post_type_hierarchical( $post_type ) && empty( $orderby ) ) {
   1210 		$query['orderby']                = 'menu_order title';
   1211 		$query['order']                  = 'asc';
   1212 		$query['posts_per_page']         = -1;
   1213 		$query['posts_per_archive_page'] = -1;
   1214 		$query['fields']                 = 'id=>parent';
   1215 	}
   1216 
   1217 	if ( ! empty( $q['show_sticky'] ) ) {
   1218 		$query['post__in'] = (array) get_option( 'sticky_posts' );
   1219 	}
   1220 
   1221 	wp( $query );
   1222 
   1223 	return $avail_post_stati;
   1224 }
   1225 
   1226 /**
   1227  * Get the query variables for the current attachments request.
   1228  *
   1229  * @since 4.2.0
   1230  *
   1231  * @param array|false $q Optional. Array of query variables to use to build the query or false
   1232  *                       to use $_GET superglobal. Default false.
   1233  * @return array The parsed query vars.
   1234  */
   1235 function wp_edit_attachments_query_vars( $q = false ) {
   1236 	if ( false === $q ) {
   1237 		$q = $_GET;
   1238 	}
   1239 	$q['m']         = isset( $q['m'] ) ? (int) $q['m'] : 0;
   1240 	$q['cat']       = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
   1241 	$q['post_type'] = 'attachment';
   1242 	$post_type      = get_post_type_object( 'attachment' );
   1243 	$states         = 'inherit';
   1244 	if ( current_user_can( $post_type->cap->read_private_posts ) ) {
   1245 		$states .= ',private';
   1246 	}
   1247 
   1248 	$q['post_status'] = isset( $q['status'] ) && 'trash' === $q['status'] ? 'trash' : $states;
   1249 	$q['post_status'] = isset( $q['attachment-filter'] ) && 'trash' === $q['attachment-filter'] ? 'trash' : $states;
   1250 
   1251 	$media_per_page = (int) get_user_option( 'upload_per_page' );
   1252 	if ( empty( $media_per_page ) || $media_per_page < 1 ) {
   1253 		$media_per_page = 20;
   1254 	}
   1255 
   1256 	/**
   1257 	 * Filters the number of items to list per page when listing media items.
   1258 	 *
   1259 	 * @since 2.9.0
   1260 	 *
   1261 	 * @param int $media_per_page Number of media to list. Default 20.
   1262 	 */
   1263 	$q['posts_per_page'] = apply_filters( 'upload_per_page', $media_per_page );
   1264 
   1265 	$post_mime_types = get_post_mime_types();
   1266 	if ( isset( $q['post_mime_type'] ) && ! array_intersect( (array) $q['post_mime_type'], array_keys( $post_mime_types ) ) ) {
   1267 		unset( $q['post_mime_type'] );
   1268 	}
   1269 
   1270 	foreach ( array_keys( $post_mime_types ) as $type ) {
   1271 		if ( isset( $q['attachment-filter'] ) && "post_mime_type:$type" === $q['attachment-filter'] ) {
   1272 			$q['post_mime_type'] = $type;
   1273 			break;
   1274 		}
   1275 	}
   1276 
   1277 	if ( isset( $q['detached'] ) || ( isset( $q['attachment-filter'] ) && 'detached' === $q['attachment-filter'] ) ) {
   1278 		$q['post_parent'] = 0;
   1279 	}
   1280 
   1281 	if ( isset( $q['mine'] ) || ( isset( $q['attachment-filter'] ) && 'mine' === $q['attachment-filter'] ) ) {
   1282 		$q['author'] = get_current_user_id();
   1283 	}
   1284 
   1285 	// Filter query clauses to include filenames.
   1286 	if ( isset( $q['s'] ) ) {
   1287 		add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
   1288 	}
   1289 
   1290 	return $q;
   1291 }
   1292 
   1293 /**
   1294  * Executes a query for attachments. An array of WP_Query arguments
   1295  * can be passed in, which will override the arguments set by this function.
   1296  *
   1297  * @since 2.5.0
   1298  *
   1299  * @param array|false $q Array of query variables to use to build the query or false to use $_GET superglobal.
   1300  * @return array
   1301  */
   1302 function wp_edit_attachments_query( $q = false ) {
   1303 	wp( wp_edit_attachments_query_vars( $q ) );
   1304 
   1305 	$post_mime_types       = get_post_mime_types();
   1306 	$avail_post_mime_types = get_available_post_mime_types( 'attachment' );
   1307 
   1308 	return array( $post_mime_types, $avail_post_mime_types );
   1309 }
   1310 
   1311 /**
   1312  * Returns the list of classes to be used by a meta box.
   1313  *
   1314  * @since 2.5.0
   1315  *
   1316  * @param string $box_id    Meta box ID (used in the 'id' attribute for the meta box).
   1317  * @param string $screen_id The screen on which the meta box is shown.
   1318  * @return string Space-separated string of class names.
   1319  */
   1320 function postbox_classes( $box_id, $screen_id ) {
   1321 	if ( isset( $_GET['edit'] ) && $_GET['edit'] == $box_id ) {
   1322 		$classes = array( '' );
   1323 	} elseif ( get_user_option( 'closedpostboxes_' . $screen_id ) ) {
   1324 		$closed = get_user_option( 'closedpostboxes_' . $screen_id );
   1325 		if ( ! is_array( $closed ) ) {
   1326 			$classes = array( '' );
   1327 		} else {
   1328 			$classes = in_array( $box_id, $closed, true ) ? array( 'closed' ) : array( '' );
   1329 		}
   1330 	} else {
   1331 		$classes = array( '' );
   1332 	}
   1333 
   1334 	/**
   1335 	 * Filters the postbox classes for a specific screen and box ID combo.
   1336 	 *
   1337 	 * The dynamic portions of the hook name, `$screen_id` and `$box_id`, refer to
   1338 	 * the screen ID and meta box ID, respectively.
   1339 	 *
   1340 	 * @since 3.2.0
   1341 	 *
   1342 	 * @param string[] $classes An array of postbox classes.
   1343 	 */
   1344 	$classes = apply_filters( "postbox_classes_{$screen_id}_{$box_id}", $classes );
   1345 	return implode( ' ', $classes );
   1346 }
   1347 
   1348 /**
   1349  * Get a sample permalink based off of the post name.
   1350  *
   1351  * @since 2.5.0
   1352  *
   1353  * @param int|WP_Post $id    Post ID or post object.
   1354  * @param string      $title Optional. Title to override the post's current title when generating the post name. Default null.
   1355  * @param string      $name  Optional. Name to override the post name. Default null.
   1356  * @return array {
   1357  *     Array containing the sample permalink with placeholder for the post name, and the post name.
   1358  *
   1359  *     @type string $0 The permalink with placeholder for the post name.
   1360  *     @type string $1 The post name.
   1361  * }
   1362  */
   1363 function get_sample_permalink( $id, $title = null, $name = null ) {
   1364 	$post = get_post( $id );
   1365 	if ( ! $post ) {
   1366 		return array( '', '' );
   1367 	}
   1368 
   1369 	$ptype = get_post_type_object( $post->post_type );
   1370 
   1371 	$original_status = $post->post_status;
   1372 	$original_date   = $post->post_date;
   1373 	$original_name   = $post->post_name;
   1374 
   1375 	// Hack: get_permalink() would return plain permalink for drafts, so we will fake that our post is published.
   1376 	if ( in_array( $post->post_status, array( 'draft', 'pending', 'future' ), true ) ) {
   1377 		$post->post_status = 'publish';
   1378 		$post->post_name   = sanitize_title( $post->post_name ? $post->post_name : $post->post_title, $post->ID );
   1379 	}
   1380 
   1381 	// If the user wants to set a new name -- override the current one.
   1382 	// Note: if empty name is supplied -- use the title instead, see #6072.
   1383 	if ( ! is_null( $name ) ) {
   1384 		$post->post_name = sanitize_title( $name ? $name : $title, $post->ID );
   1385 	}
   1386 
   1387 	$post->post_name = wp_unique_post_slug( $post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent );
   1388 
   1389 	$post->filter = 'sample';
   1390 
   1391 	$permalink = get_permalink( $post, true );
   1392 
   1393 	// Replace custom post_type token with generic pagename token for ease of use.
   1394 	$permalink = str_replace( "%$post->post_type%", '%pagename%', $permalink );
   1395 
   1396 	// Handle page hierarchy.
   1397 	if ( $ptype->hierarchical ) {
   1398 		$uri = get_page_uri( $post );
   1399 		if ( $uri ) {
   1400 			$uri = untrailingslashit( $uri );
   1401 			$uri = strrev( stristr( strrev( $uri ), '/' ) );
   1402 			$uri = untrailingslashit( $uri );
   1403 		}
   1404 
   1405 		/** This filter is documented in wp-admin/edit-tag-form.php */
   1406 		$uri = apply_filters( 'editable_slug', $uri, $post );
   1407 		if ( ! empty( $uri ) ) {
   1408 			$uri .= '/';
   1409 		}
   1410 		$permalink = str_replace( '%pagename%', "{$uri}%pagename%", $permalink );
   1411 	}
   1412 
   1413 	/** This filter is documented in wp-admin/edit-tag-form.php */
   1414 	$permalink         = array( $permalink, apply_filters( 'editable_slug', $post->post_name, $post ) );
   1415 	$post->post_status = $original_status;
   1416 	$post->post_date   = $original_date;
   1417 	$post->post_name   = $original_name;
   1418 	unset( $post->filter );
   1419 
   1420 	/**
   1421 	 * Filters the sample permalink.
   1422 	 *
   1423 	 * @since 4.4.0
   1424 	 *
   1425 	 * @param array   $permalink {
   1426 	 *     Array containing the sample permalink with placeholder for the post name, and the post name.
   1427 	 *
   1428 	 *     @type string $0 The permalink with placeholder for the post name.
   1429 	 *     @type string $1 The post name.
   1430 	 * }
   1431 	 * @param int     $post_id   Post ID.
   1432 	 * @param string  $title     Post title.
   1433 	 * @param string  $name      Post name (slug).
   1434 	 * @param WP_Post $post      Post object.
   1435 	 */
   1436 	return apply_filters( 'get_sample_permalink', $permalink, $post->ID, $title, $name, $post );
   1437 }
   1438 
   1439 /**
   1440  * Returns the HTML of the sample permalink slug editor.
   1441  *
   1442  * @since 2.5.0
   1443  *
   1444  * @param int    $id        Post ID or post object.
   1445  * @param string $new_title Optional. New title. Default null.
   1446  * @param string $new_slug  Optional. New slug. Default null.
   1447  * @return string The HTML of the sample permalink slug editor.
   1448  */
   1449 function get_sample_permalink_html( $id, $new_title = null, $new_slug = null ) {
   1450 	$post = get_post( $id );
   1451 	if ( ! $post ) {
   1452 		return '';
   1453 	}
   1454 
   1455 	list($permalink, $post_name) = get_sample_permalink( $post->ID, $new_title, $new_slug );
   1456 
   1457 	$view_link      = false;
   1458 	$preview_target = '';
   1459 
   1460 	if ( current_user_can( 'read_post', $post->ID ) ) {
   1461 		if ( 'draft' === $post->post_status || empty( $post->post_name ) ) {
   1462 			$view_link      = get_preview_post_link( $post );
   1463 			$preview_target = " target='wp-preview-{$post->ID}'";
   1464 		} else {
   1465 			if ( 'publish' === $post->post_status || 'attachment' === $post->post_type ) {
   1466 				$view_link = get_permalink( $post );
   1467 			} else {
   1468 				// Allow non-published (private, future) to be viewed at a pretty permalink, in case $post->post_name is set.
   1469 				$view_link = str_replace( array( '%pagename%', '%postname%' ), $post->post_name, $permalink );
   1470 			}
   1471 		}
   1472 	}
   1473 
   1474 	// Permalinks without a post/page name placeholder don't have anything to edit.
   1475 	if ( false === strpos( $permalink, '%postname%' ) && false === strpos( $permalink, '%pagename%' ) ) {
   1476 		$return = '<strong>' . __( 'Permalink:' ) . "</strong>\n";
   1477 
   1478 		if ( false !== $view_link ) {
   1479 			$display_link = urldecode( $view_link );
   1480 			$return      .= '<a id="sample-permalink" href="' . esc_url( $view_link ) . '"' . $preview_target . '>' . esc_html( $display_link ) . "</a>\n";
   1481 		} else {
   1482 			$return .= '<span id="sample-permalink">' . $permalink . "</span>\n";
   1483 		}
   1484 
   1485 		// Encourage a pretty permalink setting.
   1486 		if ( ! get_option( 'permalink_structure' ) && current_user_can( 'manage_options' )
   1487 			&& ! ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' ) == $id )
   1488 		) {
   1489 			$return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button button-small" target="_blank">' . __( 'Change Permalinks' ) . "</a></span>\n";
   1490 		}
   1491 	} else {
   1492 		if ( mb_strlen( $post_name ) > 34 ) {
   1493 			$post_name_abridged = mb_substr( $post_name, 0, 16 ) . '&hellip;' . mb_substr( $post_name, -16 );
   1494 		} else {
   1495 			$post_name_abridged = $post_name;
   1496 		}
   1497 
   1498 		$post_name_html = '<span id="editable-post-name">' . esc_html( $post_name_abridged ) . '</span>';
   1499 		$display_link   = str_replace( array( '%pagename%', '%postname%' ), $post_name_html, esc_html( urldecode( $permalink ) ) );
   1500 
   1501 		$return  = '<strong>' . __( 'Permalink:' ) . "</strong>\n";
   1502 		$return .= '<span id="sample-permalink"><a href="' . esc_url( $view_link ) . '"' . $preview_target . '>' . $display_link . "</a></span>\n";
   1503 		$return .= '&lrm;'; // Fix bi-directional text display defect in RTL languages.
   1504 		$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";
   1505 		$return .= '<span id="editable-post-name-full">' . esc_html( $post_name ) . "</span>\n";
   1506 	}
   1507 
   1508 	/**
   1509 	 * Filters the sample permalink HTML markup.
   1510 	 *
   1511 	 * @since 2.9.0
   1512 	 * @since 4.4.0 Added `$post` parameter.
   1513 	 *
   1514 	 * @param string  $return    Sample permalink HTML markup.
   1515 	 * @param int     $post_id   Post ID.
   1516 	 * @param string  $new_title New sample permalink title.
   1517 	 * @param string  $new_slug  New sample permalink slug.
   1518 	 * @param WP_Post $post      Post object.
   1519 	 */
   1520 	$return = apply_filters( 'get_sample_permalink_html', $return, $post->ID, $new_title, $new_slug, $post );
   1521 
   1522 	return $return;
   1523 }
   1524 
   1525 /**
   1526  * Returns HTML for the post thumbnail meta box.
   1527  *
   1528  * @since 2.9.0
   1529  *
   1530  * @param int         $thumbnail_id ID of the attachment used for thumbnail
   1531  * @param int|WP_Post $post         Optional. The post ID or object associated with the thumbnail, defaults to global $post.
   1532  * @return string The post thumbnail HTML.
   1533  */
   1534 function _wp_post_thumbnail_html( $thumbnail_id = null, $post = null ) {
   1535 	$_wp_additional_image_sizes = wp_get_additional_image_sizes();
   1536 
   1537 	$post               = get_post( $post );
   1538 	$post_type_object   = get_post_type_object( $post->post_type );
   1539 	$set_thumbnail_link = '<p class="hide-if-no-js"><a href="%s" id="set-post-thumbnail"%s class="thickbox">%s</a></p>';
   1540 	$upload_iframe_src  = get_upload_iframe_src( 'image', $post->ID );
   1541 
   1542 	$content = sprintf(
   1543 		$set_thumbnail_link,
   1544 		esc_url( $upload_iframe_src ),
   1545 		'', // Empty when there's no featured image set, `aria-describedby` attribute otherwise.
   1546 		esc_html( $post_type_object->labels->set_featured_image )
   1547 	);
   1548 
   1549 	if ( $thumbnail_id && get_post( $thumbnail_id ) ) {
   1550 		$size = isset( $_wp_additional_image_sizes['post-thumbnail'] ) ? 'post-thumbnail' : array( 266, 266 );
   1551 
   1552 		/**
   1553 		 * Filters the size used to display the post thumbnail image in the 'Featured image' meta box.
   1554 		 *
   1555 		 * Note: When a theme adds 'post-thumbnail' support, a special 'post-thumbnail'
   1556 		 * image size is registered, which differs from the 'thumbnail' image size
   1557 		 * managed via the Settings > Media screen.
   1558 		 *
   1559 		 * @since 4.4.0
   1560 		 *
   1561 		 * @param string|int[] $size         Requested image size. Can be any registered image size name, or
   1562 		 *                                   an array of width and height values in pixels (in that order).
   1563 		 * @param int          $thumbnail_id Post thumbnail attachment ID.
   1564 		 * @param WP_Post      $post         The post object associated with the thumbnail.
   1565 		 */
   1566 		$size = apply_filters( 'admin_post_thumbnail_size', $size, $thumbnail_id, $post );
   1567 
   1568 		$thumbnail_html = wp_get_attachment_image( $thumbnail_id, $size );
   1569 
   1570 		if ( ! empty( $thumbnail_html ) ) {
   1571 			$content  = sprintf(
   1572 				$set_thumbnail_link,
   1573 				esc_url( $upload_iframe_src ),
   1574 				' aria-describedby="set-post-thumbnail-desc"',
   1575 				$thumbnail_html
   1576 			);
   1577 			$content .= '<p class="hide-if-no-js howto" id="set-post-thumbnail-desc">' . __( 'Click the image to edit or update' ) . '</p>';
   1578 			$content .= '<p class="hide-if-no-js"><a href="#" id="remove-post-thumbnail">' . esc_html( $post_type_object->labels->remove_featured_image ) . '</a></p>';
   1579 		}
   1580 	}
   1581 
   1582 	$content .= '<input type="hidden" id="_thumbnail_id" name="_thumbnail_id" value="' . esc_attr( $thumbnail_id ? $thumbnail_id : '-1' ) . '" />';
   1583 
   1584 	/**
   1585 	 * Filters the admin post thumbnail HTML markup to return.
   1586 	 *
   1587 	 * @since 2.9.0
   1588 	 * @since 3.5.0 Added the `$post_id` parameter.
   1589 	 * @since 4.6.0 Added the `$thumbnail_id` parameter.
   1590 	 *
   1591 	 * @param string   $content      Admin post thumbnail HTML markup.
   1592 	 * @param int      $post_id      Post ID.
   1593 	 * @param int|null $thumbnail_id Thumbnail attachment ID, or null if there isn't one.
   1594 	 */
   1595 	return apply_filters( 'admin_post_thumbnail_html', $content, $post->ID, $thumbnail_id );
   1596 }
   1597 
   1598 /**
   1599  * Check to see if the post is currently being edited by another user.
   1600  *
   1601  * @since 2.5.0
   1602  *
   1603  * @param int|WP_Post $post_id ID or object of the post to check for editing.
   1604  * @return int|false ID of the user with lock. False if the post does not exist, post is not locked,
   1605  *                   the user with lock does not exist, or the post is locked by current user.
   1606  */
   1607 function wp_check_post_lock( $post_id ) {
   1608 	$post = get_post( $post_id );
   1609 	if ( ! $post ) {
   1610 		return false;
   1611 	}
   1612 
   1613 	$lock = get_post_meta( $post->ID, '_edit_lock', true );
   1614 	if ( ! $lock ) {
   1615 		return false;
   1616 	}
   1617 
   1618 	$lock = explode( ':', $lock );
   1619 	$time = $lock[0];
   1620 	$user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
   1621 
   1622 	if ( ! get_userdata( $user ) ) {
   1623 		return false;
   1624 	}
   1625 
   1626 	/** This filter is documented in wp-admin/includes/ajax-actions.php */
   1627 	$time_window = apply_filters( 'wp_check_post_lock_window', 150 );
   1628 
   1629 	if ( $time && $time > time() - $time_window && get_current_user_id() != $user ) {
   1630 		return $user;
   1631 	}
   1632 
   1633 	return false;
   1634 }
   1635 
   1636 /**
   1637  * Mark the post as currently being edited by the current user
   1638  *
   1639  * @since 2.5.0
   1640  *
   1641  * @param int|WP_Post $post_id ID or object of the post being edited.
   1642  * @return array|false Array of the lock time and user ID. False if the post does not exist, or
   1643  *                     there is no current user.
   1644  */
   1645 function wp_set_post_lock( $post_id ) {
   1646 	$post = get_post( $post_id );
   1647 	if ( ! $post ) {
   1648 		return false;
   1649 	}
   1650 
   1651 	$user_id = get_current_user_id();
   1652 	if ( 0 == $user_id ) {
   1653 		return false;
   1654 	}
   1655 
   1656 	$now  = time();
   1657 	$lock = "$now:$user_id";
   1658 
   1659 	update_post_meta( $post->ID, '_edit_lock', $lock );
   1660 
   1661 	return array( $now, $user_id );
   1662 }
   1663 
   1664 /**
   1665  * Outputs the HTML for the notice to say that someone else is editing or has taken over editing of this post.
   1666  *
   1667  * @since 2.8.5
   1668  */
   1669 function _admin_notice_post_locked() {
   1670 	$post = get_post();
   1671 	if ( ! $post ) {
   1672 		return;
   1673 	}
   1674 
   1675 	$user    = null;
   1676 	$user_id = wp_check_post_lock( $post->ID );
   1677 	if ( $user_id ) {
   1678 		$user = get_userdata( $user_id );
   1679 	}
   1680 
   1681 	if ( $user ) {
   1682 		/**
   1683 		 * Filters whether to show the post locked dialog.
   1684 		 *
   1685 		 * Returning false from the filter will prevent the dialog from being displayed.
   1686 		 *
   1687 		 * @since 3.6.0
   1688 		 *
   1689 		 * @param bool    $display Whether to display the dialog. Default true.
   1690 		 * @param WP_Post $post    Post object.
   1691 		 * @param WP_User $user    The user with the lock for the post.
   1692 		 */
   1693 		if ( ! apply_filters( 'show_post_locked_dialog', true, $post, $user ) ) {
   1694 			return;
   1695 		}
   1696 
   1697 		$locked = true;
   1698 	} else {
   1699 		$locked = false;
   1700 	}
   1701 
   1702 	$sendback = wp_get_referer();
   1703 	if ( $locked && $sendback && false === strpos( $sendback, 'post.php' ) && false === strpos( $sendback, 'post-new.php' ) ) {
   1704 
   1705 		$sendback_text = __( 'Go back' );
   1706 	} else {
   1707 		$sendback = admin_url( 'edit.php' );
   1708 
   1709 		if ( 'post' !== $post->post_type ) {
   1710 			$sendback = add_query_arg( 'post_type', $post->post_type, $sendback );
   1711 		}
   1712 
   1713 		$sendback_text = get_post_type_object( $post->post_type )->labels->all_items;
   1714 	}
   1715 
   1716 	$hidden = $locked ? '' : ' hidden';
   1717 
   1718 	?>
   1719 	<div id="post-lock-dialog" class="notification-dialog-wrap<?php echo $hidden; ?>">
   1720 	<div class="notification-dialog-background"></div>
   1721 	<div class="notification-dialog">
   1722 	<?php
   1723 
   1724 	if ( $locked ) {
   1725 		$query_args = array();
   1726 		if ( get_post_type_object( $post->post_type )->public ) {
   1727 			if ( 'publish' === $post->post_status || $user->ID != $post->post_author ) {
   1728 				// Latest content is in autosave.
   1729 				$nonce                       = wp_create_nonce( 'post_preview_' . $post->ID );
   1730 				$query_args['preview_id']    = $post->ID;
   1731 				$query_args['preview_nonce'] = $nonce;
   1732 			}
   1733 		}
   1734 
   1735 		$preview_link = get_preview_post_link( $post->ID, $query_args );
   1736 
   1737 		/**
   1738 		 * Filters whether to allow the post lock to be overridden.
   1739 		 *
   1740 		 * Returning false from the filter will disable the ability
   1741 		 * to override the post lock.
   1742 		 *
   1743 		 * @since 3.6.0
   1744 		 *
   1745 		 * @param bool    $override Whether to allow the post lock to be overridden. Default true.
   1746 		 * @param WP_Post $post     Post object.
   1747 		 * @param WP_User $user     The user with the lock for the post.
   1748 		 */
   1749 		$override = apply_filters( 'override_post_lock', true, $post, $user );
   1750 		$tab_last = $override ? '' : ' wp-tab-last';
   1751 
   1752 		?>
   1753 		<div class="post-locked-message">
   1754 		<div class="post-locked-avatar"><?php echo get_avatar( $user->ID, 64 ); ?></div>
   1755 		<p class="currently-editing wp-tab-first" tabindex="0">
   1756 		<?php
   1757 		if ( $override ) {
   1758 			/* translators: %s: User's display name. */
   1759 			printf( __( '%s is currently editing this post. Do you want to take over?' ), esc_html( $user->display_name ) );
   1760 		} else {
   1761 			/* translators: %s: User's display name. */
   1762 			printf( __( '%s is currently editing this post.' ), esc_html( $user->display_name ) );
   1763 		}
   1764 		?>
   1765 		</p>
   1766 		<?php
   1767 		/**
   1768 		 * Fires inside the post locked dialog before the buttons are displayed.
   1769 		 *
   1770 		 * @since 3.6.0
   1771 		 * @since 5.4.0 The $user parameter was added.
   1772 		 *
   1773 		 * @param WP_Post $post Post object.
   1774 		 * @param WP_User $user The user with the lock for the post.
   1775 		 */
   1776 		do_action( 'post_locked_dialog', $post, $user );
   1777 		?>
   1778 		<p>
   1779 		<a class="button" href="<?php echo esc_url( $sendback ); ?>"><?php echo $sendback_text; ?></a>
   1780 		<?php if ( $preview_link ) { ?>
   1781 		<a class="button<?php echo $tab_last; ?>" href="<?php echo esc_url( $preview_link ); ?>"><?php _e( 'Preview' ); ?></a>
   1782 			<?php
   1783 		}
   1784 
   1785 		// Allow plugins to prevent some users overriding the post lock.
   1786 		if ( $override ) {
   1787 			?>
   1788 	<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>
   1789 			<?php
   1790 		}
   1791 
   1792 		?>
   1793 		</p>
   1794 		</div>
   1795 		<?php
   1796 	} else {
   1797 		?>
   1798 		<div class="post-taken-over">
   1799 			<div class="post-locked-avatar"></div>
   1800 			<p class="wp-tab-first" tabindex="0">
   1801 			<span class="currently-editing"></span><br />
   1802 			<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&hellip;' ); ?></span>
   1803 			<span class="locked-saved hidden"><?php _e( 'Your latest changes were saved as a revision.' ); ?></span>
   1804 			</p>
   1805 			<?php
   1806 			/**
   1807 			 * Fires inside the dialog displayed when a user has lost the post lock.
   1808 			 *
   1809 			 * @since 3.6.0
   1810 			 *
   1811 			 * @param WP_Post $post Post object.
   1812 			 */
   1813 			do_action( 'post_lock_lost_dialog', $post );
   1814 			?>
   1815 			<p><a class="button button-primary wp-tab-last" href="<?php echo esc_url( $sendback ); ?>"><?php echo $sendback_text; ?></a></p>
   1816 		</div>
   1817 		<?php
   1818 	}
   1819 
   1820 	?>
   1821 	</div>
   1822 	</div>
   1823 	<?php
   1824 }
   1825 
   1826 /**
   1827  * Creates autosave data for the specified post from $_POST data.
   1828  *
   1829  * @since 2.6.0
   1830  *
   1831  * @param array|int $post_data Associative array containing the post data or int post ID.
   1832  * @return int|WP_Error The autosave revision ID. WP_Error or 0 on error.
   1833  */
   1834 function wp_create_post_autosave( $post_data ) {
   1835 	if ( is_numeric( $post_data ) ) {
   1836 		$post_id   = $post_data;
   1837 		$post_data = $_POST;
   1838 	} else {
   1839 		$post_id = (int) $post_data['post_ID'];
   1840 	}
   1841 
   1842 	$post_data = _wp_translate_postdata( true, $post_data );
   1843 	if ( is_wp_error( $post_data ) ) {
   1844 		return $post_data;
   1845 	}
   1846 	$post_data = _wp_get_allowed_postdata( $post_data );
   1847 
   1848 	$post_author = get_current_user_id();
   1849 
   1850 	// Store one autosave per author. If there is already an autosave, overwrite it.
   1851 	$old_autosave = wp_get_post_autosave( $post_id, $post_author );
   1852 	if ( $old_autosave ) {
   1853 		$new_autosave                = _wp_post_revision_data( $post_data, true );
   1854 		$new_autosave['ID']          = $old_autosave->ID;
   1855 		$new_autosave['post_author'] = $post_author;
   1856 
   1857 		$post = get_post( $post_id );
   1858 
   1859 		// If the new autosave has the same content as the post, delete the autosave.
   1860 		$autosave_is_different = false;
   1861 		foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) {
   1862 			if ( normalize_whitespace( $new_autosave[ $field ] ) !== normalize_whitespace( $post->$field ) ) {
   1863 				$autosave_is_different = true;
   1864 				break;
   1865 			}
   1866 		}
   1867 
   1868 		if ( ! $autosave_is_different ) {
   1869 			wp_delete_post_revision( $old_autosave->ID );
   1870 			return 0;
   1871 		}
   1872 
   1873 		/**
   1874 		 * Fires before an autosave is stored.
   1875 		 *
   1876 		 * @since 4.1.0
   1877 		 *
   1878 		 * @param array $new_autosave Post array - the autosave that is about to be saved.
   1879 		 */
   1880 		do_action( 'wp_creating_autosave', $new_autosave );
   1881 
   1882 		return wp_update_post( $new_autosave );
   1883 	}
   1884 
   1885 	// _wp_put_post_revision() expects unescaped.
   1886 	$post_data = wp_unslash( $post_data );
   1887 
   1888 	// Otherwise create the new autosave as a special post revision.
   1889 	return _wp_put_post_revision( $post_data, true );
   1890 }
   1891 
   1892 /**
   1893  * Saves a draft or manually autosaves for the purpose of showing a post preview.
   1894  *
   1895  * @since 2.7.0
   1896  *
   1897  * @return string URL to redirect to show the preview.
   1898  */
   1899 function post_preview() {
   1900 
   1901 	$post_ID     = (int) $_POST['post_ID'];
   1902 	$_POST['ID'] = $post_ID;
   1903 
   1904 	$post = get_post( $post_ID );
   1905 	if ( ! $post ) {
   1906 		wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
   1907 	}
   1908 
   1909 	if ( ! current_user_can( 'edit_post', $post->ID ) ) {
   1910 		wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
   1911 	}
   1912 
   1913 	$is_autosave = false;
   1914 
   1915 	if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author
   1916 		&& ( 'draft' === $post->post_status || 'auto-draft' === $post->post_status )
   1917 	) {
   1918 		$saved_post_id = edit_post();
   1919 	} else {
   1920 		$is_autosave = true;
   1921 
   1922 		if ( isset( $_POST['post_status'] ) && 'auto-draft' === $_POST['post_status'] ) {
   1923 			$_POST['post_status'] = 'draft';
   1924 		}
   1925 
   1926 		$saved_post_id = wp_create_post_autosave( $post->ID );
   1927 	}
   1928 
   1929 	if ( is_wp_error( $saved_post_id ) ) {
   1930 		wp_die( $saved_post_id->get_error_message() );
   1931 	}
   1932 
   1933 	$query_args = array();
   1934 
   1935 	if ( $is_autosave && $saved_post_id ) {
   1936 		$query_args['preview_id']    = $post->ID;
   1937 		$query_args['preview_nonce'] = wp_create_nonce( 'post_preview_' . $post->ID );
   1938 
   1939 		if ( isset( $_POST['post_format'] ) ) {
   1940 			$query_args['post_format'] = empty( $_POST['post_format'] ) ? 'standard' : sanitize_key( $_POST['post_format'] );
   1941 		}
   1942 
   1943 		if ( isset( $_POST['_thumbnail_id'] ) ) {
   1944 			$query_args['_thumbnail_id'] = ( (int) $_POST['_thumbnail_id'] <= 0 ) ? '-1' : (int) $_POST['_thumbnail_id'];
   1945 		}
   1946 	}
   1947 
   1948 	return get_preview_post_link( $post, $query_args );
   1949 }
   1950 
   1951 /**
   1952  * Save a post submitted with XHR
   1953  *
   1954  * Intended for use with heartbeat and autosave.js
   1955  *
   1956  * @since 3.9.0
   1957  *
   1958  * @param array $post_data Associative array of the submitted post data.
   1959  * @return mixed The value 0 or WP_Error on failure. The saved post ID on success.
   1960  *               The ID can be the draft post_id or the autosave revision post_id.
   1961  */
   1962 function wp_autosave( $post_data ) {
   1963 	// Back-compat.
   1964 	if ( ! defined( 'DOING_AUTOSAVE' ) ) {
   1965 		define( 'DOING_AUTOSAVE', true );
   1966 	}
   1967 
   1968 	$post_id              = (int) $post_data['post_id'];
   1969 	$post_data['ID']      = $post_id;
   1970 	$post_data['post_ID'] = $post_id;
   1971 
   1972 	if ( false === wp_verify_nonce( $post_data['_wpnonce'], 'update-post_' . $post_id ) ) {
   1973 		return new WP_Error( 'invalid_nonce', __( 'Error while saving.' ) );
   1974 	}
   1975 
   1976 	$post = get_post( $post_id );
   1977 
   1978 	if ( ! current_user_can( 'edit_post', $post->ID ) ) {
   1979 		return new WP_Error( 'edit_posts', __( 'Sorry, you are not allowed to edit this item.' ) );
   1980 	}
   1981 
   1982 	if ( 'auto-draft' === $post->post_status ) {
   1983 		$post_data['post_status'] = 'draft';
   1984 	}
   1985 
   1986 	if ( 'page' !== $post_data['post_type'] && ! empty( $post_data['catslist'] ) ) {
   1987 		$post_data['post_category'] = explode( ',', $post_data['catslist'] );
   1988 	}
   1989 
   1990 	if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author
   1991 		&& ( 'auto-draft' === $post->post_status || 'draft' === $post->post_status )
   1992 	) {
   1993 		// Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked.
   1994 		return edit_post( wp_slash( $post_data ) );
   1995 	} else {
   1996 		// Non-drafts or other users' drafts are not overwritten.
   1997 		// The autosave is stored in a special post revision for each user.
   1998 		return wp_create_post_autosave( wp_slash( $post_data ) );
   1999 	}
   2000 }
   2001 
   2002 /**
   2003  * Redirect to previous page.
   2004  *
   2005  * @since 2.7.0
   2006  *
   2007  * @param int $post_id Optional. Post ID.
   2008  */
   2009 function redirect_post( $post_id = '' ) {
   2010 	if ( isset( $_POST['save'] ) || isset( $_POST['publish'] ) ) {
   2011 		$status = get_post_status( $post_id );
   2012 
   2013 		if ( isset( $_POST['publish'] ) ) {
   2014 			switch ( $status ) {
   2015 				case 'pending':
   2016 					$message = 8;
   2017 					break;
   2018 				case 'future':
   2019 					$message = 9;
   2020 					break;
   2021 				default:
   2022 					$message = 6;
   2023 			}
   2024 		} else {
   2025 			$message = 'draft' === $status ? 10 : 1;
   2026 		}
   2027 
   2028 		$location = add_query_arg( 'message', $message, get_edit_post_link( $post_id, 'url' ) );
   2029 	} elseif ( isset( $_POST['addmeta'] ) && $_POST['addmeta'] ) {
   2030 		$location = add_query_arg( 'message', 2, wp_get_referer() );
   2031 		$location = explode( '#', $location );
   2032 		$location = $location[0] . '#postcustom';
   2033 	} elseif ( isset( $_POST['deletemeta'] ) && $_POST['deletemeta'] ) {
   2034 		$location = add_query_arg( 'message', 3, wp_get_referer() );
   2035 		$location = explode( '#', $location );
   2036 		$location = $location[0] . '#postcustom';
   2037 	} else {
   2038 		$location = add_query_arg( 'message', 4, get_edit_post_link( $post_id, 'url' ) );
   2039 	}
   2040 
   2041 	/**
   2042 	 * Filters the post redirect destination URL.
   2043 	 *
   2044 	 * @since 2.9.0
   2045 	 *
   2046 	 * @param string $location The destination URL.
   2047 	 * @param int    $post_id  The post ID.
   2048 	 */
   2049 	wp_redirect( apply_filters( 'redirect_post_location', $location, $post_id ) );
   2050 	exit;
   2051 }
   2052 
   2053 /**
   2054  * Sanitizes POST values from a checkbox taxonomy metabox.
   2055  *
   2056  * @since 5.1.0
   2057  *
   2058  * @param string $taxonomy The taxonomy name.
   2059  * @param array  $terms    Raw term data from the 'tax_input' field.
   2060  * @return int[] Array of sanitized term IDs.
   2061  */
   2062 function taxonomy_meta_box_sanitize_cb_checkboxes( $taxonomy, $terms ) {
   2063 	return array_map( 'intval', $terms );
   2064 }
   2065 
   2066 /**
   2067  * Sanitizes POST values from an input taxonomy metabox.
   2068  *
   2069  * @since 5.1.0
   2070  *
   2071  * @param string       $taxonomy The taxonomy name.
   2072  * @param array|string $terms    Raw term data from the 'tax_input' field.
   2073  * @return array
   2074  */
   2075 function taxonomy_meta_box_sanitize_cb_input( $taxonomy, $terms ) {
   2076 	/*
   2077 	 * Assume that a 'tax_input' string is a comma-separated list of term names.
   2078 	 * Some languages may use a character other than a comma as a delimiter, so we standardize on
   2079 	 * commas before parsing the list.
   2080 	 */
   2081 	if ( ! is_array( $terms ) ) {
   2082 		$comma = _x( ',', 'tag delimiter' );
   2083 		if ( ',' !== $comma ) {
   2084 			$terms = str_replace( $comma, ',', $terms );
   2085 		}
   2086 		$terms = explode( ',', trim( $terms, " \n\t\r\0\x0B," ) );
   2087 	}
   2088 
   2089 	$clean_terms = array();
   2090 	foreach ( $terms as $term ) {
   2091 		// Empty terms are invalid input.
   2092 		if ( empty( $term ) ) {
   2093 			continue;
   2094 		}
   2095 
   2096 		$_term = get_terms(
   2097 			array(
   2098 				'taxonomy'   => $taxonomy,
   2099 				'name'       => $term,
   2100 				'fields'     => 'ids',
   2101 				'hide_empty' => false,
   2102 			)
   2103 		);
   2104 
   2105 		if ( ! empty( $_term ) ) {
   2106 			$clean_terms[] = (int) $_term[0];
   2107 		} else {
   2108 			// No existing term was found, so pass the string. A new term will be created.
   2109 			$clean_terms[] = $term;
   2110 		}
   2111 	}
   2112 
   2113 	return $clean_terms;
   2114 }
   2115 
   2116 /**
   2117  * Return whether the post can be edited in the block editor.
   2118  *
   2119  * @since 5.0.0
   2120  *
   2121  * @param int|WP_Post $post Post ID or WP_Post object.
   2122  * @return bool Whether the post can be edited in the block editor.
   2123  */
   2124 function use_block_editor_for_post( $post ) {
   2125 	$post = get_post( $post );
   2126 
   2127 	if ( ! $post ) {
   2128 		return false;
   2129 	}
   2130 
   2131 	// We're in the meta box loader, so don't use the block editor.
   2132 	if ( isset( $_GET['meta-box-loader'] ) ) {
   2133 		check_admin_referer( 'meta-box-loader', 'meta-box-loader-nonce' );
   2134 		return false;
   2135 	}
   2136 
   2137 	$use_block_editor = use_block_editor_for_post_type( $post->post_type );
   2138 
   2139 	/**
   2140 	 * Filters whether a post is able to be edited in the block editor.
   2141 	 *
   2142 	 * @since 5.0.0
   2143 	 *
   2144 	 * @param bool    $use_block_editor Whether the post can be edited or not.
   2145 	 * @param WP_Post $post             The post being checked.
   2146 	 */
   2147 	return apply_filters( 'use_block_editor_for_post', $use_block_editor, $post );
   2148 }
   2149 
   2150 /**
   2151  * Return whether a post type is compatible with the block editor.
   2152  *
   2153  * The block editor depends on the REST API, and if the post type is not shown in the
   2154  * REST API, then it won't work with the block editor.
   2155  *
   2156  * @since 5.0.0
   2157  *
   2158  * @param string $post_type The post type.
   2159  * @return bool Whether the post type can be edited with the block editor.
   2160  */
   2161 function use_block_editor_for_post_type( $post_type ) {
   2162 	if ( ! post_type_exists( $post_type ) ) {
   2163 		return false;
   2164 	}
   2165 
   2166 	if ( ! post_type_supports( $post_type, 'editor' ) ) {
   2167 		return false;
   2168 	}
   2169 
   2170 	$post_type_object = get_post_type_object( $post_type );
   2171 	if ( $post_type_object && ! $post_type_object->show_in_rest ) {
   2172 		return false;
   2173 	}
   2174 
   2175 	/**
   2176 	 * Filters whether a post is able to be edited in the block editor.
   2177 	 *
   2178 	 * @since 5.0.0
   2179 	 *
   2180 	 * @param bool   $use_block_editor  Whether the post type can be edited or not. Default true.
   2181 	 * @param string $post_type         The post type being checked.
   2182 	 */
   2183 	return apply_filters( 'use_block_editor_for_post_type', true, $post_type );
   2184 }
   2185 
   2186 /**
   2187  * Prepares server-registered blocks for the block editor.
   2188  *
   2189  * Returns an associative array of registered block data keyed by block name. Data includes properties
   2190  * of a block relevant for client registration.
   2191  *
   2192  * @since 5.0.0
   2193  *
   2194  * @return array An associative array of registered block data.
   2195  */
   2196 function get_block_editor_server_block_settings() {
   2197 	$block_registry = WP_Block_Type_Registry::get_instance();
   2198 	$blocks         = array();
   2199 	$fields_to_pick = array(
   2200 		'api_version'      => 'apiVersion',
   2201 		'title'            => 'title',
   2202 		'description'      => 'description',
   2203 		'icon'             => 'icon',
   2204 		'attributes'       => 'attributes',
   2205 		'provides_context' => 'providesContext',
   2206 		'uses_context'     => 'usesContext',
   2207 		'supports'         => 'supports',
   2208 		'category'         => 'category',
   2209 		'styles'           => 'styles',
   2210 		'textdomain'       => 'textdomain',
   2211 		'parent'           => 'parent',
   2212 		'keywords'         => 'keywords',
   2213 		'example'          => 'example',
   2214 		'variations'       => 'variations',
   2215 	);
   2216 
   2217 	foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
   2218 		foreach ( $fields_to_pick as $field => $key ) {
   2219 			if ( ! isset( $block_type->{ $field } ) ) {
   2220 				continue;
   2221 			}
   2222 
   2223 			if ( ! isset( $blocks[ $block_name ] ) ) {
   2224 				$blocks[ $block_name ] = array();
   2225 			}
   2226 
   2227 			$blocks[ $block_name ][ $key ] = $block_type->{ $field };
   2228 		}
   2229 	}
   2230 
   2231 	return $blocks;
   2232 }
   2233 
   2234 /**
   2235  * Renders the meta boxes forms.
   2236  *
   2237  * @since 5.0.0
   2238  */
   2239 function the_block_editor_meta_boxes() {
   2240 	global $post, $current_screen, $wp_meta_boxes;
   2241 
   2242 	// Handle meta box state.
   2243 	$_original_meta_boxes = $wp_meta_boxes;
   2244 
   2245 	/**
   2246 	 * Fires right before the meta boxes are rendered.
   2247 	 *
   2248 	 * This allows for the filtering of meta box data, that should already be
   2249 	 * present by this point. Do not use as a means of adding meta box data.
   2250 	 *
   2251 	 * @since 5.0.0
   2252 	 *
   2253 	 * @param array $wp_meta_boxes Global meta box state.
   2254 	 */
   2255 	$wp_meta_boxes = apply_filters( 'filter_block_editor_meta_boxes', $wp_meta_boxes );
   2256 	$locations     = array( 'side', 'normal', 'advanced' );
   2257 	$priorities    = array( 'high', 'sorted', 'core', 'default', 'low' );
   2258 
   2259 	// Render meta boxes.
   2260 	?>
   2261 	<form class="metabox-base-form">
   2262 	<?php the_block_editor_meta_box_post_form_hidden_fields( $post ); ?>
   2263 	</form>
   2264 	<form id="toggle-custom-fields-form" method="post" action="<?php echo esc_url( admin_url( 'post.php' ) ); ?>">
   2265 		<?php wp_nonce_field( 'toggle-custom-fields', 'toggle-custom-fields-nonce' ); ?>
   2266 		<input type="hidden" name="action" value="toggle-custom-fields" />
   2267 	</form>
   2268 	<?php foreach ( $locations as $location ) : ?>
   2269 		<form class="metabox-location-<?php echo esc_attr( $location ); ?>" onsubmit="return false;">
   2270 			<div id="poststuff" class="sidebar-open">
   2271 				<div id="postbox-container-2" class="postbox-container">
   2272 					<?php
   2273 					do_meta_boxes(
   2274 						$current_screen,
   2275 						$location,
   2276 						$post
   2277 					);
   2278 					?>
   2279 				</div>
   2280 			</div>
   2281 		</form>
   2282 	<?php endforeach; ?>
   2283 	<?php
   2284 
   2285 	$meta_boxes_per_location = array();
   2286 	foreach ( $locations as $location ) {
   2287 		$meta_boxes_per_location[ $location ] = array();
   2288 
   2289 		if ( ! isset( $wp_meta_boxes[ $current_screen->id ][ $location ] ) ) {
   2290 			continue;
   2291 		}
   2292 
   2293 		foreach ( $priorities as $priority ) {
   2294 			if ( ! isset( $wp_meta_boxes[ $current_screen->id ][ $location ][ $priority ] ) ) {
   2295 				continue;
   2296 			}
   2297 
   2298 			$meta_boxes = (array) $wp_meta_boxes[ $current_screen->id ][ $location ][ $priority ];
   2299 			foreach ( $meta_boxes as $meta_box ) {
   2300 				if ( false == $meta_box || ! $meta_box['title'] ) {
   2301 					continue;
   2302 				}
   2303 
   2304 				// If a meta box is just here for back compat, don't show it in the block editor.
   2305 				if ( isset( $meta_box['args']['__back_compat_meta_box'] ) && $meta_box['args']['__back_compat_meta_box'] ) {
   2306 					continue;
   2307 				}
   2308 
   2309 				$meta_boxes_per_location[ $location ][] = array(
   2310 					'id'    => $meta_box['id'],
   2311 					'title' => $meta_box['title'],
   2312 				);
   2313 			}
   2314 		}
   2315 	}
   2316 
   2317 	/**
   2318 	 * Sadly we probably can not add this data directly into editor settings.
   2319 	 *
   2320 	 * Some meta boxes need admin_head to fire for meta box registry.
   2321 	 * admin_head fires after admin_enqueue_scripts, which is where we create our
   2322 	 * editor instance.
   2323 	 */
   2324 	$script = 'window._wpLoadBlockEditor.then( function() {
   2325 		wp.data.dispatch( \'core/edit-post\' ).setAvailableMetaBoxesPerLocation( ' . wp_json_encode( $meta_boxes_per_location ) . ' );
   2326 	} );';
   2327 
   2328 	wp_add_inline_script( 'wp-edit-post', $script );
   2329 
   2330 	/**
   2331 	 * When `wp-edit-post` is output in the `<head>`, the inline script needs to be manually printed. Otherwise,
   2332 	 * meta boxes will not display because inline scripts for `wp-edit-post` will not be printed again after this point.
   2333 	 */
   2334 	if ( wp_script_is( 'wp-edit-post', 'done' ) ) {
   2335 		printf( "<script type='text/javascript'>\n%s\n</script>\n", trim( $script ) );
   2336 	}
   2337 
   2338 	/**
   2339 	 * If the 'postcustom' meta box is enabled, then we need to perform some
   2340 	 * extra initialization on it.
   2341 	 */
   2342 	$enable_custom_fields = (bool) get_user_meta( get_current_user_id(), 'enable_custom_fields', true );
   2343 	if ( $enable_custom_fields ) {
   2344 		$script = "( function( $ ) {
   2345 			if ( $('#postcustom').length ) {
   2346 				$( '#the-list' ).wpList( {
   2347 					addBefore: function( s ) {
   2348 						s.data += '&post_id=$post->ID';
   2349 						return s;
   2350 					},
   2351 					addAfter: function() {
   2352 						$('table#list-table').show();
   2353 					}
   2354 				});
   2355 			}
   2356 		} )( jQuery );";
   2357 		wp_enqueue_script( 'wp-lists' );
   2358 		wp_add_inline_script( 'wp-lists', $script );
   2359 	}
   2360 
   2361 	// Reset meta box data.
   2362 	$wp_meta_boxes = $_original_meta_boxes;
   2363 }
   2364 
   2365 /**
   2366  * Renders the hidden form required for the meta boxes form.
   2367  *
   2368  * @since 5.0.0
   2369  *
   2370  * @param WP_Post $post Current post object.
   2371  */
   2372 function the_block_editor_meta_box_post_form_hidden_fields( $post ) {
   2373 	$form_extra = '';
   2374 	if ( 'auto-draft' === $post->post_status ) {
   2375 		$form_extra .= "<input type='hidden' id='auto_draft' name='auto_draft' value='1' />";
   2376 	}
   2377 	$form_action  = 'editpost';
   2378 	$nonce_action = 'update-post_' . $post->ID;
   2379 	$form_extra  .= "<input type='hidden' id='post_ID' name='post_ID' value='" . esc_attr( $post->ID ) . "' />";
   2380 	$referer      = wp_get_referer();
   2381 	$current_user = wp_get_current_user();
   2382 	$user_id      = $current_user->ID;
   2383 	wp_nonce_field( $nonce_action );
   2384 
   2385 	/*
   2386 	 * Some meta boxes hook into these actions to add hidden input fields in the classic post form. For backwards
   2387 	 * compatibility, we can capture the output from these actions, and extract the hidden input fields.
   2388 	 */
   2389 	ob_start();
   2390 	/** This filter is documented in wp-admin/edit-form-advanced.php */
   2391 	do_action( 'edit_form_after_title', $post );
   2392 	/** This filter is documented in wp-admin/edit-form-advanced.php */
   2393 	do_action( 'edit_form_advanced', $post );
   2394 	$classic_output = ob_get_clean();
   2395 
   2396 	$classic_elements = wp_html_split( $classic_output );
   2397 	$hidden_inputs    = '';
   2398 	foreach ( $classic_elements as $element ) {
   2399 		if ( 0 !== strpos( $element, '<input ' ) ) {
   2400 			continue;
   2401 		}
   2402 
   2403 		if ( preg_match( '/\stype=[\'"]hidden[\'"]\s/', $element ) ) {
   2404 			echo $element;
   2405 		}
   2406 	}
   2407 	?>
   2408 	<input type="hidden" id="user-id" name="user_ID" value="<?php echo (int) $user_id; ?>" />
   2409 	<input type="hidden" id="hiddenaction" name="action" value="<?php echo esc_attr( $form_action ); ?>" />
   2410 	<input type="hidden" id="originalaction" name="originalaction" value="<?php echo esc_attr( $form_action ); ?>" />
   2411 	<input type="hidden" id="post_type" name="post_type" value="<?php echo esc_attr( $post->post_type ); ?>" />
   2412 	<input type="hidden" id="original_post_status" name="original_post_status" value="<?php echo esc_attr( $post->post_status ); ?>" />
   2413 	<input type="hidden" id="referredby" name="referredby" value="<?php echo $referer ? esc_url( $referer ) : ''; ?>" />
   2414 
   2415 	<?php
   2416 	if ( 'draft' !== get_post_status( $post ) ) {
   2417 		wp_original_referer_field( true, 'previous' );
   2418 	}
   2419 	echo $form_extra;
   2420 	wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
   2421 	wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
   2422 	// Permalink title nonce.
   2423 	wp_nonce_field( 'samplepermalink', 'samplepermalinknonce', false );
   2424 
   2425 	/**
   2426 	 * Add hidden input fields to the meta box save form.
   2427 	 *
   2428 	 * Hook into this action to print `<input type="hidden" ... />` fields, which will be POSTed back to
   2429 	 * the server when meta boxes are saved.
   2430 	 *
   2431 	 * @since 5.0.0
   2432 	 *
   2433 	 * @param WP_Post $post The post that is being edited.
   2434 	 */
   2435 	do_action( 'block_editor_meta_box_hidden_fields', $post );
   2436 }