wp/wp-includes/class-wp-block-templates-registry.php
changeset 22 8c2e4d02f4ef
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wp/wp-includes/class-wp-block-templates-registry.php	Fri Sep 05 18:52:52 2025 +0200
@@ -0,0 +1,256 @@
+<?php
+/**
+ * Templates registry functions.
+ *
+ * @package WordPress
+ * @since 6.7.0
+ */
+
+/**
+ * Core class used for interacting with templates.
+ *
+ * @since 6.7.0
+ */
+final class WP_Block_Templates_Registry {
+	/**
+	 * Registered templates, as `$name => $instance` pairs.
+	 *
+	 * @since 6.7.0
+	 * @var WP_Block_Template[] $registered_block_templates Registered templates.
+	 */
+	private $registered_templates = array();
+
+	/**
+	 * Container for the main instance of the class.
+	 *
+	 * @since 6.7.0
+	 * @var WP_Block_Templates_Registry|null
+	 */
+	private static $instance = null;
+
+	/**
+	 * Registers a template.
+	 *
+	 * @since 6.7.0
+	 *
+	 * @param string $template_name Template name including namespace.
+	 * @param array  $args          Optional. Array of template arguments.
+	 * @return WP_Block_Template|WP_Error The registered template on success, or WP_Error on failure.
+	 */
+	public function register( $template_name, $args = array() ) {
+
+		$template = null;
+
+		$error_message = '';
+		$error_code    = '';
+
+		if ( ! is_string( $template_name ) ) {
+			$error_message = __( 'Template names must be strings.' );
+			$error_code    = 'template_name_no_string';
+		} elseif ( preg_match( '/[A-Z]+/', $template_name ) ) {
+			$error_message = __( 'Template names must not contain uppercase characters.' );
+			$error_code    = 'template_name_no_uppercase';
+		} elseif ( ! preg_match( '/^[a-z0-9_\-]+\/\/[a-z0-9_\-]+$/', $template_name ) ) {
+			$error_message = __( 'Template names must contain a namespace prefix. Example: my-plugin//my-custom-template' );
+			$error_code    = 'template_no_prefix';
+		} elseif ( $this->is_registered( $template_name ) ) {
+			/* translators: %s: Template name. */
+			$error_message = sprintf( __( 'Template "%s" is already registered.' ), $template_name );
+			$error_code    = 'template_already_registered';
+		}
+
+		if ( $error_message ) {
+			_doing_it_wrong(
+				__METHOD__,
+				$error_message,
+				'6.7.0'
+			);
+			return new WP_Error( $error_code, $error_message );
+		}
+
+		if ( ! $template ) {
+			$theme_name             = get_stylesheet();
+			list( $plugin, $slug )  = explode( '//', $template_name );
+			$default_template_types = get_default_block_template_types();
+
+			$template              = new WP_Block_Template();
+			$template->id          = $theme_name . '//' . $slug;
+			$template->theme       = $theme_name;
+			$template->plugin      = $plugin;
+			$template->author      = null;
+			$template->content     = isset( $args['content'] ) ? $args['content'] : '';
+			$template->source      = 'plugin';
+			$template->slug        = $slug;
+			$template->type        = 'wp_template';
+			$template->title       = isset( $args['title'] ) ? $args['title'] : $template_name;
+			$template->description = isset( $args['description'] ) ? $args['description'] : '';
+			$template->status      = 'publish';
+			$template->origin      = 'plugin';
+			$template->is_custom   = ! isset( $default_template_types[ $template_name ] );
+			$template->post_types  = isset( $args['post_types'] ) ? $args['post_types'] : array();
+		}
+
+		$this->registered_templates[ $template_name ] = $template;
+
+		return $template;
+	}
+
+	/**
+	 * Retrieves all registered templates.
+	 *
+	 * @since 6.7.0
+	 *
+	 * @return WP_Block_Template[] Associative array of `$template_name => $template` pairs.
+	 */
+	public function get_all_registered() {
+		return $this->registered_templates;
+	}
+
+	/**
+	 * Retrieves a registered template by its name.
+	 *
+	 * @since 6.7.0
+	 *
+	 * @param string $template_name Template name including namespace.
+	 * @return WP_Block_Template|null The registered template, or null if it is not registered.
+	 */
+	public function get_registered( $template_name ) {
+		if ( ! $this->is_registered( $template_name ) ) {
+			return null;
+		}
+
+		return $this->registered_templates[ $template_name ];
+	}
+
+	/**
+	 * Retrieves a registered template by its slug.
+	 *
+	 * @since 6.7.0
+	 *
+	 * @param string $template_slug Slug of the template.
+	 * @return WP_Block_Template|null The registered template, or null if it is not registered.
+	 */
+	public function get_by_slug( $template_slug ) {
+		$all_templates = $this->get_all_registered();
+
+		if ( ! $all_templates ) {
+			return null;
+		}
+
+		foreach ( $all_templates as $template ) {
+			if ( $template->slug === $template_slug ) {
+				return $template;
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Retrieves registered templates matching a query.
+	 *
+	 * @since 6.7.0
+	 *
+	 * @param array  $query {
+	 *     Arguments to retrieve templates. Optional, empty by default.
+	 *
+	 *     @type string[] $slug__in     List of slugs to include.
+	 *     @type string[] $slug__not_in List of slugs to skip.
+	 *     @type string   $post_type    Post type to get the templates for.
+	 * }
+	 * @return WP_Block_Template[] Associative array of `$template_name => $template` pairs.
+	 */
+	public function get_by_query( $query = array() ) {
+		$all_templates = $this->get_all_registered();
+
+		if ( ! $all_templates ) {
+			return array();
+		}
+
+		$query            = wp_parse_args(
+			$query,
+			array(
+				'slug__in'     => array(),
+				'slug__not_in' => array(),
+				'post_type'    => '',
+			)
+		);
+		$slugs_to_include = $query['slug__in'];
+		$slugs_to_skip    = $query['slug__not_in'];
+		$post_type        = $query['post_type'];
+
+		$matching_templates = array();
+		foreach ( $all_templates as $template_name => $template ) {
+			if ( $slugs_to_include && ! in_array( $template->slug, $slugs_to_include, true ) ) {
+				continue;
+			}
+
+			if ( $slugs_to_skip && in_array( $template->slug, $slugs_to_skip, true ) ) {
+				continue;
+			}
+
+			if ( $post_type && ! in_array( $post_type, $template->post_types, true ) ) {
+				continue;
+			}
+
+			$matching_templates[ $template_name ] = $template;
+		}
+
+		return $matching_templates;
+	}
+
+	/**
+	 * Checks if a template is registered.
+	 *
+	 * @since 6.7.0
+	 *
+	 * @param string $template_name Template name.
+	 * @return bool True if the template is registered, false otherwise.
+	 */
+	public function is_registered( $template_name ) {
+		return isset( $this->registered_templates[ $template_name ] );
+	}
+
+	/**
+	 * Unregisters a template.
+	 *
+	 * @since 6.7.0
+	 *
+	 * @param string $template_name Template name including namespace.
+	 * @return WP_Block_Template|WP_Error The unregistered template on success, or WP_Error on failure.
+	 */
+	public function unregister( $template_name ) {
+		if ( ! $this->is_registered( $template_name ) ) {
+			_doing_it_wrong(
+				__METHOD__,
+				/* translators: %s: Template name. */
+				sprintf( __( 'Template "%s" is not registered.' ), $template_name ),
+				'6.7.0'
+			);
+			/* translators: %s: Template name. */
+			return new WP_Error( 'template_not_registered', __( 'Template "%s" is not registered.' ) );
+		}
+
+		$unregistered_template = $this->registered_templates[ $template_name ];
+		unset( $this->registered_templates[ $template_name ] );
+
+		return $unregistered_template;
+	}
+
+	/**
+	 * Utility method to retrieve the main instance of the class.
+	 *
+	 * The instance will be created if it does not exist yet.
+	 *
+	 * @since 6.7.0
+	 *
+	 * @return WP_Block_Templates_Registry The main instance.
+	 */
+	public static function get_instance() {
+		if ( null === self::$instance ) {
+			self::$instance = new self();
+		}
+
+		return self::$instance;
+	}
+}