: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$metakeyselect = isset( $_POST['metakeyselect'] ) ? wp_unslash( trim( $_POST['metakeyselect'] ) ) : '';
$metakeyinput = isset( $_POST['metakeyinput'] ) ? wp_unslash( trim( $_POST['metakeyinput'] ) ) : '';
$metavalue = isset( $_POST['metavalue'] ) ? $_POST['metavalue'] : '';
if ( is_string( $metavalue ) ) {
$metavalue = trim( $metavalue );
if ( ( ( '#NONE#' !== $metakeyselect ) && ! empty( $metakeyselect ) ) || ! empty( $metakeyinput ) ) {
* We have a key/value pair. If both the select and the input
* for the key have data, the input takes precedence.
if ( '#NONE#' !== $metakeyselect ) {
$metakey = $metakeyselect;
$metakey = $metakeyinput; // Default.
if ( is_protected_meta( $metakey, 'post' ) || ! current_user_can( 'add_post_meta', $post_id, $metakey ) ) {
$metakey = wp_slash( $metakey );
return add_post_meta( $post_id, $metakey, $metavalue );
* Deletes post meta data by meta ID.
function delete_meta( $mid ) {
return delete_metadata_by_mid( 'post', $mid );
* Returns a list of previously defined keys.
* @global wpdb $wpdb WordPress database abstraction object.
* @return string[] Array of meta key names.
function get_meta_keys() {
* Returns post meta data by meta ID.
function get_post_meta_by_id( $mid ) {
return get_metadata_by_mid( 'post', $mid );
* Returns meta data for the given post ID.
* @global wpdb $wpdb WordPress database abstraction object.
* @param int $post_id A post ID.
* Array of meta data arrays for the given post ID.
* Associative array of meta data.
* @type string $meta_key Meta key.
* @type mixed $meta_value Meta value.
* @type string $meta_id Meta ID as a numeric string.
* @type string $post_id Post ID as a numeric string.
function has_meta( $post_id ) {
return $wpdb->get_results(
"SELECT meta_key, meta_value, meta_id, post_id
FROM $wpdb->postmeta WHERE post_id = %d
ORDER BY meta_key,meta_id",
* Updates post meta data by meta ID.
* @param int $meta_id Meta ID.
* @param string $meta_key Meta key. Expect slashed.
* @param string $meta_value Meta value. Expect slashed.
function update_meta( $meta_id, $meta_key, $meta_value ) {
$meta_key = wp_unslash( $meta_key );
$meta_value = wp_unslash( $meta_value );
return update_metadata_by_mid( 'post', $meta_id, $meta_value, $meta_key );
* Replaces hrefs of attachment anchors with up-to-date permalinks.
* @param int|WP_Post $post Post ID or post object.
* @return void|int|WP_Error Void if nothing fixed. 0 or WP_Error on update failure. The post ID on update success.
function _fix_attachment_links( $post ) {
$post = get_post( $post, ARRAY_A );
$content = $post['post_content'];
// Don't run if no pretty permalinks or post is not published, scheduled, or privately published.
if ( ! get_option( 'permalink_structure' ) || ! in_array( $post['post_status'], array( 'publish', 'future', 'private' ), true ) ) {
// Short if there aren't any links or no '?attachment_id=' strings (strpos cannot be zero).
if ( ! strpos( $content, '?attachment_id=' ) || ! preg_match_all( '/<a ([^>]+)>[\s\S]+?<\/a>/', $content, $link_matches ) ) {
$site_url = get_bloginfo( 'url' );
$site_url = substr( $site_url, (int) strpos( $site_url, '://' ) ); // Remove the http(s).
foreach ( $link_matches[1] as $key => $value ) {
if ( ! strpos( $value, '?attachment_id=' ) || ! strpos( $value, 'wp-att-' )
|| ! preg_match( '/href=(["\'])[^"\']*\?attachment_id=(\d+)[^"\']*\\1/', $value, $url_match )
|| ! preg_match( '/rel=["\'][^"\']*wp-att-(\d+)/', $value, $rel_match ) ) {
$quote = $url_match[1]; // The quote (single or double).
$url_id = (int) $url_match[2];
$rel_id = (int) $rel_match[1];
if ( ! $url_id || ! $rel_id || $url_id != $rel_id || ! str_contains( $url_match[0], $site_url ) ) {
$link = $link_matches[0][ $key ];
$replace = str_replace( $url_match[0], 'href=' . $quote . get_attachment_link( $url_id ) . $quote, $link );
$content = str_replace( $link, $replace, $content );
$post['post_content'] = $content;
// Escape data pulled from DB.
$post = add_magic_quotes( $post );
return wp_update_post( $post );
* Returns all the possible statuses for a post type.
* @param string $type The post_type you want the statuses for. Default 'post'.
* @return string[] An array of all the statuses for the supplied post type.
function get_available_post_statuses( $type = 'post' ) {
$statuses = wp_count_posts( $type );
return array_keys( get_object_vars( $statuses ) );
* Runs the query to fetch the posts for listing on the edit posts page.
* @param array|false $q Optional. Array of query variables to use to build the query.
* Defaults to the `$_GET` superglobal.
function wp_edit_posts_query( $q = false ) {
$q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
$q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
$post_statuses = get_post_stati();
if ( isset( $q['post_type'] ) && in_array( $q['post_type'], get_post_types(), true ) ) {
$post_type = $q['post_type'];
$avail_post_stati = get_available_post_statuses( $post_type );
if ( isset( $q['post_status'] ) && in_array( $q['post_status'], $post_statuses, true ) ) {
$post_status = $q['post_status'];
if ( isset( $q['orderby'] ) ) {
$orderby = $q['orderby'];
} elseif ( isset( $q['post_status'] ) && in_array( $q['post_status'], array( 'pending', 'draft' ), true ) ) {
if ( isset( $q['order'] ) ) {
} elseif ( isset( $q['post_status'] ) && 'pending' === $q['post_status'] ) {
$per_page = "edit_{$post_type}_per_page";
$posts_per_page = (int) get_user_option( $per_page );
if ( empty( $posts_per_page ) || $posts_per_page < 1 ) {
* Filters the number of items per page to show for a specific 'per_page' type.
* The dynamic portion of the hook name, `$post_type`, refers to the post type.
* Possible hook names include:
* - `edit_attachment_per_page`
* @param int $posts_per_page Number of posts to display per page for the given post
$posts_per_page = apply_filters( "edit_{$post_type}_per_page", $posts_per_page );
* Filters the number of posts displayed per page when specifically listing "posts".
* @param int $posts_per_page Number of posts to be displayed. Default 20.
* @param string $post_type The post type.
$posts_per_page = apply_filters( 'edit_posts_per_page', $posts_per_page, $post_type );
$query = compact( 'post_type', 'post_status', 'perm', 'order', 'orderby', 'posts_per_page' );
// Hierarchical types require special args.
if ( is_post_type_hierarchical( $post_type ) && empty( $orderby ) ) {
$query['orderby'] = 'menu_order title';
$query['posts_per_page'] = -1;
$query['posts_per_archive_page'] = -1;
$query['fields'] = 'id=>parent';
if ( ! empty( $q['show_sticky'] ) ) {
$query['post__in'] = (array) get_option( 'sticky_posts' );
return $avail_post_stati;
* Returns the query variables for the current attachments request.
* @param array|false $q Optional. Array of query variables to use to build the query.
* Defaults to the `$_GET` superglobal.
* @return array The parsed query vars.
function wp_edit_attachments_query_vars( $q = false ) {
$q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
$q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
$q['post_type'] = 'attachment';
$post_type = get_post_type_object( 'attachment' );
if ( current_user_can( $post_type->cap->read_private_posts ) ) {
$q['post_status'] = isset( $q['status'] ) && 'trash' === $q['status'] ? 'trash' : $states;
$q['post_status'] = isset( $q['attachment-filter'] ) && 'trash' === $q['attachment-filter'] ? 'trash' : $states;
$media_per_page = (int) get_user_option( 'upload_per_page' );
if ( empty( $media_per_page ) || $media_per_page < 1 ) {
* Filters the number of items to list per page when listing media items.
* @param int $media_per_page Number of media to list. Default 20.
$q['posts_per_page'] = apply_filters( 'upload_per_page', $media_per_page );
$post_mime_types = get_post_mime_types();
if ( isset( $q['post_mime_type'] ) && ! array_intersect( (array) $q['post_mime_type'], array_keys( $post_mime_types ) ) ) {
unset( $q['post_mime_type'] );
foreach ( array_keys( $post_mime_types ) as $type ) {
if ( isset( $q['attachment-filter'] ) && "post_mime_type:$type" === $q['attachment-filter'] ) {
$q['post_mime_type'] = $type;
if ( isset( $q['detached'] ) || ( isset( $q['attachment-filter'] ) && 'detached' === $q['attachment-filter'] ) ) {
if ( isset( $q['mine'] ) || ( isset( $q['attachment-filter'] ) && 'mine' === $q['attachment-filter'] ) ) {
$q['author'] = get_current_user_id();
// Filter query clauses to include filenames.
if ( isset( $q['s'] ) ) {
add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
* Executes a query for attachments. An array of WP_Query arguments
* can be passed in, which will override the arguments set by this function.
* @param array|false $q Optional. Array of query variables to use to build the query.
* Defaults to the `$_GET` superglobal.
function wp_edit_attachments_query( $q = false ) {
wp( wp_edit_attachments_query_vars( $q ) );
$post_mime_types = get_post_mime_types();
$avail_post_mime_types = get_available_post_mime_types( 'attachment' );
return array( $post_mime_types, $avail_post_mime_types );
* Returns the list of classes to be used by a meta box.
* @param string $box_id Meta box ID (used in the 'id' attribute for the meta box).
* @param string $screen_id The screen on which the meta box is shown.
* @return string Space-separated string of class names.
function postbox_classes( $box_id, $screen_id ) {
if ( isset( $_GET['edit'] ) && $_GET['edit'] === $box_id ) {
} elseif ( get_user_option( 'closedpostboxes_' . $screen_id ) ) {
$closed = get_user_option( 'closedpostboxes_' . $screen_id );
if ( ! is_array( $closed ) ) {
$classes = in_array( $box_id, $closed, true ) ? array( 'closed' ) : array( '' );
* Filters the postbox classes for a specific screen and box ID combo.
* The dynamic portions of the hook name, `$screen_id` and `$box_id`, refer to
* the screen ID and meta box ID, respectively.
* @param string[] $classes An array of postbox classes.
$classes = apply_filters( "postbox_classes_{$screen_id}_{$box_id}", $classes );
return implode( ' ', $classes );
* Returns a sample permalink based on the post name.
* @param int|WP_Post $post Post ID or post object.
* @param string|null $title Optional. Title to override the post's current title
* when generating the post name. Default null.
* @param string|null $name Optional. Name to override the post name. Default null.
* Array containing the sample permalink with placeholder for the post name, and the post name.
* @type string $0 The permalink with placeholder for the post name.
* @type string $1 The post name.
function get_sample_permalink( $post, $title = null, $name = null ) {
$post = get_post( $post );
$ptype = get_post_type_object( $post->post_type );
$original_status = $post->post_status;
$original_date = $post->post_date;
$original_name = $post->post_name;
$original_filter = $post->filter;
// Hack: get_permalink() would return plain permalink for drafts, so we will fake that our post is published.
if ( in_array( $post->post_status, array( 'auto-draft', 'draft', 'pending', 'future' ), true ) ) {
$post->post_status = 'publish';
$post->post_name = sanitize_title( $post->post_name ? $post->post_name : $post->post_title, $post->ID );
* If the user wants to set a new name -- override the current one.
* Note: if empty name is supplied -- use the title instead, see #6072.
if ( ! is_null( $name ) ) {
$post->post_name = sanitize_title( $name ? $name : $title, $post->ID );
$post->post_name = wp_unique_post_slug( $post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent );
$post->filter = 'sample';
$permalink = get_permalink( $post, true );
// Replace custom post_type token with generic pagename token for ease of use.
$permalink = str_replace( "%$post->post_type%", '%pagename%', $permalink );
// Handle page hierarchy.
if ( $ptype->hierarchical ) {
$uri = get_page_uri( $post );
$uri = untrailingslashit( $uri );
$uri = strrev( stristr( strrev( $uri ), '/' ) );
$uri = untrailingslashit( $uri );
/** This filter is documented in wp-admin/edit-tag-form.php */
$uri = apply_filters( 'editable_slug', $uri, $post );