Make WordPress Core


Ignore:
Timestamp:
06/23/2020 03:43:19 PM (4 years ago)
Author:
gziolo
Message:

Editor: Introduce new API method that register block from block.json metadata file

Backports changes added to Gutenberg in:

register_block_type_from_metadata function is going to be used to register all blocks on the server using block.json metadata files.

Props ocean90, azaozz, aduth, mcsf, jorgefilipecosta, spacedmonkey, nosolosw, swissspidy and noahtallen.
Fixes #50263.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/blocks.php

    r48102 r48141  
    3939function unregister_block_type( $name ) {
    4040    return WP_Block_Type_Registry::get_instance()->unregister( $name );
     41}
     42
     43/**
     44 * Removes the block asset's path prefix if provided.
     45 *
     46 * @since 5.5.0
     47 *
     48 * @param string $asset_handle_or_path Asset handle or prefixed path.
     49 * @return string Path without the prefix or the original value.
     50 */
     51function remove_block_asset_path_prefix( $asset_handle_or_path ) {
     52    $path_prefix = 'file:';
     53    if ( 0 !== strpos( $asset_handle_or_path, $path_prefix ) ) {
     54        return $asset_handle_or_path;
     55    }
     56    return substr(
     57        $asset_handle_or_path,
     58        strlen( $path_prefix )
     59    );
     60}
     61
     62/**
     63 * Generates the name for an asset based on the name of the block
     64 * and the field name provided.
     65 *
     66 * @since 5.5.0
     67 *
     68 * @param string $block_name Name of the block.
     69 * @param string $field_name Name of the metadata field.
     70 * @return string Generated asset name for the block's field.
     71 */
     72function generate_block_asset_handle( $block_name, $field_name ) {
     73    $field_mappings = array(
     74        'editorScript' => 'editor-script',
     75        'script'       => 'script',
     76        'editorStyle'  => 'editor-style',
     77        'style'        => 'style',
     78    );
     79    return str_replace( '/', '-', $block_name ) .
     80        '-' . $field_mappings[ $field_name ];
     81}
     82
     83/**
     84 * Finds a script handle for the selected block metadata field. It detects
     85 * when a path to file was provided and finds a corresponding
     86 * asset file with details necessary to register the script under
     87 * automatically generated handle name. It returns unprocessed script handle
     88 * otherwise.
     89 *
     90 * @since 5.5.0
     91 *
     92 * @param array  $metadata   Block metadata.
     93 * @param string $field_name Field name to pick from metadata.
     94 * @return string|bool Script handle provided directly or created through
     95 *                     script's registration, or false on failure.
     96 */
     97function register_block_script_handle( $metadata, $field_name ) {
     98    if ( empty( $metadata[ $field_name ] ) ) {
     99        return false;
     100    }
     101    $script_handle = $metadata[ $field_name ];
     102    $script_path   = remove_block_asset_path_prefix( $metadata[ $field_name ] );
     103    if ( $script_handle === $script_path ) {
     104        return $script_handle;
     105    }
     106
     107    $script_handle     = generate_block_asset_handle( $metadata['name'], $field_name );
     108    $script_asset_path = realpath(
     109        dirname( $metadata['file'] ) . '/' .
     110        substr_replace( $script_path, '.asset.php', - strlen( '.js' ) )
     111    );
     112    if ( ! file_exists( $script_asset_path ) ) {
     113        $message = sprintf(
     114            /* translators: %1: field name. %2: block name */
     115            __( 'The asset file for the "%1$s" defined in "%2$s" block definition is missing.', 'default' ),
     116            $field_name,
     117            $metadata['name']
     118        );
     119        _doing_it_wrong( __FUNCTION__, $message, '5.5.0' );
     120        return false;
     121    }
     122    $script_asset = require $script_asset_path;
     123    $result       = wp_register_script(
     124        $script_handle,
     125        plugins_url( $script_path, $metadata['file'] ),
     126        $script_asset['dependencies'],
     127        $script_asset['version']
     128    );
     129    return $result ? $script_handle : false;
     130}
     131
     132/**
     133 * Finds a style handle for the block metadata field. It detects when a path
     134 * to file was provided and registers the style under automatically
     135 * generated handle name. It returns unprocessed style handle otherwise.
     136 *
     137 * @since 5.5.0
     138 *
     139 * @param array  $metadata Block metadata.
     140 * @param string $field_name Field name to pick from metadata.
     141 * @return string|boolean Style handle provided directly or created through
     142 *                        style's registration, or false on failure.
     143 */
     144function register_block_style_handle( $metadata, $field_name ) {
     145    if ( empty( $metadata[ $field_name ] ) ) {
     146        return false;
     147    }
     148    $style_handle = $metadata[ $field_name ];
     149    $style_path   = remove_block_asset_path_prefix( $metadata[ $field_name ] );
     150    if ( $style_handle === $style_path ) {
     151        return $style_handle;
     152    }
     153
     154    $style_handle = generate_block_asset_handle( $metadata['name'], $field_name );
     155    $block_dir    = dirname( $metadata['file'] );
     156    $result       = wp_register_style(
     157        $style_handle,
     158        plugins_url( $style_path, $metadata['file'] ),
     159        array(),
     160        filemtime( realpath( "$block_dir/$style_path" ) )
     161    );
     162    return $result ? $style_handle : false;
     163}
     164
     165/**
     166 * Registers a block type from metadata stored in the `block.json` file.
     167 *
     168 * @since 5.5.0
     169 *
     170 * @param string $file_or_folder Path to the JSON file with metadata definition for
     171 *                               the block or path to the folder where the `block.json` file is located.
     172 * @param array  $args {
     173 *     Optional. Array of block type arguments. Any arguments may be defined, however the
     174 *     ones described below are supported by default. Default empty array.
     175 *
     176 *     @type callable $render_callback Callback used to render blocks of this block type.
     177 * }
     178 * @return WP_Block_Type|false The registered block type on success, or false on failure.
     179 */
     180function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
     181    $filename      = 'block.json';
     182    $metadata_file = ( substr( $file_or_folder, -strlen( $filename ) ) !== $filename ) ?
     183        trailingslashit( $file_or_folder ) . $filename :
     184        $file_or_folder;
     185    if ( ! file_exists( $metadata_file ) ) {
     186        return false;
     187    }
     188
     189    $metadata = json_decode( file_get_contents( $metadata_file ), true );
     190    if ( ! is_array( $metadata ) || empty( $metadata['name'] ) ) {
     191        return false;
     192    }
     193    $metadata['file'] = $metadata_file;
     194
     195    $settings          = array();
     196    $property_mappings = array(
     197        'title'           => 'title',
     198        'category'        => 'category',
     199        'parent'          => 'parent',
     200        'icon'            => 'icon',
     201        'description'     => 'description',
     202        'keywords'        => 'keywords',
     203        'attributes'      => 'attributes',
     204        'providesContext' => 'provides_context',
     205        'usesContext'     => 'uses_context',
     206        'supports'        => 'supports',
     207        'styles'          => 'styles',
     208        'example'         => 'example',
     209    );
     210
     211    foreach ( $property_mappings as $key => $mapped_key ) {
     212        if ( isset( $metadata[ $key ] ) ) {
     213            $settings[ $mapped_key ] = $metadata[ $key ];
     214        }
     215    }
     216
     217    if ( ! empty( $metadata['editorScript'] ) ) {
     218        $settings['editor_script'] = register_block_script_handle(
     219            $metadata,
     220            'editorScript'
     221        );
     222    }
     223
     224    if ( ! empty( $metadata['script'] ) ) {
     225        $settings['script'] = register_block_script_handle(
     226            $metadata,
     227            'script'
     228        );
     229    }
     230
     231    if ( ! empty( $metadata['editorStyle'] ) ) {
     232        $settings['editor_style'] = register_block_style_handle(
     233            $metadata,
     234            'editorStyle'
     235        );
     236    }
     237
     238    if ( ! empty( $metadata['style'] ) ) {
     239        $settings['style'] = register_block_style_handle(
     240            $metadata,
     241            'style'
     242        );
     243    }
     244
     245    return register_block_type(
     246        $metadata['name'],
     247        array_merge(
     248            $settings,
     249            $args
     250        )
     251    );
    41252}
    42253
Note: See TracChangeset for help on using the changeset viewer.