wp/wp-includes/block-template-utils.php
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
equal deleted inserted replaced
21:48c4eec2b7e6 22:8c2e4d02f4ef
   204 			'title'       => _x( 'Page: 404', 'Template name' ),
   204 			'title'       => _x( 'Page: 404', 'Template name' ),
   205 			'description' => __( 'Displays when a visitor views a non-existent page, such as a dead link or a mistyped URL.' ),
   205 			'description' => __( 'Displays when a visitor views a non-existent page, such as a dead link or a mistyped URL.' ),
   206 		),
   206 		),
   207 	);
   207 	);
   208 
   208 
       
   209 	// Add a title and description to post format templates.
       
   210 	$post_formats = get_post_format_strings();
       
   211 	foreach ( $post_formats as $post_format_slug => $post_format_name ) {
       
   212 		$default_template_types[ 'taxonomy-post_format-post-format-' . $post_format_slug ] = array(
       
   213 			'title'       => sprintf(
       
   214 				/* translators: %s: Post format name. */
       
   215 				_x( 'Post Format: %s', 'Template name' ),
       
   216 				$post_format_name
       
   217 			),
       
   218 			'description' => sprintf(
       
   219 				/* translators: %s: Post format name. */
       
   220 				__( 'Displays the %s post format archive.' ),
       
   221 				$post_format_name
       
   222 			),
       
   223 		);
       
   224 	}
       
   225 
   209 	/**
   226 	/**
   210 	 * Filters the list of default template types.
   227 	 * Filters the list of default template types.
   211 	 *
   228 	 *
   212 	 * @since 5.9.0
   229 	 * @since 5.9.0
   213 	 *
   230 	 *
   353  *     @type string[] $slug__not_in List of slugs to skip.
   370  *     @type string[] $slug__not_in List of slugs to skip.
   354  *     @type string   $area         A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only).
   371  *     @type string   $area         A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only).
   355  *     @type string   $post_type    Post type to get the templates for.
   372  *     @type string   $post_type    Post type to get the templates for.
   356  * }
   373  * }
   357  *
   374  *
   358  * @return array Template
   375  * @return array|null Template files on success, null if `$template_type` is not matched.
   359  */
   376  */
   360 function _get_block_templates_files( $template_type, $query = array() ) {
   377 function _get_block_templates_files( $template_type, $query = array() ) {
   361 	if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) {
   378 	if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) {
   362 		return null;
   379 		return null;
   363 	}
   380 	}
   590 	$template->status         = 'publish';
   607 	$template->status         = 'publish';
   591 	$template->has_theme_file = true;
   608 	$template->has_theme_file = true;
   592 	$template->is_custom      = true;
   609 	$template->is_custom      = true;
   593 	$template->modified       = null;
   610 	$template->modified       = null;
   594 
   611 
       
   612 	if ( 'wp_template' === $template_type ) {
       
   613 		$registered_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $template_file['slug'] );
       
   614 		if ( $registered_template ) {
       
   615 			$template->plugin      = $registered_template->plugin;
       
   616 			$template->title       = empty( $template->title ) || $template->title === $template->slug ? $registered_template->title : $template->title;
       
   617 			$template->description = empty( $template->description ) ? $registered_template->description : $template->description;
       
   618 		}
       
   619 	}
       
   620 
   595 	if ( 'wp_template' === $template_type && isset( $default_template_types[ $template_file['slug'] ] ) ) {
   621 	if ( 'wp_template' === $template_type && isset( $default_template_types[ $template_file['slug'] ] ) ) {
   596 		$template->description = $default_template_types[ $template_file['slug'] ]['description'];
   622 		$template->description = $default_template_types[ $template_file['slug'] ]['description'];
   597 		$template->title       = $default_template_types[ $template_file['slug'] ]['title'];
   623 		$template->title       = $default_template_types[ $template_file['slug'] ]['title'];
   598 		$template->is_custom   = false;
   624 		$template->is_custom   = false;
   599 	}
   625 	}
   604 
   630 
   605 	if ( 'wp_template_part' === $template_type && isset( $template_file['area'] ) ) {
   631 	if ( 'wp_template_part' === $template_type && isset( $template_file['area'] ) ) {
   606 		$template->area = $template_file['area'];
   632 		$template->area = $template_file['area'];
   607 	}
   633 	}
   608 
   634 
   609 	$before_block_visitor = '_inject_theme_attribute_in_template_part_block';
   635 	if ( 'wp_template_part' === $template->type ) {
   610 	$after_block_visitor  = null;
   636 		/*
   611 	$hooked_blocks        = get_hooked_blocks();
   637 		 * In order for hooked blocks to be inserted at positions first_child and last_child in a template part,
   612 	if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
   638 		 * we need to wrap its content a mock template part block and traverse it.
   613 		$before_block_visitor = make_before_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
   639 		 */
   614 		$after_block_visitor  = make_after_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
   640 		$content           = get_comment_delimited_block_content(
   615 	}
   641 			'core/template-part',
   616 	$blocks            = parse_blocks( $template->content );
   642 			array(),
   617 	$template->content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
   643 			$template->content
       
   644 		);
       
   645 		$content           = apply_block_hooks_to_content(
       
   646 			$content,
       
   647 			$template,
       
   648 			'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata'
       
   649 		);
       
   650 		$template->content = remove_serialized_parent_block( $content );
       
   651 	} else {
       
   652 		$template->content = apply_block_hooks_to_content(
       
   653 			$template->content,
       
   654 			$template,
       
   655 			'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata'
       
   656 		);
       
   657 	}
   618 
   658 
   619 	return $template;
   659 	return $template;
   620 }
   660 }
   621 
   661 
   622 /**
   662 /**
   992 					break;
  1032 					break;
   993 			}
  1033 			}
   994 		}
  1034 		}
   995 	}
  1035 	}
   996 
  1036 
   997 	$hooked_blocks = get_hooked_blocks();
  1037 	if ( 'wp_template' === $post->post_type ) {
   998 	if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
  1038 		$registered_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $template->slug );
   999 		$before_block_visitor = make_before_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
  1039 		if ( $registered_template ) {
  1000 		$after_block_visitor  = make_after_block_visitor( $hooked_blocks, $template, 'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata' );
  1040 			$template->plugin      = $registered_template->plugin;
  1001 		$blocks               = parse_blocks( $template->content );
  1041 			$template->origin      =
  1002 		$template->content    = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
  1042 				'theme' !== $template->origin && 'theme' !== $template->source ?
       
  1043 				'plugin' :
       
  1044 				$template->origin;
       
  1045 			$template->title       = empty( $template->title ) || $template->title === $template->slug ? $registered_template->title : $template->title;
       
  1046 			$template->description = empty( $template->description ) ? $registered_template->description : $template->description;
       
  1047 		}
       
  1048 	}
       
  1049 
       
  1050 	if ( 'wp_template_part' === $template->type ) {
       
  1051 		$existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true );
       
  1052 		$attributes                     = ! empty( $existing_ignored_hooked_blocks ) ? array( 'metadata' => array( 'ignoredHookedBlocks' => json_decode( $existing_ignored_hooked_blocks, true ) ) ) : array();
       
  1053 
       
  1054 		/*
       
  1055 		 * In order for hooked blocks to be inserted at positions first_child and last_child in a template part,
       
  1056 		 * we need to wrap its content a mock template part block and traverse it.
       
  1057 		 */
       
  1058 		$content           = get_comment_delimited_block_content(
       
  1059 			'core/template-part',
       
  1060 			$attributes,
       
  1061 			$template->content
       
  1062 		);
       
  1063 		$content           = apply_block_hooks_to_content(
       
  1064 			$content,
       
  1065 			$template,
       
  1066 			'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata'
       
  1067 		);
       
  1068 		$template->content = remove_serialized_parent_block( $content );
       
  1069 	} else {
       
  1070 		$template->content = apply_block_hooks_to_content(
       
  1071 			$template->content,
       
  1072 			$template,
       
  1073 			'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata'
       
  1074 		);
  1003 	}
  1075 	}
  1004 
  1076 
  1005 	return $template;
  1077 	return $template;
  1006 }
  1078 }
  1007 
  1079 
  1107 		$query_result[] = $template;
  1179 		$query_result[] = $template;
  1108 	}
  1180 	}
  1109 
  1181 
  1110 	if ( ! isset( $query['wp_id'] ) ) {
  1182 	if ( ! isset( $query['wp_id'] ) ) {
  1111 		/*
  1183 		/*
  1112 		 * If the query has found some use templates, those have priority
  1184 		 * If the query has found some user templates, those have priority
  1113 		 * over the theme-provided ones, so we skip querying and building them.
  1185 		 * over the theme-provided ones, so we skip querying and building them.
  1114 		 */
  1186 		 */
  1115 		$query['slug__not_in'] = wp_list_pluck( $query_result, 'slug' );
  1187 		$query['slug__not_in'] = wp_list_pluck( $query_result, 'slug' );
  1116 		$template_files        = _get_block_templates_files( $template_type, $query );
  1188 		/*
       
  1189 		 * We need to unset the post_type query param because some templates
       
  1190 		 * would be excluded otherwise, like `page.html` when looking for
       
  1191 		 * `page` templates. We need all templates so we can exclude duplicates
       
  1192 		 * from plugin-registered templates.
       
  1193 		 * See: https://github.com/WordPress/gutenberg/issues/65584
       
  1194 		 */
       
  1195 		$template_files_query = $query;
       
  1196 		unset( $template_files_query['post_type'] );
       
  1197 		$template_files = _get_block_templates_files( $template_type, $template_files_query );
  1117 		foreach ( $template_files as $template_file ) {
  1198 		foreach ( $template_files as $template_file ) {
  1118 			$query_result[] = _build_block_template_result_from_file( $template_file, $template_type );
  1199 			// If the query doesn't specify a post type, or it does and the template matches the post type, add it.
       
  1200 			if (
       
  1201 				! isset( $query['post_type'] ) ||
       
  1202 				(
       
  1203 					isset( $template_file['postTypes'] ) &&
       
  1204 					in_array( $query['post_type'], $template_file['postTypes'], true )
       
  1205 				)
       
  1206 			) {
       
  1207 				$query_result[] = _build_block_template_result_from_file( $template_file, $template_type );
       
  1208 			} elseif ( ! isset( $template_file['postTypes'] ) ) {
       
  1209 				// The custom templates with no associated post types are available for all post types as long
       
  1210 				// as they are not default templates.
       
  1211 				$candidate              = _build_block_template_result_from_file( $template_file, $template_type );
       
  1212 				$default_template_types = get_default_block_template_types();
       
  1213 				if ( ! isset( $default_template_types[ $candidate->slug ] ) ) {
       
  1214 					$query_result[] = $candidate;
       
  1215 				}
       
  1216 			}
       
  1217 		}
       
  1218 
       
  1219 		if ( 'wp_template' === $template_type ) {
       
  1220 			// Add templates registered in the template registry. Filtering out the ones which have a theme file.
       
  1221 			$registered_templates          = WP_Block_Templates_Registry::get_instance()->get_by_query( $query );
       
  1222 			$matching_registered_templates = array_filter(
       
  1223 				$registered_templates,
       
  1224 				function ( $registered_template ) use ( $template_files ) {
       
  1225 					foreach ( $template_files as $template_file ) {
       
  1226 						if ( $template_file['slug'] === $registered_template->slug ) {
       
  1227 							return false;
       
  1228 						}
       
  1229 					}
       
  1230 					return true;
       
  1231 				}
       
  1232 			);
       
  1233 			$query_result                  = array_merge( $query_result, $matching_registered_templates );
  1119 		}
  1234 		}
  1120 	}
  1235 	}
  1121 
  1236 
  1122 	/**
  1237 	/**
  1123 	 * Filters the array of queried block templates array after they've been fetched.
  1238 	 * Filters the array of queried block templates array after they've been fetched.
  1245 		/** This filter is documented in wp-includes/block-template-utils.php */
  1360 		/** This filter is documented in wp-includes/block-template-utils.php */
  1246 		return apply_filters( 'get_block_file_template', null, $id, $template_type );
  1361 		return apply_filters( 'get_block_file_template', null, $id, $template_type );
  1247 	}
  1362 	}
  1248 	list( $theme, $slug ) = $parts;
  1363 	list( $theme, $slug ) = $parts;
  1249 
  1364 
  1250 	if ( get_stylesheet() !== $theme ) {
  1365 	if ( get_stylesheet() === $theme ) {
  1251 		/** This filter is documented in wp-includes/block-template-utils.php */
  1366 		$template_file = _get_block_template_file( $template_type, $slug );
  1252 		return apply_filters( 'get_block_file_template', null, $id, $template_type );
  1367 		if ( null !== $template_file ) {
  1253 	}
  1368 			$block_template = _build_block_template_result_from_file( $template_file, $template_type );
  1254 
  1369 
  1255 	$template_file = _get_block_template_file( $template_type, $slug );
  1370 			/** This filter is documented in wp-includes/block-template-utils.php */
  1256 	if ( null === $template_file ) {
  1371 			return apply_filters( 'get_block_file_template', $block_template, $id, $template_type );
  1257 		/** This filter is documented in wp-includes/block-template-utils.php */
  1372 		}
  1258 		return apply_filters( 'get_block_file_template', null, $id, $template_type );
  1373 	}
  1259 	}
  1374 
  1260 
  1375 	$block_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $slug );
  1261 	$block_template = _build_block_template_result_from_file( $template_file, $template_type );
       
  1262 
  1376 
  1263 	/**
  1377 	/**
  1264 	 * Filters the block template object after it has been (potentially) fetched from the theme file.
  1378 	 * Filters the block template object after it has been (potentially) fetched from the theme file.
  1265 	 *
  1379 	 *
  1266 	 * @since 5.9.0
  1380 	 * @since 5.9.0
  1331  * specified path in a ZIP file.
  1445  * specified path in a ZIP file.
  1332  *
  1446  *
  1333  * @since 5.9.0
  1447  * @since 5.9.0
  1334  * @since 6.0.0 Adds the whole theme to the export archive.
  1448  * @since 6.0.0 Adds the whole theme to the export archive.
  1335  *
  1449  *
  1336  * @global string $wp_version The WordPress version string.
       
  1337  *
       
  1338  * @return WP_Error|string Path of the ZIP file or error on failure.
  1450  * @return WP_Error|string Path of the ZIP file or error on failure.
  1339  */
  1451  */
  1340 function wp_generate_block_templates_export_file() {
  1452 function wp_generate_block_templates_export_file() {
  1341 	global $wp_version;
  1453 	$wp_version = wp_get_wp_version();
  1342 
  1454 
  1343 	if ( ! class_exists( 'ZipArchive' ) ) {
  1455 	if ( ! class_exists( 'ZipArchive' ) ) {
  1344 		return new WP_Error( 'missing_zip_package', __( 'Zip Export not supported.' ) );
  1456 		return new WP_Error( 'missing_zip_package', __( 'Zip Export not supported.' ) );
  1345 	}
  1457 	}
  1346 
  1458 
  1613 
  1725 
  1614 	if ( is_wp_error( $template ) ) {
  1726 	if ( is_wp_error( $template ) ) {
  1615 		return $template;
  1727 		return $template;
  1616 	}
  1728 	}
  1617 
  1729 
  1618 	$changes->post_content = apply_block_hooks_to_content( $changes->post_content, $template, 'set_ignored_hooked_blocks_metadata' );
  1730 	if ( 'wp_template_part' === $post->post_type ) {
       
  1731 		$attributes                     = array();
       
  1732 		$existing_ignored_hooked_blocks = isset( $post->ID ) ? get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ) : '';
       
  1733 
       
  1734 		if ( ! empty( $existing_ignored_hooked_blocks ) ) {
       
  1735 			$attributes['metadata'] = array(
       
  1736 				'ignoredHookedBlocks' => json_decode( $existing_ignored_hooked_blocks, true ),
       
  1737 			);
       
  1738 		}
       
  1739 
       
  1740 		$content               = get_comment_delimited_block_content(
       
  1741 			'core/template-part',
       
  1742 			$attributes,
       
  1743 			$changes->post_content
       
  1744 		);
       
  1745 		$content               = apply_block_hooks_to_content( $content, $template, 'set_ignored_hooked_blocks_metadata' );
       
  1746 		$changes->post_content = remove_serialized_parent_block( $content );
       
  1747 
       
  1748 		$wrapper_block_markup  = extract_serialized_parent_block( $content );
       
  1749 		$wrapper_block         = parse_blocks( $wrapper_block_markup )[0];
       
  1750 		$ignored_hooked_blocks = $wrapper_block['attrs']['metadata']['ignoredHookedBlocks'] ?? array();
       
  1751 		if ( ! empty( $ignored_hooked_blocks ) ) {
       
  1752 			if ( ! isset( $changes->meta_input ) ) {
       
  1753 				$changes->meta_input = array();
       
  1754 			}
       
  1755 			$changes->meta_input['_wp_ignored_hooked_blocks'] = wp_json_encode( $ignored_hooked_blocks );
       
  1756 		}
       
  1757 	} else {
       
  1758 		$changes->post_content = apply_block_hooks_to_content( $changes->post_content, $template, 'set_ignored_hooked_blocks_metadata' );
       
  1759 	}
  1619 
  1760 
  1620 	return $changes;
  1761 	return $changes;
  1621 }
  1762 }