$wp_query; if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '6.1.0' ); return false; } if ( 'pre_get_posts' === current_filter() ) { _doing_it_wrong( __FUNCTION__, sprintf( /* translators: 1: pre_get_posts, 2: WP_Query->is_main_query(), 3: is_main_query(), 4: Documentation URL. */ __( 'In %1$s, use the %2$s method, not the %3$s function. See %4$s.' ), 'pre_get_posts', 'WP_Query->is_main_query()', 'is_main_query()', __( 'https://developer.wordpress.org/reference/functions/is_main_query/' ) ), '3.7.0' ); } return $wp_query->is_main_query(); } /* * The Loop. Post loop control. */ /** * Determines whether current WordPress query has posts to loop over. * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool True if posts are available, false if end of the loop. */ function have_posts() { global $wp_query; if ( ! isset( $wp_query ) ) { return false; } return $wp_query->have_posts(); } /** * Determines whether the caller is in the Loop. * * For more information on this and similar theme functions, check out * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ * Conditional Tags} article in the Theme Developer Handbook. * * @since 2.0.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool True if caller is within loop, false if loop hasn't started or ended. */ function in_the_loop() { global $wp_query; if ( ! isset( $wp_query ) ) { return false; } return $wp_query->in_the_loop; } /** * Rewind the loop posts. * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. */ function rewind_posts() { global $wp_query; if ( ! isset( $wp_query ) ) { return; } $wp_query->rewind_posts(); } /** * Iterate the post index in the loop. * * @since 1.5.0 * * @global WP_Query $wp_query WordPress Query object. */ function the_post() { global $wp_query; if ( ! isset( $wp_query ) ) { return; } $wp_query->the_post(); } /* * Comments loop. */ /** * Determines whether current WordPress query has comments to loop over. * * @since 2.2.0 * * @global WP_Query $wp_query WordPress Query object. * * @return bool True if comments are available, false if no more comments. */ function have_comments() { global $wp_query; if ( ! isset( $wp_query ) ) { return false; } return $wp_query->have_comments(); } /** * Iterate comment index in the comment loop. * * @since 2.2.0 * * @global WP_Query $wp_query WordPress Query object. */ function the_comment() { global $wp_query; if ( ! isset( $wp_query ) ) { return; } $wp_query->the_comment(); } /** * Redirect old slugs to the correct permalink. * * Attempts to find the current slug from the past slugs. * * @since 2.1.0 */ function wp_old_slug_redirect() { if ( is_404() && '' !== get_query_var( 'name' ) ) { // Guess the current post type based on the query vars. if ( get_query_var( 'post_type' ) ) { $post_type = get_query_var( 'post_type' ); } elseif ( get_query_var( 'attachment' ) ) { $post_type = 'attachment'; } elseif ( get_query_var( 'pagename' ) ) { $post_type = 'page'; } else { $post_type = 'post'; } if ( is_array( $post_type ) ) { if ( count( $post_type ) > 1 ) { return; } $post_type = reset( $post_type ); } // Do not attempt redirect for hierarchical post types. if ( is_post_type_hierarchical( $post_type ) ) { return; } $id = _find_post_by_old_slug( $post_type ); if ( ! $id ) { $id = _find_post_by_old_date( $post_type ); } /** * Filters the old slug redirect post ID. * * @since 4.9.3 * * @param int $id The redirect post ID. */ $id = apply_filters( 'old_slug_redirect_post_id', $id ); if ( ! $id ) { return; } $link = get_permalink( $id ); if ( get_query_var( 'paged' ) > 1 ) { $link = user_trailingslashit( trailingslashit( $link ) . 'page/' . get_query_var( 'paged' ) ); } elseif ( is_embed() ) { $link = user_trailingslashit( trailingslashit( $link ) . 'embed' ); } /** * Filters the old slug redirect URL. * * @since 4.4.0 * * @param string $link The redirect URL. */ $link = apply_filters( 'old_slug_redirect_url', $link ); if ( ! $link ) { return; } wp_redirect( $link, 301 ); // Permanent redirect. exit; } } /** * Find the post ID for redirecting an old slug. * * @since 4.9.3 * @access private * * @see wp_old_slug_redirect() * @global wpdb $wpdb WordPress database abstraction object. * * @param string $post_type The current post type based on the query vars. * @return int The Post ID. */ function _find_post_by_old_slug( $post_type ) { global $wpdb; $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_slug' AND meta_value = %s", $post_type, get_query_var( 'name' ) ); /* * If year, monthnum, or day have been specified, make our query more precise * just in case there are multiple identical _wp_old_slug values. */ if ( get_query_var( 'year' ) ) { $query .= $wpdb->prepare( ' AND YEAR(post_date) = %d', get_query_var( 'year' ) ); } if ( get_query_var( 'monthnum' ) ) { $query .= $wpdb->prepare( ' AND MONTH(post_date) = %d', get_query_var( 'monthnum' ) ); } if ( get_query_var( 'day' ) ) { $query .= $wpdb->prepare( ' AND DAYOFMONTH(post_date) = %d', get_query_var( 'day' ) ); } $key = md5( $query ); $last_changed = wp_cache_get_last_changed( 'posts' ); $cache_key = "find_post_by_old_slug:$key"; $cache = wp_cache_get_salted( $cache_key, 'post-queries', $last_changed ); if ( false !== $cache ) { $id = $cache; } else { $id = (int) $wpdb->get_var( $query ); wp_cache_set_salted( $cache_key, $id, 'post-queries', $last_changed ); } return $id; } /** * Find the post ID for redirecting an old date. * * @since 4.9.3 * @access private * * @see wp_old_slug_redirect() * @global wpdb $wpdb WordPress database abstraction object. * * @param string $post_type The current post type based on the query vars. * @return int The Post ID. */ function _find_post_by_old_date( $post_type ) { global $wpdb; $date_query = ''; if ( get_query_var( 'year' ) ) { $date_query .= $wpdb->prepare( ' AND YEAR(pm_date.meta_value) = %d', get_query_var( 'year' ) ); } if ( get_query_var( 'monthnum' ) ) { $date_query .= $wpdb->prepare( ' AND MONTH(pm_date.meta_value) = %d', get_query_var( 'monthnum' ) ); } if ( get_query_var( 'day' ) ) { $date_query .= $wpdb->prepare( ' AND DAYOFMONTH(pm_date.meta_value) = %d', get_query_var( 'day' ) ); } $id = 0; if ( $date_query ) { $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta AS pm_date, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_date' AND post_name = %s" . $date_query, $post_type, get_query_var( 'name' ) ); $key = md5( $query ); $last_changed = wp_cache_get_last_changed( 'posts' ); $cache_key = "find_post_by_old_date:$key"; $cache = wp_cache_get_salted( $cache_key, 'post-queries', $last_changed ); if ( false !== $cache ) { $id = $cache; } else { $id = (int) $wpdb->get_var( $query ); if ( ! $id ) { // Check to see if an old slug matches the old date. $id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts, $wpdb->postmeta AS pm_slug, $wpdb->postmeta AS pm_date WHERE ID = pm_slug.post_id AND ID = pm_date.post_id AND post_type = %s AND pm_slug.meta_key = '_wp_old_slug' AND pm_slug.meta_value = %s AND pm_date.meta_key = '_wp_old_date'" . $date_query, $post_type, get_query_var( 'name' ) ) ); } wp_cache_set_salted( $cache_key, $id, 'post-queries', $last_changed ); } } return $id; } /** * Set up global post data. * * @since 1.5.0 * @since 4.4.0 Added the ability to pass a post ID to `$post`. * * @global WP_Query $wp_query WordPress Query object. * * @param WP_Post|object|int $post WP_Post instance or Post ID/object. * @return bool True when finished. */ function setup_postdata( $post ) { global $wp_query; if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) { return $wp_query->setup_postdata( $post ); } return false; } /** * Generates post data. * * @since 5.2.0 * * @global WP_Query $wp_query WordPress Query object. * * @param WP_Post|object|int $post WP_Post instance or Post ID/object. * @return array|false Elements of post, or false on failure. */ function generate_postdata( $post ) { global $wp_query; if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) { return $wp_query->generate_postdata( $post ); } return false; } in_array( $template_slug, $slugs_to_include, true ) ) { continue; } // Skip this item if its slug matches any of the slugs to skip. if ( ! empty( $slugs_to_skip ) && in_array( $template_slug, $slugs_to_skip, true ) ) { continue; } /* * The child theme items (stylesheet) are processed before the parent theme's (template). * If a child theme defines a template, prevent the parent template from being added to the list as well. */ if ( isset( $template_files[ $template_slug ] ) ) { continue; } $new_template_item = array( 'slug' => $template_slug, 'path' => $template_file, 'theme' => $theme_slug, 'type' => $template_type, ); if ( 'wp_template_part' === $template_type ) { $candidate = _add_block_template_part_area_info( $new_template_item ); if ( ! isset( $area ) || $area === $candidate['area'] ) { $template_files[ $template_slug ] = $candidate; } } if ( 'wp_template' === $template_type ) { $candidate = _add_block_template_info( $new_template_item ); $is_custom = ! isset( $default_template_types[ $candidate['slug'] ] ); if ( ! $post_type || ( $post_type && isset( $candidate['postTypes'] ) && in_array( $post_type, $candidate['postTypes'], true ) ) ) { $template_files[ $template_slug ] = $candidate; } // The custom templates with no associated post types are available for all post types. if ( $post_type && ! isset( $candidate['postTypes'] ) && $is_custom ) { $template_files[ $template_slug ] = $candidate; } } } } return array_values( $template_files ); } /** * Attempts to add custom template information to the template item. * * @since 5.9.0 * @access private * * @param array $template_item Template to add information to (requires 'slug' field). * @return array Template item. */ function _add_block_template_info( $template_item ) { if ( ! wp_theme_has_theme_json() ) { return $template_item; } $theme_data = wp_get_theme_data_custom_templates(); if ( isset( $theme_data[ $template_item['slug'] ] ) ) { $template_item['title'] = $theme_data[ $template_item['slug'] ]['title']; $template_item['postTypes'] = $theme_data[ $template_item['slug'] ]['postTypes']; } return $template_item; } /** * Attempts to add the template part's area information to the input template. * * @since 5.9.0 * @access private * * @param array $template_info Template to add information to (requires 'type' and 'slug' fields). * @return array Template info. */ function _add_block_template_part_area_info( $template_info ) { if ( wp_theme_has_theme_json() ) { $theme_data = wp_get_theme_data_template_parts(); } if ( isset( $theme_data[ $template_info['slug'] ]['area'] ) ) { $template_info['title'] = $theme_data[ $template_info['slug'] ]['title']; $template_info['area'] = _filter_block_template_part_area( $theme_data[ $template_info['slug'] ]['area'] ); } else { $template_info['area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; } return $template_info; } /** * Returns an array containing the references of * the passed blocks and their inner blocks. * * @since 5.9.0 * @access private * * @param array $blocks array of blocks. * @return array block references to the passed blocks and their inner blocks. */ function _flatten_blocks( &$blocks ) { $all_blocks = array(); $queue = array(); foreach ( $blocks as &$block ) { $queue[] = &$block; } while ( count( $queue ) > 0 ) { $block = &$queue[0]; array_shift( $queue ); $all_blocks[] = &$block; if ( ! empty( $block['innerBlocks'] ) ) { foreach ( $block['innerBlocks'] as &$inner_block ) { $queue[] = &$inner_block; } } } return $all_blocks; } /** * Injects the active theme's stylesheet as a `theme` attribute * into a given template part block. * * @since 6.4.0 * @access private * * @param array $block a parsed block. */ function _inject_theme_attribute_in_template_part_block( &$block ) { if ( 'core/template-part' === $block['blockName'] && ! isset( $block['attrs']['theme'] ) ) { $block['attrs']['theme'] = get_stylesheet(); } } /** * Removes the `theme` attribute from a given template part block. * * @since 6.4.0 * @access private * * @param array $block a parsed block. */ function _remove_theme_attribute_from_template_part_block( &$block ) { if ( 'core/template-part' === $block['blockName'] && isset( $block['attrs']['theme'] ) ) { unset( $block['attrs']['theme'] ); } } /** * Builds a unified template object based on a theme file. * * @since 5.9.0 * @since 6.3.0 Added `modified` property to template objects. * @since 7.1.0 Added `date` property to template objects. * @access private * * @param array $template_file Theme file. * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'. * @return WP_Block_Template Template. */ function _build_block_template_result_from_file( $template_file, $template_type ) { $default_template_types = get_default_block_template_types(); $theme = get_stylesheet(); $template = new WP_Block_Template(); $template->id = $theme . '//' . $template_file['slug']; $template->theme = $theme; $template->content = file_get_contents( $template_file['path'] ); $template->slug = $template_file['slug']; $template->source = 'theme'; $template->type = $template_type; $template->title = ! empty( $template_file['title'] ) ? $template_file['title'] : $template_file['slug']; $template->status = 'publish'; $template->has_theme_file = true; $template->is_custom = true; $template->modified = null; $template->date = null; if ( 'wp_template' === $template_type ) { $registered_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $template_file['slug'] ); if ( $registered_template ) { $template->plugin = $registered_template->plugin; $template->title = empty( $template->title ) || $template->title === $template->slug ? $registered_template->title : $template->title; $template->description = empty( $template->description ) ? $registered_template->description : $template->description; } } if ( 'wp_template' === $template_type && isset( $default_template_types[ $template_file['slug'] ] ) ) { $template->description = $default_template_types[ $template_file['slug'] ]['description']; $template->title = $default_template_types[ $template_file['slug'] ]['title']; $template->is_custom = false; } if ( 'wp_template' === $template_type && isset( $template_file['postTypes'] ) ) { $template->post_types = $template_file['postTypes']; } if ( 'wp_template_part' === $template_type && isset( $template_file['area'] ) ) { $template->area = $template_file['area']; } if ( 'wp_template_part' === $template->type ) { /* * In order for hooked blocks to be inserted at positions first_child and last_child in a template part, * we need to wrap its content a mock template part block and traverse it. */ $content = get_comment_delimited_block_content( 'core/template-part', array(), $template->content ); $content = apply_block_hooks_to_content( $content, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); $template->content = remove_serialized_parent_block( $content ); } else { $template->content = apply_block_hooks_to_content( $template->content, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); } return $template; } /** * Builds the title and description of a post-specific template based on the underlying referenced post. * * Mutates the underlying template object. * * @since 6.1.0 * @access private * * @param string $post_type Post type, e.g. page, post, product. * @param string $slug Slug of the post, e.g. a-story-about-shoes. * @param WP_Block_Template $template Template to mutate adding the description and title computed. * @return bool Returns true if the referenced post was found and false otherwise. */ function _wp_build_title_and_description_for_single_post_type_block_template( $post_type, $slug, WP_Block_Template $template ) { $post_type_object = get_post_type_object( $post_type ); $default_args = array( 'post_type' => $post_type, 'post_status' => 'publish', 'posts_per_page' => 1, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, 'ignore_sticky_posts' => true, 'no_found_rows' => true, ); $args = array( 'name' => $slug, ); $args = wp_parse_args( $args, $default_args ); $posts_query = new WP_Query( $args ); if ( empty( $posts_query->posts ) ) { $template->title = sprintf( /* translators: Custom template title in the Site Editor referencing a post that was not found. 1: Post type singular name, 2: Post type slug. */ __( 'Not found: %1$s (%2$s)' ), $post_type_object->labels->singular_name, $slug ); return false; } $post_title = $posts_query->posts[0]->post_title; $template->title = sprintf( /* translators: Custom template title in the Site Editor. 1: Post type singular name, 2: Post title. */ __( '%1$s: %2$s' ), $post_type_object->labels->singular_name, $post_title ); $template->description = sprintf( /* translators: Custom template description in the Site Editor. %s: Post title. */ __( 'Template for %s' ), $post_title ); $args = array( 'title' => $post_title, ); $args = wp_parse_args( $args, $default_args ); $posts_with_same_title_query = new WP_Query( $args ); if ( count( $posts_with_same_title_query->posts ) > 1 ) { $template->title = sprintf( /* translators: Custom template title in the Site Editor. 1: Template title, 2: Post type slug. */ __( '%1$s (%2$s)' ), $template->title, $slug ); } return true; } /** * Builds the title and description of a taxonomy-specific template based on the underlying entity referenced. * * Mutates the underlying template object. * * @since 6.1.0 * @access private * * @param string $taxonomy Identifier of the taxonomy, e.g. category. * @param string $slug Slug of the term, e.g. shoes. * @param WP_Block_Template $template Template to mutate adding the description and title computed. * @return bool True if the term referenced was found and false otherwise. */ function _wp_build_title_and_description_for_taxonomy_block_template( $taxonomy, $slug, WP_Block_Template $template ) { $taxonomy_object = get_taxonomy( $taxonomy ); $default_args = array( 'taxonomy' => $taxonomy, 'hide_empty' => false, 'update_term_meta_cache' => false, ); $term_query = new WP_Term_Query(); $args = array( 'number' => 1, 'slug' => $slug, ); $args = wp_parse_args( $args, $default_args ); $terms_query = $term_query->query( $args ); if ( empty( $terms_query ) ) { $template->title = sprintf( /* translators: Custom template title in the Site Editor, referencing a taxonomy term that was not found. 1: Taxonomy singular name, 2: Term slug. */ __( 'Not found: %1$s (%2$s)' ), $taxonomy_object->labels->singular_name, $slug ); return false; } $term_title = $terms_query[0]->name; $template->title = sprintf( /* translators: Custom template title in the Site Editor. 1: Taxonomy singular name, 2: Term title. */ __( '%1$s: %2$s' ), $taxonomy_object->labels->singular_name, $term_title ); $template->description = sprintf( /* translators: Custom template description in the Site Editor. %s: Term title. */ __( 'Template for %s' ), $term_title ); $term_query = new WP_Term_Query(); $args = array( 'number' => 2, 'name' => $term_title, ); $args = wp_parse_args( $args, $default_args ); $terms_with_same_title_query = $term_query->query( $args ); if ( count( $terms_with_same_title_query ) > 1 ) { $template->title = sprintf( /* translators: Custom template title in the Site Editor. 1: Template title, 2: Term slug. */ __( '%1$s (%2$s)' ), $template->title, $slug ); } return true; } /** * Builds a block template object from a post object. * * This is a helper function that creates a block template object from a given post object. * It is self-sufficient in that it only uses information passed as arguments; it does not * query the database for additional information. * * @since 6.5.3 * @access private * * @param WP_Post $post Template post. * @param array $terms Additional terms to inform the template object. * @param array $meta Additional meta fields to inform the template object. * @return WP_Block_Template|WP_Error Template or error object. */ function _build_block_template_object_from_post_object( $post, $terms = array(), $meta = array() ) { if ( empty( $terms['wp_theme'] ) ) { return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.' ) ); } $theme = $terms['wp_theme']; $default_template_types = get_default_block_template_types(); $template_file = _get_block_template_file( $post->post_type, $post->post_name ); $has_theme_file = get_stylesheet() === $theme && null !== $template_file; $template = new WP_Block_Template(); $template->wp_id = $post->ID; $template->id = $theme . '//' . $post->post_name; $template->theme = $theme; $template->content = $post->post_content; $template->slug = $post->post_name; $template->source = 'custom'; $template->origin = ! empty( $meta['origin'] ) ? $meta['origin'] : null; $template->type = $post->post_type; $template->description = $post->post_excerpt; $template->title = $post->post_title; $template->status = $post->post_status; $template->has_theme_file = $has_theme_file; $template->is_custom = empty( $meta['is_wp_suggestion'] ); $template->author = $post->post_author; $template->modified = $post->post_modified; $template->date = $post->post_date; if ( 'wp_template' === $post->post_type && $has_theme_file && isset( $template_file['postTypes'] ) ) { $template->post_types = $template_file['postTypes']; } if ( 'wp_template' === $post->post_type && isset( $default_template_types[ $template->slug ] ) ) { $template->is_custom = false; } if ( 'wp_template_part' === $post->post_type && isset( $terms['wp_template_part_area'] ) ) { $template->area = $terms['wp_template_part_area']; } return $template; } /** * Builds a unified template object based a post Object. * * @since 5.9.0 * @since 6.3.0 Added `modified` property to template objects. * @since 6.4.0 Added support for a revision post to be passed to this function. * @access private * * @param WP_Post $post Template post. * @return WP_Block_Template|WP_Error Template or error object. */ function _build_block_template_result_from_post( $post ) { $post_id = wp_is_post_revision( $post ); if ( ! $post_id ) { $post_id = $post; } $parent_post = get_post( $post_id ); $post->post_name = $parent_post->post_name; $post->post_type = $parent_post->post_type; $terms = get_the_terms( $parent_post, 'wp_theme' ); if ( is_wp_error( $terms ) ) { return $terms; } if ( ! $terms ) { return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.' ) ); } $terms = array( 'wp_theme' => $terms[0]->name, ); if ( 'wp_template_part' === $parent_post->post_type ) { $type_terms = get_the_terms( $parent_post, 'wp_template_part_area' ); if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) { $terms['wp_template_part_area'] = $type_terms[0]->name; } } $meta = array( 'origin' => get_post_meta( $parent_post->ID, 'origin', true ), 'is_wp_suggestion' => get_post_meta( $parent_post->ID, 'is_wp_suggestion', true ), ); $template = _build_block_template_object_from_post_object( $post, $terms, $meta ); if ( is_wp_error( $template ) ) { return $template; } // Check for a block template without a description and title or with a title equal to the slug. if ( 'wp_template' === $parent_post->post_type && empty( $template->description ) && ( empty( $template->title ) || $template->title === $template->slug ) ) { $matches = array(); // Check for a block template for a single author, page, post, tag, category, custom post type, or custom taxonomy. if ( preg_match( '/(author|page|single|tag|category|taxonomy)-(.+)/', $template->slug, $matches ) ) { $type = $matches[1]; $slug_remaining = $matches[2]; switch ( $type ) { case 'author': $nice_name = $slug_remaining; $users = get_users( array( 'capability' => 'edit_posts', 'search' => $nice_name, 'search_columns' => array( 'user_nicename' ), 'fields' => 'display_name', ) ); if ( empty( $users ) ) { $template->title = sprintf( /* translators: Custom template title in the Site Editor, referencing a deleted author. %s: Author nicename. */ __( 'Deleted author: %s' ), $nice_name ); } else { $author_name = $users[0]; $template->title = sprintf( /* translators: Custom template title in the Site Editor. %s: Author name. */ __( 'Author: %s' ), $author_name ); $template->description = sprintf( /* translators: Custom template description in the Site Editor. %s: Author name. */ __( 'Template for %s' ), $author_name ); $users_with_same_name = get_users( array( 'capability' => 'edit_posts', 'search' => $author_name, 'search_columns' => array( 'display_name' ), 'fields' => 'display_name', ) ); if ( count( $users_with_same_name ) > 1 ) { $template->title = sprintf( /* translators: Custom template title in the Site Editor. 1: Template title of an author template, 2: Author nicename. */ __( '%1$s (%2$s)' ), $template->title, $nice_name ); } } break; case 'page': _wp_build_title_and_description_for_single_post_type_block_template( 'page', $slug_remaining, $template ); break; case 'single': $post_types = get_post_types(); foreach ( $post_types as $post_type ) { $post_type_length = strlen( $post_type ) + 1; // If $slug_remaining starts with $post_type followed by a hyphen. if ( 0 === strncmp( $slug_remaining, $post_type . '-', $post_type_length ) ) { $slug = substr( $slug_remaining, $post_type_length, strlen( $slug_remaining ) ); $found = _wp_build_title_and_description_for_single_post_type_block_template( $post_type, $slug, $template ); if ( $found ) { break; } } } break; case 'tag': _wp_build_title_and_description_for_taxonomy_block_template( 'post_tag', $slug_remaining, $template ); break; case 'category': _wp_build_title_and_description_for_taxonomy_block_template( 'category', $slug_remaining, $template ); break; case 'taxonomy': $taxonomies = get_taxonomies(); foreach ( $taxonomies as $taxonomy ) { $taxonomy_length = strlen( $taxonomy ) + 1; // If $slug_remaining starts with $taxonomy followed by a hyphen. if ( 0 === strncmp( $slug_remaining, $taxonomy . '-', $taxonomy_length ) ) { $slug = substr( $slug_remaining, $taxonomy_length, strlen( $slug_remaining ) ); $found = _wp_build_title_and_description_for_taxonomy_block_template( $taxonomy, $slug, $template ); if ( $found ) { break; } } } break; } } } if ( 'wp_template' === $post->post_type ) { $registered_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $template->slug ); if ( $registered_template ) { $template->plugin = $registered_template->plugin; $template->origin = 'theme' !== $template->origin && 'theme' !== $template->source ? 'plugin' : $template->origin; $template->title = empty( $template->title ) || $template->title === $template->slug ? $registered_template->title : $template->title; $template->description = empty( $template->description ) ? $registered_template->description : $template->description; } } if ( 'wp_template_part' === $template->type ) { $existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ); $attributes = ! empty( $existing_ignored_hooked_blocks ) ? array( 'metadata' => array( 'ignoredHookedBlocks' => json_decode( $existing_ignored_hooked_blocks, true ) ) ) : array(); /* * In order for hooked blocks to be inserted at positions first_child and last_child in a template part, * we need to wrap its content a mock template part block and traverse it. */ $content = get_comment_delimited_block_content( 'core/template-part', $attributes, $template->content ); $content = apply_block_hooks_to_content( $content, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); $template->content = remove_serialized_parent_block( $content ); } else { $template->content = apply_block_hooks_to_content( $template->content, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); } return $template; } /** * Retrieves a list of unified template objects based on a query. * * @since 5.8.0 * * @param array $query { * Optional. Arguments to retrieve templates. * * @type string[] $slug__in List of slugs to include. * @type int $wp_id Post ID of customized template. * @type string $area A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only). * @type string $post_type Post type to get the templates for. * } * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'. * @return WP_Block_Template[] Array of block templates. */ function get_block_templates( $query = array(), $template_type = 'wp_template' ) { /** * Filters the block templates array before the query takes place. * * Return a non-null value to bypass the WordPress queries. * * @since 5.9.0 * * @param WP_Block_Template[]|null $block_templates Return an array of block templates to short-circuit the default query, * or null to allow WP to run its normal queries. * @param array $query { * Arguments to retrieve templates. All arguments are optional. * * @type string[] $slug__in List of slugs to include. * @type int $wp_id Post ID of customized template. * @type string $area A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only). * @type string $post_type Post type to get the templates for. * } * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'. */ $templates = apply_filters( 'pre_get_block_templates', null, $query, $template_type ); if ( ! is_null( $templates ) ) { return $templates; } $post_type = $query['post_type'] ?? ''; $wp_query_args = array( 'post_status' => array( 'auto-draft', 'draft', 'publish' ), 'post_type' => $template_type, 'posts_per_page' => -1, 'no_found_rows' => true, 'lazy_load_term_meta' => false, 'tax_query' => array( array( 'taxonomy' => 'wp_theme', 'field' => 'name', 'terms' => get_stylesheet(), ), ), ); if ( 'wp_template_part' === $template_type && isset( $query['area'] ) ) { $wp_query_args['tax_query'][] = array( 'taxonomy' => 'wp_template_part_area', 'field' => 'name', 'terms' => $query['area'], ); $wp_query_args['tax_query']['relation'] = 'AND'; } if ( ! empty( $query['slug__in'] ) ) { $wp_query_args['post_name__in'] = $query['slug__in']; $wp_query_args['posts_per_page'] = count( array_unique( $query['slug__in'] ) ); } // This is only needed for the regular templates/template parts post type listing and editor. if ( isset( $query['wp_id'] ) ) { $wp_query_args['p'] = $query['wp_id']; } else { $wp_query_args['post_status'] = 'publish'; } $template_query = new WP_Query( $wp_query_args ); $query_result = array(); foreach ( $template_query->posts as $post ) { $template = _build_block_template_result_from_post( $post ); if ( is_wp_error( $template ) ) { continue; } if ( $post_type && ! $template->is_custom ) { continue; } if ( $post_type && isset( $template->post_types ) && ! in_array( $post_type, $template->post_types, true ) ) { continue; } $query_result[] = $template; } if ( ! isset( $query['wp_id'] ) ) { /* * If the query has found some user templates, those have priority * over the theme-provided ones, so we skip querying and building them. */ $query['slug__not_in'] = wp_list_pluck( $query_result, 'slug' ); /* * We need to unset the post_type query param because some templates * would be excluded otherwise, like `page.html` when looking for * `page` templates. We need all templates so we can exclude duplicates * from plugin-registered templates. * See: https://github.com/WordPress/gutenberg/issues/65584 */ $template_files_query = $query; unset( $template_files_query['post_type'] ); $template_files = _get_block_templates_files( $template_type, $template_files_query ); foreach ( $template_files as $template_file ) { // If the query doesn't specify a post type, or it does and the template matches the post type, add it. if ( ! isset( $query['post_type'] ) || ( isset( $template_file['postTypes'] ) && in_array( $query['post_type'], $template_file['postTypes'], true ) ) ) { $query_result[] = _build_block_template_result_from_file( $template_file, $template_type ); } elseif ( ! isset( $template_file['postTypes'] ) ) { // The custom templates with no associated post types are available for all post types as long // as they are not default templates. $candidate = _build_block_template_result_from_file( $template_file, $template_type ); $default_template_types = get_default_block_template_types(); if ( ! isset( $default_template_types[ $candidate->slug ] ) ) { $query_result[] = $candidate; } } } if ( 'wp_template' === $template_type ) { // Add templates registered in the template registry. Filtering out the ones which have a theme file. $registered_templates = WP_Block_Templates_Registry::get_instance()->get_by_query( $query ); $matching_registered_templates = array_filter( $registered_templates, function ( $registered_template ) use ( $template_files ) { foreach ( $template_files as $template_file ) { if ( $template_file['slug'] === $registered_template->slug ) { return false; } } return true; } ); $matching_registered_templates = array_map( function ( $template ) { $template->content = apply_block_hooks_to_content( $template->content, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); return $template; }, $matching_registered_templates ); $query_result = array_merge( $query_result, $matching_registered_templates ); } } /** * Filters the array of queried block templates array after they've been fetched. * * @since 5.9.0 * * @param WP_Block_Template[] $query_result Array of found block templates. * @param array $query { * Arguments to retrieve templates. All arguments are optional. * * @type string[] $slug__in List of slugs to include. * @type int $wp_id Post ID of customized template. * @type string $area A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only). * @type string $post_type Post type to get the templates for. * } * @param string $template_type wp_template or wp_template_part. */ return apply_filters( 'get_block_templates', $query_result, $query, $template_type ); } /** * Retrieves a single unified template object using its id. * * @since 5.8.0 * * @param string $id Template unique identifier (example: 'theme_slug//template_slug'). * @param string $template_type Optional. Template type. Either 'wp_template' or 'wp_template_part'. * Default 'wp_template'. * @return WP_Block_Template|null Template. */ function get_block_template( $id, $template_type = 'wp_template' ) { /** * Filters the block template object before the query takes place. * * Return a non-null value to bypass the WordPress queries. * * @since 5.9.0 * * @param WP_Block_Template|null $block_template Return block template object to short-circuit the default query, * or null to allow WP to run its normal queries. * @param string $id Template unique identifier (example: 'theme_slug//template_slug'). * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'. */ $block_template = apply_filters( 'pre_get_block_template', null, $id, $template_type ); if ( ! is_null( $block_template ) ) { return $block_template; } $parts = explode( '//', $id, 2 ); if ( count( $parts ) < 2 ) { return null; } list( $theme, $slug ) = $parts; $wp_query_args = array( 'post_name__in' => array( $slug ), 'post_type' => $template_type, 'post_status' => array( 'auto-draft', 'draft', 'publish', 'trash' ), 'posts_per_page' => 1, 'no_found_rows' => true, 'tax_query' => array( array( 'taxonomy' => 'wp_theme', 'field' => 'name', 'terms' => $theme, ), ), ); $template_query = new WP_Query( $wp_query_args ); $posts = $template_query->posts; if ( count( $posts ) > 0 ) { $template = _build_block_template_result_from_post( $posts[0] ); if ( ! is_wp_error( $template ) ) { return $template; } } $block_template = get_block_file_template( $id, $template_type ); /** * Filters the queried block template object after it's been fetched. * * @since 5.9.0 * * @param WP_Block_Template|null $block_template The found block template, or null if there isn't one. * @param string $id Template unique identifier (example: 'theme_slug//template_slug'). * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'. */ return apply_filters( 'get_block_template', $block_template, $id, $template_type ); } /** * Retrieves a unified template object based on a theme file or plugin registration. * * This is a fallback of get_block_template(), used when no templates are found in the database. * Also checks for templates registered via the Template Registration API. * * @since 5.9.0 * * @param string $id Template unique identifier (example: 'theme_slug//template_slug'). * @param string $template_type Optional. Template type. Either 'wp_template' or 'wp_template_part'. * Default 'wp_template'. * @return WP_Block_Template|null The found block template, or null if there isn't one. */ function get_block_file_template( $id, $template_type = 'wp_template' ) { /** * Filters the block template object before the theme file discovery takes place. * * Return a non-null value to bypass the WordPress theme file discovery. * * @since 5.9.0 * * @param WP_Block_Template|null $block_template Return block template object to short-circuit the default query, * or null to allow WP to run its normal queries. * @param string $id Template unique identifier (example: 'theme_slug//template_slug'). * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'. */ $block_template = apply_filters( 'pre_get_block_file_template', null, $id, $template_type ); if ( ! is_null( $block_template ) ) { return $block_template; } $parts = explode( '//', $id, 2 ); if ( count( $parts ) < 2 ) { /** This filter is documented in wp-includes/block-template-utils.php */ return apply_filters( 'get_block_file_template', null, $id, $template_type ); } list( $theme, $slug ) = $parts; if ( get_stylesheet() === $theme ) { $template_file = _get_block_template_file( $template_type, $slug ); if ( null !== $template_file ) { $block_template = _build_block_template_result_from_file( $template_file, $template_type ); /** This filter is documented in wp-includes/block-template-utils.php */ return apply_filters( 'get_block_file_template', $block_template, $id, $template_type ); } } $block_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $slug ); if ( $block_template ) { $block_template->content = apply_block_hooks_to_content( $block_template->content, $block_template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' ); } /** * Filters the block template object after it has been (potentially) fetched from the theme file. * * @since 5.9.0 * * @param WP_Block_Template|null $block_template The found block template, or null if there is none. * @param string $id Template unique identifier (example: 'theme_slug//template_slug'). * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'. */ return apply_filters( 'get_block_file_template', $block_template, $id, $template_type ); } /** * Prints a block template part. * * @since 5.9.0 * * @param string $part The block template part to print, for example 'header' or 'footer'. */ function block_template_part( $part ) { $template_part = get_block_template( get_stylesheet() . '//' . $part, 'wp_template_part' ); if ( ! $template_part || empty( $template_part->content ) ) { return; } echo do_blocks( $template_part->content ); } /** * Prints the header block template part. * * @since 5.9.0 */ function block_header_area() { block_template_part( 'header' ); } /** * Prints the footer block template part. * * @since 5.9.0 */ function block_footer_area() { block_template_part( 'footer' ); } /** * Determines whether a theme directory should be ignored during export. * * @since 6.0.0 * * @param string $path The path of the file in the theme. * @return bool Whether this file is in an ignored directory. */ function wp_is_theme_directory_ignored( $path ) { $directories_to_ignore = array( '.DS_Store', '.svn', '.git', '.hg', '.bzr', 'node_modules', 'vendor' ); return array_any( $directories_to_ignore, fn( $directory ) => str_starts_with( $path, $directory ) ); } /** * Creates an export of the current templates and * template parts from the site editor at the * specified path in a ZIP file. * * @since 5.9.0 * @since 6.0.0 Adds the whole theme to the export archive. * * @return WP_Error|string Path of the ZIP file or error on failure. */ function wp_generate_block_templates_export_file() { $wp_version = wp_get_wp_version(); if ( ! class_exists( 'ZipArchive' ) ) { return new WP_Error( 'missing_zip_package', __( 'Zip Export not supported.' ) ); } $obscura = wp_generate_password( 12, false, false ); $theme_name = basename( get_stylesheet() ); $filename = get_temp_dir() . $theme_name . $obscura . '.zip'; $zip = new ZipArchive(); if ( true !== $zip->open( $filename, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) { return new WP_Error( 'unable_to_create_zip', __( 'Unable to open export file (archive) for writing.' ) ); } $zip->addEmptyDir( 'templates' ); $zip->addEmptyDir( 'parts' ); // Get path of the theme. $theme_path = wp_normalize_path( get_stylesheet_directory() ); // Create recursive directory iterator. $theme_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $theme_path ), RecursiveIteratorIterator::LEAVES_ONLY ); // Make a copy of the current theme. foreach ( $theme_files as $file ) { // Skip directories as they are added automatically. if ( ! $file->isDir() ) { // Get real and relative path for current file. $file_path = wp_normalize_path( $file ); $relative_path = substr( $file_path, strlen( $theme_path ) + 1 ); if ( ! wp_is_theme_directory_ignored( $relative_path ) ) { $zip->addFile( $file_path, $relative_path ); } } } // Load templates into the zip file. $templates = get_block_templates(); foreach ( $templates as $template ) { $template->content = traverse_and_serialize_blocks( parse_blocks( $template->content ), '_remove_theme_attribute_from_template_part_block' ); $zip->addFromString( 'templates/' . $template->slug . '.html', $template->content ); } // Load template parts into the zip file. $template_parts = get_block_templates( array(), 'wp_template_part' ); foreach ( $template_parts as $template_part ) { $zip->addFromString( 'parts/' . $template_part->slug . '.html', $template_part->content ); } // Load theme.json into the zip file. $tree = WP_Theme_JSON_Resolver::get_theme_data( array(), array( 'with_supports' => false ) ); // Merge with user data. $tree->merge( WP_Theme_JSON_Resolver::get_user_data() ); $theme_json_raw = $tree->get_data(); // If a version is defined, add a schema. if ( $theme_json_raw['version'] ) { $theme_json_version = 'wp/' . substr( $wp_version, 0, 3 ); $schema = array( '$schema' => 'https://schemas.wp.org/' . $theme_json_version . '/theme.json' ); $theme_json_raw = array_merge( $schema, $theme_json_raw ); } // Convert to a string. $theme_json_encoded = wp_json_encode( $theme_json_raw, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); // Replace 4 spaces with a tab. $theme_json_tabbed = preg_replace( '~(?:^|\G)\h{4}~m', "\t", $theme_json_encoded ); // Add the theme.json file to the zip. $zip->addFromString( 'theme.json', $theme_json_tabbed ); // Save changes to the zip file. $zip->close(); return $filename; } /** * Gets the template hierarchy for the given template slug to be created. * * Note: Always add `index` as the last fallback template. * * @since 6.1.0 * * @param string $slug The template slug to be created. * @param bool $is_custom Optional. Indicates if a template is custom or * part of the template hierarchy. Default false. * @param string $template_prefix Optional. The template prefix for the created template. * Used to extract the main template type, e.g. * in `taxonomy-books` the `taxonomy` is extracted. * Default empty string. * @return string[] The template hierarchy. */ function get_template_hierarchy( $slug, $is_custom = false, $template_prefix = '' ) { if ( 'index' === $slug ) { /** This filter is documented in wp-includes/template.php */ return apply_filters( 'index_template_hierarchy', array( 'index' ) ); } if ( $is_custom ) { /** This filter is documented in wp-includes/template.php */ return apply_filters( 'page_template_hierarchy', array( 'page', 'singular', 'index' ) ); } if ( 'front-page' === $slug ) { /** This filter is documented in wp-includes/template.php */ return apply_filters( 'frontpage_template_hierarchy', array( 'front-page', 'home', 'index' ) ); } $matches = array(); $template_hierarchy = array( $slug ); // Most default templates don't have `$template_prefix` assigned. if ( ! empty( $template_prefix ) ) { list( $type ) = explode( '-', $template_prefix ); // We need these checks because we always add the `$slug` above. if ( ! in_array( $template_prefix, array( $slug, $type ), true ) ) { $template_hierarchy[] = $template_prefix; } if ( $slug !== $type ) { $template_hierarchy[] = $type; } } elseif ( preg_match( '/^(author|category|archive|tag|page)-.+$/', $slug, $matches ) ) { $template_hierarchy[] = $matches[1]; } elseif ( preg_match( '/^(taxonomy|single)-(.+)$/', $slug, $matches ) ) { $type = $matches[1]; $slug_remaining = $matches[2]; $items = 'single' === $type ? get_post_types() : get_taxonomies(); foreach ( $items as $item ) { if ( ! str_starts_with( $slug_remaining, $item ) ) { continue; } // If $slug_remaining is equal to $post_type or $taxonomy we have // the single-$post_type template or the taxonomy-$taxonomy template. if ( $slug_remaining === $item ) { $template_hierarchy[] = $type; break; } // If $slug_remaining is single-$post_type-$slug template. if ( strlen( $slug_remaining ) > strlen( $item ) + 1 ) { $template_hierarchy[] = "$type-$item"; $template_hierarchy[] = $type; break; } } } // Handle `archive` template. if ( str_starts_with( $slug, 'author' ) || str_starts_with( $slug, 'taxonomy' ) || str_starts_with( $slug, 'category' ) || str_starts_with( $slug, 'tag' ) || 'date' === $slug ) { $template_hierarchy[] = 'archive'; } // Handle `single` template. if ( 'attachment' === $slug ) { $template_hierarchy[] = 'single'; } // Handle `singular` template. if ( str_starts_with( $slug, 'single' ) || str_starts_with( $slug, 'page' ) || 'attachment' === $slug ) { $template_hierarchy[] = 'singular'; } $template_hierarchy[] = 'index'; $template_type = ''; if ( ! empty( $template_prefix ) ) { list( $template_type ) = explode( '-', $template_prefix ); } else { list( $template_type ) = explode( '-', $slug ); } $valid_template_types = array( '404', 'archive', 'attachment', 'author', 'category', 'date', 'embed', 'frontpage', 'home', 'index', 'page', 'paged', 'privacypolicy', 'search', 'single', 'singular', 'tag', 'taxonomy' ); if ( in_array( $template_type, $valid_template_types, true ) ) { /** This filter is documented in wp-includes/template.php */ return apply_filters( "{$template_type}_template_hierarchy", $template_hierarchy ); } return $template_hierarchy; } /** * Inject ignoredHookedBlocks metadata attributes into a template or template part. * * Given an object that represents a `wp_template` or `wp_template_part` post object * prepared for inserting or updating the database, locate all blocks that have * hooked blocks, and inject a `metadata.ignoredHookedBlocks` attribute into the anchor * blocks to reflect the latter. * * @since 6.5.0 * @access private * * @param stdClass $changes An object representing a template or template part * prepared for inserting or updating the database. * @param WP_REST_Request $deprecated Deprecated. Not used. * @return stdClass|WP_Error The updated object representing a template or template part. */ function inject_ignored_hooked_blocks_metadata_attributes( $changes, $deprecated = null ) { if ( null !== $deprecated ) { _deprecated_argument( __FUNCTION__, '6.5.3' ); } if ( ! isset( $changes->post_content ) ) { return $changes; } $hooked_blocks = get_hooked_blocks(); if ( empty( $hooked_blocks ) && ! has_filter( 'hooked_block_types' ) ) { return $changes; } $meta = $changes->meta_input ?? array(); $terms = $changes->tax_input ?? array(); if ( empty( $changes->ID ) ) { // There's no post object for this template in the database for this template yet. $post = $changes; } else { // Find the existing post object. $post = get_post( $changes->ID ); // If the post is a revision, use the parent post's post_name and post_type. $post_id = wp_is_post_revision( $post ); if ( $post_id ) { $parent_post = get_post( $post_id ); $post->post_name = $parent_post->post_name; $post->post_type = $parent_post->post_type; } // Apply the changes to the existing post object. $post = (object) array_merge( (array) $post, (array) $changes ); $type_terms = get_the_terms( $changes->ID, 'wp_theme' ); $terms['wp_theme'] = ! is_wp_error( $type_terms ) && ! empty( $type_terms ) ? $type_terms[0]->name : null; } // Required for the WP_Block_Template. Update the post object with the current time. $post->post_modified = current_time( 'mysql' ); /* * If the post_author is empty, set it to the current user. If it arrived as * an int (e.g. from a REST controller), normalize it to a string, since the * resulting object is passed to new WP_Post(). */ if ( empty( $post->post_author ) ) { $post->post_author = (string) get_current_user_id(); } elseif ( is_int( $post->post_author ) ) { $post->post_author = (string) $post->post_author; } if ( 'wp_template_part' === $post->post_type && ! isset( $terms['wp_template_part_area'] ) ) { $area_terms = get_the_terms( $changes->ID, 'wp_template_part_area' ); $terms['wp_template_part_area'] = ! is_wp_error( $area_terms ) && ! empty( $area_terms ) ? $area_terms[0]->name : null; } $template = _build_block_template_object_from_post_object( new WP_Post( $post ), $terms, $meta ); if ( is_wp_error( $template ) ) { return $template; } if ( 'wp_template_part' === $post->post_type ) { $attributes = array(); $existing_ignored_hooked_blocks = isset( $post->ID ) ? get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ) : ''; if ( ! empty( $existing_ignored_hooked_blocks ) ) { $attributes['metadata'] = array( 'ignoredHookedBlocks' => json_decode( $existing_ignored_hooked_blocks, true ), ); } $content = get_comment_delimited_block_content( 'core/template-part', $attributes, $changes->post_content ); $content = apply_block_hooks_to_content( $content, $template, 'set_ignored_hooked_blocks_metadata' ); $changes->post_content = remove_serialized_parent_block( $content ); $wrapper_block_markup = extract_serialized_parent_block( $content ); $wrapper_block = parse_blocks( $wrapper_block_markup )[0]; $ignored_hooked_blocks = $wrapper_block['attrs']['metadata']['ignoredHookedBlocks'] ?? array(); if ( ! empty( $ignored_hooked_blocks ) ) { if ( ! isset( $changes->meta_input ) ) { $changes->meta_input = array(); } $changes->meta_input['_wp_ignored_hooked_blocks'] = wp_json_encode( $ignored_hooked_blocks ); } } else { $changes->post_content = apply_block_hooks_to_content( $changes->post_content, $template, 'set_ignored_hooked_blocks_metadata' ); } return $changes; } = $post->post_name; } if ( rest_is_field_included( 'guid', $fields ) ) { $data['guid'] = array(); } if ( rest_is_field_included( 'guid.rendered', $fields ) ) { /** This filter is documented in wp-includes/post-template.php */ $data['guid']['rendered'] = apply_filters( 'get_the_guid', $post->guid, $post->ID ); } if ( rest_is_field_included( 'guid.raw', $fields ) ) { $data['guid']['raw'] = $post->guid; } if ( rest_is_field_included( 'title', $fields ) ) { $data['title'] = array(); } if ( rest_is_field_included( 'title.raw', $fields ) ) { $data['title']['raw'] = $post->post_title; } if ( rest_is_field_included( 'title.rendered', $fields ) ) { $data['title']['rendered'] = get_the_title( $post->ID ); } if ( rest_is_field_included( 'content', $fields ) ) { $data['content'] = array(); } if ( rest_is_field_included( 'content.raw', $fields ) ) { $data['content']['raw'] = $post->post_content; } if ( rest_is_field_included( 'content.rendered', $fields ) ) { /** This filter is documented in wp-includes/post-template.php */ $data['content']['rendered'] = apply_filters( 'the_content', $post->post_content ); } if ( rest_is_field_included( 'excerpt', $fields ) ) { $data['excerpt'] = array(); } if ( rest_is_field_included( 'excerpt.raw', $fields ) ) { $data['excerpt']['raw'] = $post->post_excerpt; } if ( rest_is_field_included( 'excerpt.rendered', $fields ) ) { $data['excerpt']['rendered'] = $this->prepare_excerpt_response( $post->post_excerpt, $post ); } if ( rest_is_field_included( 'meta', $fields ) ) { $data['meta'] = $this->meta->get_value( $post->ID, $request ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( ! empty( $data['parent'] ) ) { $response->add_link( 'parent', rest_url( rest_get_route_for_post( $data['parent'] ) ) ); } /** * Filters a revision returned from the REST API. * * Allows modification of the revision right before it is returned. * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param WP_Post $post The original revision object. * @param WP_REST_Request $request Request used to generate the response. */ $response = apply_filters( 'rest_prepare_revision', $response, $post, $request ); $this->restore_post_data( $previous_post ); return $response; } /** * Restores the global post to its previous value after preparing a revision. * * Preparing a revision overwrites the global post and post data via * setup_postdata(). This restores the global post that was in place * beforehand so the change does not leak into the rest of the request. * * Only the global post is guaranteed to be restored. When there was no * previous global post and the main query has no post either, which is the * usual state during a REST request, wp_reset_postdata() has nothing to * restore from, so the remaining globals set by setup_postdata() (such as * $id, $authordata and $pages) are left describing the revision. Clearing * those would mean unsetting each one by hand, which is beyond what is * needed to keep the global post from leaking. * * @since 7.1.0 * * @param WP_Post|null $previous_post The global post to restore, or null if there was none. */ private function restore_post_data( ?WP_Post $previous_post ): void { if ( $previous_post ) { $GLOBALS['post'] = $previous_post; setup_postdata( $previous_post ); return; } /* * There was no global post to restore, so clear the revision's post data. * This runs before clearing the global post because wp_reset_postdata() * repopulates it from the main query whenever that query has a post. Note * that it is a no-op when the main query has no post, in which case only * the global post below is cleared. */ wp_reset_postdata(); /* * Assigned rather than unset so that any `global $post` binding made before * this request keeps pointing at the global. Unsetting removes the entry from * the symbol table, which detaches those bindings, and a later write through * one of them would no longer be visible to get_post(). */ $GLOBALS['post'] = null; } /** * Checks the post_date_gmt or modified_gmt and prepare any post or * modified date for single post output. * * @since 4.7.0 * * @param string $date_gmt GMT publication time. * @param string|null $date Optional. Local publication time. Default null. * @return string|null ISO8601/RFC3339 formatted datetime, otherwise null. */ protected function prepare_date_response( $date_gmt, $date = null ) { if ( '0000-00-00 00:00:00' === $date_gmt ) { return null; } if ( isset( $date ) ) { return mysql_to_rfc3339( $date ); } return mysql_to_rfc3339( $date_gmt ); } /** * Retrieves the revision's schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => "{$this->parent_post_type}-revision", 'type' => 'object', // Base properties for every Revision. 'properties' => array( 'author' => array( 'description' => __( 'The ID for the author of the revision.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), 'date' => array( 'description' => __( "The date the revision was published, in the site's timezone." ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit', 'embed' ), ), 'date_gmt' => array( 'description' => __( 'The date the revision was published, as GMT.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), ), 'guid' => array( 'description' => __( 'GUID for the revision, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), ), 'id' => array( 'description' => __( 'Unique identifier for the revision.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), 'modified' => array( 'description' => __( "The date the revision was last modified, in the site's timezone." ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), ), 'modified_gmt' => array( 'description' => __( 'The date the revision was last modified, as GMT.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), ), 'parent' => array( 'description' => __( 'The ID for the parent of the revision.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), 'slug' => array( 'description' => __( 'An alphanumeric identifier for the revision unique to its type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), ), ), ); $parent_schema = $this->parent_controller->get_item_schema(); if ( ! empty( $parent_schema['properties']['title'] ) ) { $schema['properties']['title'] = $parent_schema['properties']['title']; } if ( ! empty( $parent_schema['properties']['content'] ) ) { $schema['properties']['content'] = $parent_schema['properties']['content']; } if ( ! empty( $parent_schema['properties']['excerpt'] ) ) { $schema['properties']['excerpt'] = $parent_schema['properties']['excerpt']; } if ( ! empty( $parent_schema['properties']['guid'] ) ) { $schema['properties']['guid'] = $parent_schema['properties']['guid']; } $schema['properties']['meta'] = $this->meta->get_field_schema(); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * * @since 4.7.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; unset( $query_params['per_page']['default'] ); $query_params['exclude'] = array( 'description' => __( 'Ensure result set excludes specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['include'] = array( 'description' => __( 'Limit result set to specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['offset'] = array( 'description' => __( 'Offset the result set by a specific number of items.' ), 'type' => 'integer', ); $query_params['order'] = array( 'description' => __( 'Order sort attribute ascending or descending.' ), 'type' => 'string', 'default' => 'desc', 'enum' => array( 'asc', 'desc' ), ); $query_params['orderby'] = array( 'description' => __( 'Sort collection by object attribute.' ), 'type' => 'string', 'default' => 'date', 'enum' => array( 'date', 'id', 'include', 'relevance', 'slug', 'include_slugs', 'title', ), ); return $query_params; } /** * Checks the post excerpt and prepare it for single post output. * * @since 4.7.0 * * @param string $excerpt The post excerpt. * @param WP_Post $post Post revision object. * @return string Prepared excerpt or empty string. */ protected function prepare_excerpt_response( $excerpt, $post ) { /** This filter is documented in wp-includes/post-template.php */ $excerpt = apply_filters( 'the_excerpt', $excerpt ); if ( empty( $excerpt ) ) { return ''; } return $excerpt; } }
Fatal error: Uncaught Error: Class 'WP_REST_Revisions_Controller' not found in /home/he2a35ddd308f/public_html/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 /home/he2a35ddd308f/public_html/wp-settings.php(329): require() #1 /home/he2a35ddd308f/public_html/wp-config.php(75): require_once('/home/he2a35ddd...') #2 /home/he2a35ddd308f/public_html/wp-load.php(50): require_once('/home/he2a35ddd...') #3 /home/he2a35ddd308f/public_html/wp-blog-header.php(13): require_once('/home/he2a35ddd...') #4 /home/he2a35ddd308f/public_html/index.php(17): require('/home/he2a35ddd...') #5 {main} thrown in /home/he2a35ddd308f/public_html/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17

Fatal error: Uncaught Error: Call to a member function set() on null in /home/he2a35ddd308f/public_html/wp-includes/l10n.php:857 Stack trace: #0 /home/he2a35ddd308f/public_html/wp-includes/l10n.php(960): load_textdomain('default', '/home/he2a35ddd...', 'lv') #1 /home/he2a35ddd308f/public_html/wp-includes/class-wp-fatal-error-handler.php(49): load_default_textdomain() #2 [internal function]: WP_Fatal_Error_Handler->handle() #3 {main} thrown in /home/he2a35ddd308f/public_html/wp-includes/l10n.php on line 857