: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
// Disable autosave endpoints for global styles.
remove_post_type_support( 'wp_global_styles', 'autosave' );
$navigation_post_edit_link = 'site-editor.php?' . build_query(
'postType' => 'wp_navigation',
'name' => _x( 'Navigation Menus', 'post type general name' ),
'singular_name' => _x( 'Navigation Menu', 'post type singular name' ),
'add_new' => __( 'Add New Navigation Menu' ),
'add_new_item' => __( 'Add New Navigation Menu' ),
'new_item' => __( 'New Navigation Menu' ),
'edit_item' => __( 'Edit Navigation Menu' ),
'view_item' => __( 'View Navigation Menu' ),
'all_items' => __( 'Navigation Menus' ),
'search_items' => __( 'Search Navigation Menus' ),
'parent_item_colon' => __( 'Parent Navigation Menu:' ),
'not_found' => __( 'No Navigation Menu found.' ),
'not_found_in_trash' => __( 'No Navigation Menu found in Trash.' ),
'archives' => __( 'Navigation Menu archives' ),
'insert_into_item' => __( 'Insert into Navigation Menu' ),
'uploaded_to_this_item' => __( 'Uploaded to this Navigation Menu' ),
'filter_items_list' => __( 'Filter Navigation Menu list' ),
'items_list_navigation' => __( 'Navigation Menus list navigation' ),
'items_list' => __( 'Navigation Menus list' ),
'description' => __( 'Navigation menus that can be inserted into your site.' ),
'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
'_edit_link' => $navigation_post_edit_link, /* internal use only. don't use this when registering your own post type. */
'show_in_admin_bar' => false,
'edit_others_posts' => 'edit_theme_options',
'delete_posts' => 'edit_theme_options',
'publish_posts' => 'edit_theme_options',
'create_posts' => 'edit_theme_options',
'read_private_posts' => 'edit_theme_options',
'delete_private_posts' => 'edit_theme_options',
'delete_published_posts' => 'edit_theme_options',
'delete_others_posts' => 'edit_theme_options',
'edit_private_posts' => 'edit_theme_options',
'edit_published_posts' => 'edit_theme_options',
'edit_posts' => 'edit_theme_options',
'rest_base' => 'navigation',
'rest_controller_class' => 'WP_REST_Posts_Controller',
'name' => __( 'Font Families' ),
'singular_name' => __( 'Font Family' ),
'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
'read' => 'edit_theme_options',
'read_private_posts' => 'edit_theme_options',
'create_posts' => 'edit_theme_options',
'publish_posts' => 'edit_theme_options',
'edit_posts' => 'edit_theme_options',
'edit_others_posts' => 'edit_theme_options',
'edit_published_posts' => 'edit_theme_options',
'delete_posts' => 'edit_theme_options',
'delete_others_posts' => 'edit_theme_options',
'delete_published_posts' => 'edit_theme_options',
'rest_base' => 'font-families',
'rest_controller_class' => 'WP_REST_Font_Families_Controller',
'supports' => array( 'title' ),
'name' => __( 'Font Faces' ),
'singular_name' => __( 'Font Face' ),
'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
'read' => 'edit_theme_options',
'read_private_posts' => 'edit_theme_options',
'create_posts' => 'edit_theme_options',
'publish_posts' => 'edit_theme_options',
'edit_posts' => 'edit_theme_options',
'edit_others_posts' => 'edit_theme_options',
'edit_published_posts' => 'edit_theme_options',
'delete_posts' => 'edit_theme_options',
'delete_others_posts' => 'edit_theme_options',
'delete_published_posts' => 'edit_theme_options',
'rest_base' => 'font-families/(?P<font_family_id>[\d]+)/font-faces',
'rest_controller_class' => 'WP_REST_Font_Faces_Controller',
'supports' => array( 'title' ),
'label' => _x( 'Published', 'post status' ),
'_builtin' => true, /* internal use only. */
/* translators: %s: Number of published posts. */
'label_count' => _n_noop(
'Published <span class="count">(%s)</span>',
'Published <span class="count">(%s)</span>'
'label' => _x( 'Scheduled', 'post status' ),
'_builtin' => true, /* internal use only. */
/* translators: %s: Number of scheduled posts. */
'label_count' => _n_noop(
'Scheduled <span class="count">(%s)</span>',
'Scheduled <span class="count">(%s)</span>'
'label' => _x( 'Draft', 'post status' ),
'_builtin' => true, /* internal use only. */
/* translators: %s: Number of draft posts. */
'label_count' => _n_noop(
'Draft <span class="count">(%s)</span>',
'Drafts <span class="count">(%s)</span>'
'label' => _x( 'Pending', 'post status' ),
'_builtin' => true, /* internal use only. */
/* translators: %s: Number of pending posts. */
'label_count' => _n_noop(
'Pending <span class="count">(%s)</span>',
'Pending <span class="count">(%s)</span>'
'label' => _x( 'Private', 'post status' ),
'_builtin' => true, /* internal use only. */
/* translators: %s: Number of private posts. */
'label_count' => _n_noop(
'Private <span class="count">(%s)</span>',
'Private <span class="count">(%s)</span>'
'label' => _x( 'Trash', 'post status' ),
'_builtin' => true, /* internal use only. */
/* translators: %s: Number of trashed posts. */
'label_count' => _n_noop(
'Trash <span class="count">(%s)</span>',
'Trash <span class="count">(%s)</span>'
'show_in_admin_status_list' => true,
'_builtin' => true, /* internal use only. */
'_builtin' => true, /* internal use only. */
'exclude_from_search' => false,
'label' => _x( 'Pending', 'request status' ),
'_builtin' => true, /* internal use only. */
/* translators: %s: Number of pending requests. */
'label_count' => _n_noop(
'Pending <span class="count">(%s)</span>',
'Pending <span class="count">(%s)</span>'
'exclude_from_search' => false,
'label' => _x( 'Confirmed', 'request status' ),
'_builtin' => true, /* internal use only. */
/* translators: %s: Number of confirmed requests. */
'label_count' => _n_noop(
'Confirmed <span class="count">(%s)</span>',
'Confirmed <span class="count">(%s)</span>'
'exclude_from_search' => false,
'label' => _x( 'Failed', 'request status' ),
'_builtin' => true, /* internal use only. */
/* translators: %s: Number of failed requests. */
'label_count' => _n_noop(
'Failed <span class="count">(%s)</span>',
'Failed <span class="count">(%s)</span>'
'exclude_from_search' => false,
'label' => _x( 'Completed', 'request status' ),
'_builtin' => true, /* internal use only. */
/* translators: %s: Number of completed requests. */
'label_count' => _n_noop(
'Completed <span class="count">(%s)</span>',
'Completed <span class="count">(%s)</span>'
'exclude_from_search' => false,
* Retrieves attached file path based on attachment ID.
* By default the path will go through the {@see 'get_attached_file'} filter, but
* passing `true` to the `$unfiltered` argument will return the file path unfiltered.
* The function works by retrieving the `_wp_attached_file` post meta value.
* This is a convenience function to prevent looking up the meta name and provide
* a mechanism for sending the attached filename through a filter.
* @param int $attachment_id Attachment ID.
* @param bool $unfiltered Optional. Whether to skip the {@see 'get_attached_file'} filter.
* @return string|false The file path to where the attached file should be, false otherwise.
function get_attached_file( $attachment_id, $unfiltered = false ) {
$file = get_post_meta( $attachment_id, '_wp_attached_file', true );
// If the file is relative, prepend upload dir.
if ( $file && ! str_starts_with( $file, '/' ) && ! preg_match( '|^.:\\\|', $file ) ) {
$uploads = wp_get_upload_dir();
if ( false === $uploads['error'] ) {
$file = $uploads['basedir'] . "/$file";
* Filters the attached file based on the given ID.
* @param string|false $file The file path to where the attached file should be, false otherwise.
* @param int $attachment_id Attachment ID.
return apply_filters( 'get_attached_file', $file, $attachment_id );
* Updates attachment file path based on attachment ID.
* Used to update the file path of the attachment, which uses post meta name
* '_wp_attached_file' to store the path of the attachment.
* @param int $attachment_id Attachment ID.
* @param string $file File path for the attachment.
* @return bool True on success, false on failure.
function update_attached_file( $attachment_id, $file ) {
if ( ! get_post( $attachment_id ) ) {
* Filters the path to the attached file to update.
* @param string $file Path to the attached file to update.
* @param int $attachment_id Attachment ID.
$file = apply_filters( 'update_attached_file', $file, $attachment_id );
$file = _wp_relative_upload_path( $file );
return update_post_meta( $attachment_id, '_wp_attached_file', $file );
return delete_post_meta( $attachment_id, '_wp_attached_file' );
* Returns relative path to an uploaded file.
* The path is relative to the current upload dir.
* @param string $path Full path to the file.
* @return string Relative path on success, unchanged path on failure.
function _wp_relative_upload_path( $path ) {
$uploads = wp_get_upload_dir();
if ( str_starts_with( $new_path, $uploads['basedir'] ) ) {
$new_path = str_replace( $uploads['basedir'], '', $new_path );
$new_path = ltrim( $new_path, '/' );
* Filters the relative path to an uploaded file.
* @param string $new_path Relative path to the file.
* @param string $path Full path to the file.
return apply_filters( '_wp_relative_upload_path', $new_path, $path );
* Retrieves all children of the post parent ID.
* Normally, without any enhancements, the children would apply to pages. In the
* context of the inner workings of WordPress, pages, posts, and attachments
* share the same table, so therefore the functionality could apply to any one
* of them. It is then noted that while this function does not work on posts, it
* does not mean that it won't work on posts. It is recommended that you know
* what context you wish to retrieve the children of.
* Attachments may also be made the child of a post, so if that is an accurate
* statement (which needs to be verified), it would then be possible to get
* all of the attachments for a post. Attachments have since changed since
* version 2.5, so this is most likely inaccurate, but serves generally as an
* example of what is possible.
* The arguments listed as defaults are for this function and also of the
* get_posts() function. The arguments are combined with the get_children defaults
* and are then passed to the get_posts() function, which accepts additional arguments.
* You can replace the defaults in this function, listed below and the additional
* arguments listed in the get_posts() function.
* The 'post_parent' is the most important argument and important attention
* needs to be paid to the $args parameter. If you pass either an object or an
* integer (number), then just the 'post_parent' is grabbed and everything else
* is lost. If you don't specify any arguments, then it is assumed that you are
* in The Loop and the post parent will be grabbed for from the current post.
* The 'post_parent' argument is the ID to get the children. The 'numberposts'
* is the amount of posts to retrieve that has a default of '-1', which is
* used to get all of the posts. Giving a number higher than 0 will only
* retrieve that amount of posts.
* The 'post_type' and 'post_status' arguments can be used to choose what
* criteria of posts to retrieve. The 'post_type' can be anything, but WordPress
* post types are 'post', 'pages', and 'attachments'. The 'post_status'
* argument will accept any post status within the write administration panels.
* @todo Check validity of description.
* @global WP_Post $post Global post object.
* @param mixed $args Optional. User defined arguments for replacing the defaults. Default empty.
* @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
* correspond to a WP_Post object, an associative array, or a numeric array,
* respectively. Default OBJECT.
* @return WP_Post[]|array[]|int[] Array of post objects, arrays, or IDs, depending on `$output`.
function get_children( $args = '', $output = OBJECT ) {
if ( isset( $GLOBALS['post'] ) ) {
$args = array( 'post_parent' => (int) $GLOBALS['post']->post_parent );
} elseif ( is_object( $args ) ) {
$args = array( 'post_parent' => (int) $args->post_parent );
} elseif ( is_numeric( $args ) ) {
$args = array( 'post_parent' => (int) $args );
$parsed_args = wp_parse_args( $args, $defaults );
$children = get_posts( $parsed_args );
if ( ! empty( $parsed_args['fields'] ) ) {