[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> block-patterns.php (source)

   1  <?php
   2  /**
   3   * Register the block patterns and block patterns categories
   4   *
   5   * @package WordPress
   6   * @since 5.5.0
   7   */
   8  
   9  add_theme_support( 'core-block-patterns' );
  10  
  11  /**
  12   * Registers a new block pattern.
  13   *
  14   * @since 5.5.0
  15   *
  16   * @param string $pattern_name       Block pattern name including namespace.
  17   * @param array  $pattern_properties List of properties for the block pattern.
  18   *                                   See WP_Block_Patterns_Registry::register() for accepted arguments.
  19   * @return bool True if the pattern was registered with success and false otherwise.
  20   */
  21  function register_block_pattern( $pattern_name, $pattern_properties ) {
  22      return WP_Block_Patterns_Registry::get_instance()->register( $pattern_name, $pattern_properties );
  23  }
  24  
  25  /**
  26   * Unregisters a block pattern.
  27   *
  28   * @since 5.5.0
  29   *
  30   * @param string $pattern_name Block pattern name including namespace.
  31   * @return bool True if the pattern was unregistered with success and false otherwise.
  32   */
  33  function unregister_block_pattern( $pattern_name ) {
  34      return WP_Block_Patterns_Registry::get_instance()->unregister( $pattern_name );
  35  }
  36  
  37  /**
  38   * Registers a new pattern category.
  39   *
  40   * @since 5.5.0
  41   *
  42   * @param string $category_name       Pattern category name including namespace.
  43   * @param array  $category_properties List of properties for the block pattern.
  44   *                                    See WP_Block_Pattern_Categories_Registry::register() for
  45   *                                    accepted arguments.
  46   * @return bool True if the pattern category was registered with success and false otherwise.
  47   */
  48  function register_block_pattern_category( $category_name, $category_properties ) {
  49      return WP_Block_Pattern_Categories_Registry::get_instance()->register( $category_name, $category_properties );
  50  }
  51  
  52  /**
  53   * Unregisters a pattern category.
  54   *
  55   * @since 5.5.0
  56   *
  57   * @param string $category_name Pattern category name including namespace.
  58   * @return bool True if the pattern category was unregistered with success and false otherwise.
  59   */
  60  function unregister_block_pattern_category( $category_name ) {
  61      return WP_Block_Pattern_Categories_Registry::get_instance()->unregister( $category_name );
  62  }
  63  
  64  /**
  65   * Registers the core block patterns and categories.
  66   *
  67   * @since 5.5.0
  68   * @since 6.3.0 Added source to core block patterns.
  69   * @access private
  70   */
  71  function _register_core_block_patterns_and_categories() {
  72      $should_register_core_patterns = get_theme_support( 'core-block-patterns' );
  73  
  74      if ( $should_register_core_patterns ) {
  75          $core_block_patterns = array(
  76              'query-standard-posts',
  77              'query-medium-posts',
  78              'query-small-posts',
  79              'query-grid-posts',
  80              'query-large-title-posts',
  81              'query-offset-posts',
  82          );
  83  
  84          foreach ( $core_block_patterns as $core_block_pattern ) {
  85              $pattern           = require __DIR__ . '/block-patterns/' . $core_block_pattern . '.php';
  86              $pattern['source'] = 'core';
  87              register_block_pattern( 'core/' . $core_block_pattern, $pattern );
  88          }
  89      }
  90  
  91      register_block_pattern_category(
  92          'banner',
  93          array(
  94              'label'       => _x( 'Banners', 'Block pattern category' ),
  95              'description' => __( 'Bold sections designed to showcase key content.' ),
  96          )
  97      );
  98      register_block_pattern_category(
  99          'buttons',
 100          array(
 101              'label'       => _x( 'Buttons', 'Block pattern category' ),
 102              'description' => __( 'Patterns that contain buttons and call to actions.' ),
 103          )
 104      );
 105      register_block_pattern_category(
 106          'columns',
 107          array(
 108              'label'       => _x( 'Columns', 'Block pattern category' ),
 109              'description' => __( 'Multi-column patterns with more complex layouts.' ),
 110          )
 111      );
 112      register_block_pattern_category(
 113          'text',
 114          array(
 115              'label'       => _x( 'Text', 'Block pattern category' ),
 116              'description' => __( 'Patterns containing mostly text.' ),
 117          )
 118      );
 119      register_block_pattern_category(
 120          'query',
 121          array(
 122              'label'       => _x( 'Posts', 'Block pattern category' ),
 123              'description' => __( 'Display your latest posts in lists, grids or other layouts.' ),
 124          )
 125      );
 126      register_block_pattern_category(
 127          'featured',
 128          array(
 129              'label'       => _x( 'Featured', 'Block pattern category' ),
 130              'description' => __( 'A set of high quality curated patterns.' ),
 131          )
 132      );
 133      register_block_pattern_category(
 134          'call-to-action',
 135          array(
 136              'label'       => _x( 'Call to action', 'Block pattern category' ),
 137              'description' => __( 'Sections whose purpose is to trigger a specific action.' ),
 138          )
 139      );
 140      register_block_pattern_category(
 141          'team',
 142          array(
 143              'label'       => _x( 'Team', 'Block pattern category' ),
 144              'description' => __( 'A variety of designs to display your team members.' ),
 145          )
 146      );
 147      register_block_pattern_category(
 148          'testimonials',
 149          array(
 150              'label'       => _x( 'Testimonials', 'Block pattern category' ),
 151              'description' => __( 'Share reviews and feedback about your brand/business.' ),
 152          )
 153      );
 154      register_block_pattern_category(
 155          'services',
 156          array(
 157              'label'       => _x( 'Services', 'Block pattern category' ),
 158              'description' => __( 'Briefly describe what your business does and how you can help.' ),
 159          )
 160      );
 161      register_block_pattern_category(
 162          'contact',
 163          array(
 164              'label'       => _x( 'Contact', 'Block pattern category' ),
 165              'description' => __( 'Display your contact information.' ),
 166          )
 167      );
 168      register_block_pattern_category(
 169          'about',
 170          array(
 171              'label'       => _x( 'About', 'Block pattern category' ),
 172              'description' => __( 'Introduce yourself.' ),
 173          )
 174      );
 175      register_block_pattern_category(
 176          'portfolio',
 177          array(
 178              'label'       => _x( 'Portfolio', 'Block pattern category' ),
 179              'description' => __( 'Showcase your latest work.' ),
 180          )
 181      );
 182      register_block_pattern_category(
 183          'gallery',
 184          array(
 185              'label'       => _x( 'Gallery', 'Block pattern category' ),
 186              'description' => __( 'Different layouts for displaying images.' ),
 187          )
 188      );
 189      register_block_pattern_category(
 190          'media',
 191          array(
 192              'label'       => _x( 'Media', 'Block pattern category' ),
 193              'description' => __( 'Different layouts containing video or audio.' ),
 194          )
 195      );
 196      register_block_pattern_category(
 197          'videos',
 198          array(
 199              'label'       => _x( 'Videos', 'Block pattern category' ),
 200              'description' => __( 'Different layouts containing videos.' ),
 201          )
 202      );
 203      register_block_pattern_category(
 204          'audio',
 205          array(
 206              'label'       => _x( 'Audio', 'Block pattern category' ),
 207              'description' => __( 'Different layouts containing audio.' ),
 208          )
 209      );
 210      register_block_pattern_category(
 211          'posts',
 212          array(
 213              'label'       => _x( 'Posts', 'Block pattern category' ),
 214              'description' => __( 'Display your latest posts in lists, grids or other layouts.' ),
 215          )
 216      );
 217      register_block_pattern_category(
 218          'footer',
 219          array(
 220              'label'       => _x( 'Footers', 'Block pattern category' ),
 221              'description' => __( 'A variety of footer designs displaying information and site navigation.' ),
 222          )
 223      );
 224      register_block_pattern_category(
 225          'header',
 226          array(
 227              'label'       => _x( 'Headers', 'Block pattern category' ),
 228              'description' => __( 'A variety of header designs displaying your site title and navigation.' ),
 229          )
 230      );
 231  }
 232  
 233  /**
 234   * Normalize the pattern properties to camelCase.
 235   *
 236   * The API's format is snake_case, `register_block_pattern()` expects camelCase.
 237   *
 238   * @since 6.2.0
 239   * @access private
 240   *
 241   * @param array $pattern Pattern as returned from the Pattern Directory API.
 242   * @return array Normalized pattern.
 243   */
 244  function wp_normalize_remote_block_pattern( $pattern ) {
 245      if ( isset( $pattern['block_types'] ) ) {
 246          $pattern['blockTypes'] = $pattern['block_types'];
 247          unset( $pattern['block_types'] );
 248      }
 249  
 250      if ( isset( $pattern['viewport_width'] ) ) {
 251          $pattern['viewportWidth'] = $pattern['viewport_width'];
 252          unset( $pattern['viewport_width'] );
 253      }
 254  
 255      return (array) $pattern;
 256  }
 257  
 258  /**
 259   * Register Core's official patterns from wordpress.org/patterns.
 260   *
 261   * @since 5.8.0
 262   * @since 5.9.0 The $current_screen argument was removed.
 263   * @since 6.2.0 Normalize the pattern from the API (snake_case) to the
 264   *              format expected by `register_block_pattern` (camelCase).
 265   * @since 6.3.0 Add 'pattern-directory/core' to the pattern's 'source'.
 266   *
 267   * @param WP_Screen $deprecated Unused. Formerly the screen that the current request was triggered from.
 268   */
 269  function _load_remote_block_patterns( $deprecated = null ) {
 270      if ( ! empty( $deprecated ) ) {
 271          _deprecated_argument( __FUNCTION__, '5.9.0' );
 272          $current_screen = $deprecated;
 273          if ( ! $current_screen->is_block_editor ) {
 274              return;
 275          }
 276      }
 277  
 278      $supports_core_patterns = get_theme_support( 'core-block-patterns' );
 279  
 280      /**
 281       * Filter to disable remote block patterns.
 282       *
 283       * @since 5.8.0
 284       *
 285       * @param bool $should_load_remote
 286       */
 287      $should_load_remote = apply_filters( 'should_load_remote_block_patterns', true );
 288  
 289      if ( $supports_core_patterns && $should_load_remote ) {
 290          $request         = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
 291          $core_keyword_id = 11; // 11 is the ID for "core".
 292          $request->set_param( 'keyword', $core_keyword_id );
 293          $response = rest_do_request( $request );
 294          if ( $response->is_error() ) {
 295              return;
 296          }
 297          $patterns = $response->get_data();
 298  
 299          foreach ( $patterns as $pattern ) {
 300              $pattern['source']  = 'pattern-directory/core';
 301              $normalized_pattern = wp_normalize_remote_block_pattern( $pattern );
 302              $pattern_name       = 'core/' . sanitize_title( $normalized_pattern['title'] );
 303              register_block_pattern( $pattern_name, $normalized_pattern );
 304          }
 305      }
 306  }
 307  
 308  /**
 309   * Register `Featured` (category) patterns from wordpress.org/patterns.
 310   *
 311   * @since 5.9.0
 312   * @since 6.2.0 Normalized the pattern from the API (snake_case) to the
 313   *              format expected by `register_block_pattern()` (camelCase).
 314   * @since 6.3.0 Add 'pattern-directory/featured' to the pattern's 'source'.
 315   */
 316  function _load_remote_featured_patterns() {
 317      $supports_core_patterns = get_theme_support( 'core-block-patterns' );
 318  
 319      /** This filter is documented in wp-includes/block-patterns.php */
 320      $should_load_remote = apply_filters( 'should_load_remote_block_patterns', true );
 321  
 322      if ( ! $should_load_remote || ! $supports_core_patterns ) {
 323          return;
 324      }
 325  
 326      $request         = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
 327      $featured_cat_id = 26; // This is the `Featured` category id from pattern directory.
 328      $request->set_param( 'category', $featured_cat_id );
 329      $response = rest_do_request( $request );
 330      if ( $response->is_error() ) {
 331          return;
 332      }
 333      $patterns = $response->get_data();
 334      $registry = WP_Block_Patterns_Registry::get_instance();
 335      foreach ( $patterns as $pattern ) {
 336          $pattern['source']  = 'pattern-directory/featured';
 337          $normalized_pattern = wp_normalize_remote_block_pattern( $pattern );
 338          $pattern_name       = sanitize_title( $normalized_pattern['title'] );
 339          // Some patterns might be already registered as core patterns with the `core` prefix.
 340          $is_registered = $registry->is_registered( $pattern_name ) || $registry->is_registered( "core/$pattern_name" );
 341          if ( ! $is_registered ) {
 342              register_block_pattern( $pattern_name, $normalized_pattern );
 343          }
 344      }
 345  }
 346  
 347  /**
 348   * Registers patterns from Pattern Directory provided by a theme's
 349   * `theme.json` file.
 350   *
 351   * @since 6.0.0
 352   * @since 6.2.0 Normalized the pattern from the API (snake_case) to the
 353   *              format expected by `register_block_pattern()` (camelCase).
 354   * @since 6.3.0 Add 'pattern-directory/theme' to the pattern's 'source'.
 355   * @access private
 356   */
 357  function _register_remote_theme_patterns() {
 358      /** This filter is documented in wp-includes/block-patterns.php */
 359      if ( ! apply_filters( 'should_load_remote_block_patterns', true ) ) {
 360          return;
 361      }
 362  
 363      if ( ! wp_theme_has_theme_json() ) {
 364          return;
 365      }
 366  
 367      $pattern_settings = wp_get_theme_directory_pattern_slugs();
 368      if ( empty( $pattern_settings ) ) {
 369          return;
 370      }
 371  
 372      $request         = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
 373      $request['slug'] = $pattern_settings;
 374      $response        = rest_do_request( $request );
 375      if ( $response->is_error() ) {
 376          return;
 377      }
 378      $patterns          = $response->get_data();
 379      $patterns_registry = WP_Block_Patterns_Registry::get_instance();
 380      foreach ( $patterns as $pattern ) {
 381          $pattern['source']  = 'pattern-directory/theme';
 382          $normalized_pattern = wp_normalize_remote_block_pattern( $pattern );
 383          $pattern_name       = sanitize_title( $normalized_pattern['title'] );
 384          // Some patterns might be already registered as core patterns with the `core` prefix.
 385          $is_registered = $patterns_registry->is_registered( $pattern_name ) || $patterns_registry->is_registered( "core/$pattern_name" );
 386          if ( ! $is_registered ) {
 387              register_block_pattern( $pattern_name, $normalized_pattern );
 388          }
 389      }
 390  }
 391  
 392  /**
 393   * Register any patterns that the active theme may provide under its
 394   * `./patterns/` directory.
 395   *
 396   * @since 6.0.0
 397   * @since 6.1.0 The `postTypes` property was added.
 398   * @since 6.2.0 The `templateTypes` property was added.
 399   * @since 6.4.0 Uses the `WP_Theme::get_block_patterns` method.
 400   * @access private
 401   */
 402  function _register_theme_block_patterns() {
 403  
 404      /*
 405       * During the bootstrap process, a check for active and valid themes is run.
 406       * If no themes are returned, the theme's functions.php file will not be loaded,
 407       * which can lead to errors if patterns expect some variables or constants to
 408       * already be set at this point, so bail early if that is the case.
 409       */
 410      if ( empty( wp_get_active_and_valid_themes() ) ) {
 411          return;
 412      }
 413  
 414      /*
 415       * Register patterns for the active theme. If the theme is a child theme,
 416       * let it override any patterns from the parent theme that shares the same slug.
 417       */
 418      $themes   = array();
 419      $theme    = wp_get_theme();
 420      $themes[] = $theme;
 421      if ( $theme->parent() ) {
 422          $themes[] = $theme->parent();
 423      }
 424      $registry = WP_Block_Patterns_Registry::get_instance();
 425  
 426      foreach ( $themes as $theme ) {
 427          $patterns    = $theme->get_block_patterns();
 428          $dirpath     = $theme->get_stylesheet_directory() . '/patterns/';
 429          $text_domain = $theme->get( 'TextDomain' );
 430  
 431          foreach ( $patterns as $file => $pattern_data ) {
 432              if ( $registry->is_registered( $pattern_data['slug'] ) ) {
 433                  continue;
 434              }
 435  
 436              $file_path = $dirpath . $file;
 437  
 438              if ( ! file_exists( $file_path ) ) {
 439                  _doing_it_wrong(
 440                      __FUNCTION__,
 441                      sprintf(
 442                          /* translators: %s: file name. */
 443                          __( 'Could not register file "%s" as a block pattern as the file does not exist.' ),
 444                          $file
 445                      ),
 446                      '6.4.0'
 447                  );
 448                  $theme->delete_pattern_cache();
 449                  continue;
 450              }
 451  
 452              $pattern_data['filePath'] = $file_path;
 453  
 454              // Translate the pattern metadata.
 455              // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain,WordPress.WP.I18n.LowLevelTranslationFunction
 456              $pattern_data['title'] = translate_with_gettext_context( $pattern_data['title'], 'Pattern title', $text_domain );
 457              if ( ! empty( $pattern_data['description'] ) ) {
 458                  // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain,WordPress.WP.I18n.LowLevelTranslationFunction
 459                  $pattern_data['description'] = translate_with_gettext_context( $pattern_data['description'], 'Pattern description', $text_domain );
 460              }
 461  
 462              register_block_pattern( $pattern_data['slug'], $pattern_data );
 463          }
 464      }
 465  }
 466  add_action( 'init', '_register_theme_block_patterns' );


Generated : Fri Apr 24 08:20:12 2026 Cross-referenced by PHPXref