WordPress.org

Make WordPress Core

Ticket #45097: 45097.3.diff

File 45097.3.diff, 24.4 KB (added by desrosj, 3 years ago)
  • src/wp-includes/class-wp-block-type-registry.php

     
     1<?php
     2/**
     3 * Blocks API: WP_Block_Type_Registry class
     4 *
     5 * @package WordPress
     6 * @subpackage Blocks
     7 * @since 5.0.0
     8 */
     9
     10/**
     11 * Core class used for interacting with block types.
     12 *
     13 * @since 5.0.0
     14 */
     15final class WP_Block_Type_Registry {
     16        /**
     17         * Registered block types, as `$name => $instance` pairs.
     18         *
     19         * @since 5.0.0
     20         * @var WP_Block_Type[]
     21         */
     22        private $registered_block_types = array();
     23
     24        /**
     25         * Container for the main instance of the class.
     26         *
     27         * @since 5.0.0
     28         * @var WP_Block_Type_Registry|null
     29         */
     30        private static $instance = null;
     31
     32        /**
     33         * Registers a block type.
     34         *
     35         * @since 5.0.0
     36         *
     37         * @param string|WP_Block_Type $name Block type name including namespace, or alternatively a
     38         *                                   complete WP_Block_Type instance. In case a WP_Block_Type
     39         *                                   is provided, the $args parameter will be ignored.
     40         * @param array                $args {
     41         *     Optional. Array of block type arguments. Any arguments may be defined, however the
     42         *     ones described below are supported by default. Default empty array.
     43         *
     44         *     @type callable $render_callback Callback used to render blocks of this block type.
     45         *     @type array    $attributes      Block attributes mapping, property name to schema.
     46         * }
     47         * @return WP_Block_Type|false The registered block type on success, or false on failure.
     48         */
     49        public function register( $name, $args = array() ) {
     50                $block_type = null;
     51                if ( $name instanceof WP_Block_Type ) {
     52                        $block_type = $name;
     53                        $name       = $block_type->name;
     54                }
     55
     56                if ( ! is_string( $name ) ) {
     57                        $message = __( 'Block type names must be strings.' );
     58                        _doing_it_wrong( __METHOD__, $message, '5.0.0' );
     59                        return false;
     60                }
     61
     62                if ( preg_match( '/[A-Z]+/', $name ) ) {
     63                        $message = __( 'Block type names must not contain uppercase characters.' );
     64                        _doing_it_wrong( __METHOD__, $message, '5.0.0' );
     65                        return false;
     66                }
     67
     68                $name_matcher = '/^[a-z0-9-]+\/[a-z0-9-]+$/';
     69                if ( ! preg_match( $name_matcher, $name ) ) {
     70                        $message = __( 'Block type names must contain a namespace prefix. Example: my-plugin/my-custom-block-type' );
     71                        _doing_it_wrong( __METHOD__, $message, '5.0.0' );
     72                        return false;
     73                }
     74
     75                if ( $this->is_registered( $name ) ) {
     76                        /* translators: 1: block name */
     77                        $message = sprintf( __( 'Block type "%s" is already registered.' ), $name );
     78                        _doing_it_wrong( __METHOD__, $message, '5.0.0' );
     79                        return false;
     80                }
     81
     82                if ( ! $block_type ) {
     83                        $block_type = new WP_Block_Type( $name, $args );
     84                }
     85
     86                $this->registered_block_types[ $name ] = $block_type;
     87
     88                return $block_type;
     89        }
     90
     91        /**
     92         * Unregisters a block type.
     93         *
     94         * @since 5.0.0
     95         *
     96         * @param string|WP_Block_Type $name Block type name including namespace, or alternatively a
     97         *                                   complete WP_Block_Type instance.
     98         * @return WP_Block_Type|false The unregistered block type on success, or false on failure.
     99         */
     100        public function unregister( $name ) {
     101                if ( $name instanceof WP_Block_Type ) {
     102                        $name = $name->name;
     103                }
     104
     105                if ( ! $this->is_registered( $name ) ) {
     106                        /* translators: 1: block name */
     107                        $message = sprintf( __( 'Block type "%s" is not registered.' ), $name );
     108                        _doing_it_wrong( __METHOD__, $message, '5.0.0' );
     109                        return false;
     110                }
     111
     112                $unregistered_block_type = $this->registered_block_types[ $name ];
     113                unset( $this->registered_block_types[ $name ] );
     114
     115                return $unregistered_block_type;
     116        }
     117
     118        /**
     119         * Retrieves a registered block type.
     120         *
     121         * @since 5.0.0
     122         *
     123         * @param string $name Block type name including namespace.
     124         * @return WP_Block_Type|null The registered block type, or null if it is not registered.
     125         */
     126        public function get_registered( $name ) {
     127                if ( ! $this->is_registered( $name ) ) {
     128                        return null;
     129                }
     130
     131                return $this->registered_block_types[ $name ];
     132        }
     133
     134        /**
     135         * Retrieves all registered block types.
     136         *
     137         * @since 5.0.0
     138         *
     139         * @return WP_Block_Type[] Associative array of `$block_type_name => $block_type` pairs.
     140         */
     141        public function get_all_registered() {
     142                return $this->registered_block_types;
     143        }
     144
     145        /**
     146         * Checks if a block type is registered.
     147         *
     148         * @since 5.0.0
     149         *
     150         * @param string $name Block type name including namespace.
     151         * @return bool True if the block type is registered, false otherwise.
     152         */
     153        public function is_registered( $name ) {
     154                return isset( $this->registered_block_types[ $name ] );
     155        }
     156
     157        /**
     158         * Utility method to retrieve the main instance of the class.
     159         *
     160         * The instance will be created if it does not exist yet.
     161         *
     162         * @since 5.0.0
     163         *
     164         * @return WP_Block_Type_Registry The main instance.
     165         */
     166        public static function get_instance() {
     167                if ( null === self::$instance ) {
     168                        self::$instance = new self();
     169                }
     170
     171                return self::$instance;
     172        }
     173}
  • src/wp-includes/class-wp-block-type.php

     
     1<?php
     2/**
     3 * Blocks API: WP_Block_Type class
     4 *
     5 * @package WordPress
     6 * @subpackage Blocks
     7 * @since 5.0.0
     8 */
     9
     10/**
     11 * Core class representing a block type.
     12 *
     13 * @since 5.0.0
     14 *
     15 * @see register_block_type()
     16 */
     17class WP_Block_Type {
     18        /**
     19         * Block type key.
     20         *
     21         * @since 5.0.0
     22         * @var string
     23         */
     24        public $name;
     25
     26        /**
     27         * Block type render callback.
     28         *
     29         * @since 5.0.0
     30         * @var callable
     31         */
     32        public $render_callback;
     33
     34        /**
     35         * Block type attributes property schemas.
     36         *
     37         * @since 5.0.0
     38         * @var array
     39         */
     40        public $attributes;
     41
     42        /**
     43         * Block type editor script handle.
     44         *
     45         * @since 5.0.0
     46         * @var string
     47         */
     48        public $editor_script;
     49
     50        /**
     51         * Block type front end script handle.
     52         *
     53         * @since 5.0.0
     54         * @var string
     55         */
     56        public $script;
     57
     58        /**
     59         * Block type editor style handle.
     60         *
     61         * @since 5.0.0
     62         * @var string
     63         */
     64        public $editor_style;
     65
     66        /**
     67         * Block type front end style handle.
     68         *
     69         * @since 5.0.0
     70         * @var string
     71         */
     72        public $style;
     73
     74        /**
     75         * Constructor.
     76         *
     77         * Will populate object properties from the provided arguments.
     78         *
     79         * @since 5.0.0
     80         *
     81         * @see register_block_type()
     82         *
     83         * @param string       $block_type Block type name including namespace.
     84         * @param array|string $args       Optional. Array or string of arguments for registering a block type.
     85         *                                 Default empty array.
     86         */
     87        public function __construct( $block_type, $args = array() ) {
     88                $this->name = $block_type;
     89
     90                $this->set_props( $args );
     91        }
     92
     93        /**
     94         * Renders the block type output for given attributes.
     95         *
     96         * @since 5.0.0
     97         *
     98         * @param array  $attributes Optional. Block attributes. Default empty array.
     99         * @param string $content    Optional. Block content. Default empty string.
     100         * @return string Rendered block type output.
     101         */
     102        public function render( $attributes = array(), $content = '' ) {
     103                if ( ! $this->is_dynamic() ) {
     104                        return '';
     105                }
     106
     107                $attributes = $this->prepare_attributes_for_render( $attributes );
     108
     109                return (string) call_user_func( $this->render_callback, $attributes, $content );
     110        }
     111
     112        /**
     113         * Returns true if the block type is dynamic, or false otherwise. A dynamic
     114         * block is one which defers its rendering to occur on-demand at runtime.
     115         *
     116         * @since 5.0.0
     117         *
     118         * @return boolean Whether block type is dynamic.
     119         */
     120        public function is_dynamic() {
     121                return is_callable( $this->render_callback );
     122        }
     123
     124        /**
     125         * Validates attributes against the current block schema, populating
     126         * defaulted and missing values, and omitting unknown attributes.
     127         *
     128         * @since 5.0.0
     129         *
     130         * @param  array $attributes Original block attributes.
     131         * @return array             Prepared block attributes.
     132         */
     133        public function prepare_attributes_for_render( $attributes ) {
     134                if ( ! isset( $this->attributes ) ) {
     135                        return $attributes;
     136                }
     137
     138                $prepared_attributes = array();
     139
     140                foreach ( $this->attributes as $attribute_name => $schema ) {
     141                        $value = null;
     142
     143                        if ( isset( $attributes[ $attribute_name ] ) ) {
     144                                $is_valid = rest_validate_value_from_schema( $attributes[ $attribute_name ], $schema );
     145                                if ( ! is_wp_error( $is_valid ) ) {
     146                                        $value = rest_sanitize_value_from_schema( $attributes[ $attribute_name ], $schema );
     147                                }
     148                        }
     149
     150                        if ( is_null( $value ) && isset( $schema['default'] ) ) {
     151                                $value = $schema['default'];
     152                        }
     153
     154                        $prepared_attributes[ $attribute_name ] = $value;
     155                }
     156
     157                return $prepared_attributes;
     158        }
     159
     160        /**
     161         * Sets block type properties.
     162         *
     163         * @since 5.0.0
     164         *
     165         * @param array|string $args Array or string of arguments for registering a block type.
     166         */
     167        public function set_props( $args ) {
     168                $args = wp_parse_args(
     169                        $args,
     170                        array(
     171                                'render_callback' => null,
     172                        )
     173                );
     174
     175                $args['name'] = $this->name;
     176
     177                foreach ( $args as $property_name => $property_value ) {
     178                        $this->$property_name = $property_value;
     179                }
     180        }
     181
     182        /**
     183         * Get all available block attributes including possible layout attribute from Columns block.
     184         *
     185         * @since 5.0.0
     186         *
     187         * @return array Array of attributes.
     188         */
     189        public function get_attributes() {
     190                return is_array( $this->attributes ) ?
     191                        array_merge(
     192                                $this->attributes,
     193                                array(
     194                                        'layout' => array(
     195                                                'type' => 'string',
     196                                        ),
     197                                )
     198                        ) :
     199                        array(
     200                                'layout' => array(
     201                                        'type' => 'string',
     202                                ),
     203                        );
     204        }
     205}
  • src/wp-settings.php

     
    240240require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php' );
    241241require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-term-meta-fields.php' );
    242242require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-user-meta-fields.php' );
     243require( ABSPATH . WPINC . '/class-wp-block-type.php' );
     244require( ABSPATH . WPINC . '/class-wp-block-type-registry.php' );
    243245
    244246$GLOBALS['wp_embed'] = new WP_Embed();
    245247
  • tests/phpunit/includes/bootstrap.php

     
    117117require dirname( __FILE__ ) . '/exceptions.php';
    118118require dirname( __FILE__ ) . '/utils.php';
    119119require dirname( __FILE__ ) . '/spy-rest-server.php';
     120require dirname( __FILE__ ) . '/class-wp-fake-block-type.php';
    120121
    121122/**
    122123 * A child class of the PHP test runner.
  • tests/phpunit/includes/class-wp-fake-block-type.php

     
     1<?php
     2/**
     3 * WP_Fake_Block_Type for testing
     4 *
     5 * @package WordPress
     6 * @subpackage Blocks
     7 * @since 5.0.0
     8 */
     9
     10/**
     11 * Test class extending WP_Block_Type
     12 *
     13 * @since 5.0.0
     14 */
     15class WP_Fake_Block_Type extends WP_Block_Type {
     16
     17        /**
     18         * Render the fake block.
     19         *
     20         * @param array  $attributes Optional. Block attributes. Default empty array.
     21         * @param string $content    Optional. Block content. Default empty string.
     22         * @return string Rendered block HTML.
     23         */
     24        public function render( $attributes = array(), $content = '' ) {
     25                return '<div>' . $content . '</div>';
     26        }
     27}
  • tests/phpunit/tests/blocks/block-type-registry.php

     
     1<?php
     2/**
     3 * WP_Block_Type_Registry Tests
     4 *
     5 * @package WordPress
     6 * @subpackage Blocks
     7 * @since 5.0.0
     8 */
     9
     10/**
     11 * Tests for WP_Block_Type_Registry
     12 *
     13 * @since 5.0.0
     14 *
     15 * @group blocks
     16 */
     17class WP_Test_Block_Type_Registry extends WP_UnitTestCase {
     18
     19        /**
     20         * Fake block type registry.
     21         *
     22         * @since 5.0.0
     23         * @var WP_Block_Type_Registry
     24         */
     25        private $registry = null;
     26
     27        /**
     28         * Set up each test method.
     29         *
     30         * @since 5.0.0
     31         */
     32        public function setUp() {
     33                parent::setUp();
     34
     35                $this->registry = new WP_Block_Type_Registry();
     36        }
     37
     38        /**
     39         * Tear down each test method.
     40         *
     41         * @since 5.0.0
     42         */
     43        public function tearDown() {
     44                parent::tearDown();
     45
     46                $this->registry = null;
     47        }
     48
     49        /**
     50         * Should reject numbers
     51         *
     52         * @ticket 45097
     53         *
     54         * @expectedIncorrectUsage WP_Block_Type_Registry::register
     55         */
     56        public function test_invalid_non_string_names() {
     57                $result = $this->registry->register( 1, array() );
     58                $this->assertFalse( $result );
     59        }
     60
     61        /**
     62         * Should reject blocks without a namespace
     63         *
     64         * @ticket 45097
     65         *
     66         * @expectedIncorrectUsage WP_Block_Type_Registry::register
     67         */
     68        public function test_invalid_names_without_namespace() {
     69                $result = $this->registry->register( 'paragraph', array() );
     70                $this->assertFalse( $result );
     71        }
     72
     73        /**
     74         * Should reject blocks with invalid characters
     75         *
     76         * @ticket 45097
     77         *
     78         * @expectedIncorrectUsage WP_Block_Type_Registry::register
     79         */
     80        public function test_invalid_characters() {
     81                $result = $this->registry->register( 'still/_doing_it_wrong', array() );
     82                $this->assertFalse( $result );
     83        }
     84
     85        /**
     86         * Should reject blocks with uppercase characters
     87         *
     88         * @ticket 45097
     89         *
     90         * @expectedIncorrectUsage WP_Block_Type_Registry::register
     91         */
     92        public function test_uppercase_characters() {
     93                $result = $this->registry->register( 'Core/Paragraph', array() );
     94                $this->assertFalse( $result );
     95        }
     96
     97        /**
     98         * Should accept valid block names
     99         *
     100         * @ticket 45097
     101         */
     102        public function test_register_block_type() {
     103                $name     = 'core/paragraph';
     104                $settings = array(
     105                        'icon' => 'editor-paragraph',
     106                );
     107
     108                $block_type = $this->registry->register( $name, $settings );
     109                $this->assertEquals( $name, $block_type->name );
     110                $this->assertEquals( $settings['icon'], $block_type->icon );
     111                $this->assertEquals( $block_type, $this->registry->get_registered( $name ) );
     112        }
     113
     114        /**
     115         * Should fail to re-register the same block
     116         *
     117         * @ticket 45097
     118         *
     119         * @expectedIncorrectUsage WP_Block_Type_Registry::register
     120         */
     121        public function test_register_block_type_twice() {
     122                $name     = 'core/paragraph';
     123                $settings = array(
     124                        'icon' => 'editor-paragraph',
     125                );
     126
     127                $result = $this->registry->register( $name, $settings );
     128                $this->assertNotFalse( $result );
     129                $result = $this->registry->register( $name, $settings );
     130                $this->assertFalse( $result );
     131        }
     132
     133        /**
     134         * Should accept a WP_Block_Type instance
     135         *
     136         * @ticket 45097
     137         */
     138        public function test_register_block_type_instance() {
     139                $block_type = new WP_Fake_Block_Type( 'core/fake' );
     140
     141                $result = $this->registry->register( $block_type );
     142                $this->assertSame( $block_type, $result );
     143        }
     144
     145        /**
     146         * Unregistering should fail if a block is not registered
     147         *
     148         * @ticket 45097
     149         *
     150         * @expectedIncorrectUsage WP_Block_Type_Registry::unregister
     151         */
     152        public function test_unregister_not_registered_block() {
     153                $result = $this->registry->unregister( 'core/unregistered' );
     154                $this->assertFalse( $result );
     155        }
     156
     157        /**
     158         * Should unregister existing blocks
     159         *
     160         * @ticket 45097
     161         */
     162        public function test_unregister_block_type() {
     163                $name     = 'core/paragraph';
     164                $settings = array(
     165                        'icon' => 'editor-paragraph',
     166                );
     167
     168                $this->registry->register( $name, $settings );
     169                $block_type = $this->registry->unregister( $name );
     170                $this->assertEquals( $name, $block_type->name );
     171                $this->assertEquals( $settings['icon'], $block_type->icon );
     172                $this->assertFalse( $this->registry->is_registered( $name ) );
     173        }
     174
     175        /**
     176         * @ticket 45097
     177         */
     178        public function test_get_all_registered() {
     179                $names    = array( 'core/paragraph', 'core/image', 'core/blockquote' );
     180                $settings = array(
     181                        'icon' => 'random',
     182                );
     183
     184                foreach ( $names as $name ) {
     185                        $this->registry->register( $name, $settings );
     186                }
     187
     188                $registered = $this->registry->get_all_registered();
     189                $this->assertEqualSets( $names, array_keys( $registered ) );
     190        }
     191}
  • tests/phpunit/tests/blocks/block-type.php

     
     1<?php
     2/**
     3 * WP_Block_Type Tests
     4 *
     5 * @package WordPress
     6 * @subpackage Blocks
     7 * @since 5.0.0
     8 */
     9
     10/**
     11 * Tests for WP_Block_Type
     12 *
     13 * @since 5.0.0
     14 *
     15 * @group blocks
     16 */
     17class WP_Test_Block_Type extends WP_UnitTestCase {
     18
     19        /**
     20         * Editor user ID.
     21         *
     22         * @since 5.0.0
     23         * @var int
     24         */
     25        protected static $editor_user_id;
     26
     27        /**
     28         * ID for a post containing blocks.
     29         *
     30         * @since 5.0.0
     31         * @var int
     32         */
     33        protected static $post_with_blocks;
     34
     35        /**
     36         * ID for a post without blocks.
     37         *
     38         * @since 5.0.0
     39         * @var int
     40         */
     41        protected static $post_without_blocks;
     42
     43        /**
     44         * Set up before class.
     45         *
     46         * @since 5.0.0
     47         */
     48        public static function wpSetUpBeforeClass() {
     49                self::$editor_user_id = self::factory()->user->create(
     50                        array(
     51                                'role' => 'editor',
     52                        )
     53                );
     54
     55                self::$post_with_blocks = self::factory()->post->create(
     56                        array(
     57                                'post_title'   => 'Example',
     58                                'post_content' => "<!-- wp:core/text {\"dropCap\":true} -->\n<p class=\"has-drop-cap\">Tester</p>\n<!-- /wp:core/text -->",
     59                        )
     60                );
     61
     62                self::$post_without_blocks = self::factory()->post->create(
     63                        array(
     64                                'post_title'   => 'Example',
     65                                'post_content' => 'Tester',
     66                        )
     67                );
     68        }
     69
     70        /**
     71         * @ticket 45097
     72         */
     73        public function test_set_props() {
     74                $name = 'core/fake';
     75                $args = array(
     76                        'render_callback' => array( $this, 'render_fake_block' ),
     77                        'foo'             => 'bar',
     78                );
     79
     80                $block_type = new WP_Block_Type( $name, $args );
     81
     82                $this->assertSame( $name, $block_type->name );
     83                $this->assertSame( $args['render_callback'], $block_type->render_callback );
     84                $this->assertSame( $args['foo'], $block_type->foo );
     85        }
     86
     87        /**
     88         * @ticket 45097
     89         */
     90        public function test_render() {
     91                $attributes = array(
     92                        'foo' => 'bar',
     93                        'bar' => 'foo',
     94                );
     95
     96                $block_type = new WP_Block_Type(
     97                        'core/fake',
     98                        array(
     99                                'render_callback' => array( $this, 'render_fake_block' ),
     100                        )
     101                );
     102                $output     = $block_type->render( $attributes );
     103                $this->assertEquals( $attributes, json_decode( $output, true ) );
     104        }
     105
     106        /**
     107         * @ticket 45097
     108         */
     109        public function test_render_with_content() {
     110                $attributes = array(
     111                        'foo' => 'bar',
     112                        'bar' => 'foo',
     113                );
     114
     115                $content = 'baz';
     116
     117                $expected = array_merge( $attributes, array( '_content' => $content ) );
     118
     119                $block_type = new WP_Block_Type(
     120                        'core/fake',
     121                        array(
     122                                'render_callback' => array( $this, 'render_fake_block_with_content' ),
     123                        )
     124                );
     125                $output     = $block_type->render( $attributes, $content );
     126                $this->assertEquals( $expected, json_decode( $output, true ) );
     127        }
     128
     129        /**
     130         * @ticket 45097
     131         */
     132        public function test_render_for_static_block() {
     133                $block_type = new WP_Block_Type( 'core/fake', array() );
     134                $output     = $block_type->render();
     135
     136                $this->assertEquals( '', $output );
     137        }
     138
     139        /**
     140         * @ticket 45097
     141         */
     142        public function test_is_dynamic_for_static_block() {
     143                $block_type = new WP_Block_Type( 'core/fake', array() );
     144
     145                $this->assertFalse( $block_type->is_dynamic() );
     146        }
     147
     148        /**
     149         * @ticket 45097
     150         */
     151        public function test_is_dynamic_for_dynamic_block() {
     152                $block_type = new WP_Block_Type(
     153                        'core/fake',
     154                        array(
     155                                'render_callback' => array( $this, 'render_fake_block' ),
     156                        )
     157                );
     158
     159                $this->assertTrue( $block_type->is_dynamic() );
     160        }
     161
     162        /**
     163         * @ticket 45097
     164         */
     165        public function test_prepare_attributes() {
     166                $attributes = array(
     167                        'correct'            => 'include',
     168                        'wrongType'          => 5,
     169                        'wrongTypeDefaulted' => 5,
     170                        /* missingDefaulted */
     171                        'undefined'          => 'omit',
     172                );
     173
     174                $block_type = new WP_Block_Type(
     175                        'core/fake',
     176                        array(
     177                                'attributes' => array(
     178                                        'correct'            => array(
     179                                                'type' => 'string',
     180                                        ),
     181                                        'wrongType'          => array(
     182                                                'type' => 'string',
     183                                        ),
     184                                        'wrongTypeDefaulted' => array(
     185                                                'type'    => 'string',
     186                                                'default' => 'defaulted',
     187                                        ),
     188                                        'missingDefaulted'   => array(
     189                                                'type'    => 'string',
     190                                                'default' => 'define',
     191                                        ),
     192                                ),
     193                        )
     194                );
     195
     196                $prepared_attributes = $block_type->prepare_attributes_for_render( $attributes );
     197
     198                $this->assertEquals(
     199                        array(
     200                                'correct'            => 'include',
     201                                'wrongType'          => null,
     202                                'wrongTypeDefaulted' => 'defaulted',
     203                                'missingDefaulted'   => 'define',
     204                        ),
     205                        $prepared_attributes
     206                );
     207        }
     208
     209        /**
     210         * @ticket 45097
     211         */
     212        public function test_has_block_with_mixed_content() {
     213                $mixed_post_content = 'before' .
     214                '<!-- wp:core/fake --><!-- /wp:core/fake -->' .
     215                '<!-- wp:core/fake_atts {"value":"b1"} --><!-- /wp:core/fake_atts -->' .
     216                '<!-- wp:core/fake-child -->
     217                <p>testing the test</p>
     218                <!-- /wp:core/fake-child -->' .
     219                'between' .
     220                '<!-- wp:core/self-close-fake /-->' .
     221                '<!-- wp:custom/fake {"value":"b2"} /-->' .
     222                'after';
     223
     224                $this->assertTrue( has_block( 'core/fake', $mixed_post_content ) );
     225
     226                $this->assertTrue( has_block( 'core/fake_atts', $mixed_post_content ) );
     227
     228                $this->assertTrue( has_block( 'core/fake-child', $mixed_post_content ) );
     229
     230                $this->assertTrue( has_block( 'core/self-close-fake', $mixed_post_content ) );
     231
     232                $this->assertTrue( has_block( 'custom/fake', $mixed_post_content ) );
     233
     234                // checking for a partial block name should fail.
     235                $this->assertFalse( has_block( 'core/fak', $mixed_post_content ) );
     236
     237                // checking for a wrong namespace should fail.
     238                $this->assertFalse( has_block( 'custom/fake_atts', $mixed_post_content ) );
     239
     240                // checking for namespace only should not work. Or maybe ... ?
     241                $this->assertFalse( has_block( 'core', $mixed_post_content ) );
     242        }
     243
     244        /**
     245         * @ticket 45097
     246         */
     247        public function test_has_block_with_invalid_content() {
     248                // some content with invalid HMTL comments and a single valid block.
     249                $invalid_content = 'before' .
     250                '<!- - wp:core/weird-space --><!-- /wp:core/weird-space -->' .
     251                '<!--wp:core/untrimmed-left --><!-- /wp:core/untrimmed -->' .
     252                '<!-- wp:core/fake --><!-- /wp:core/fake -->' .
     253                '<!-- wp:core/untrimmed-right--><!-- /wp:core/untrimmed2 -->' .
     254                'after';
     255
     256                $this->assertFalse( has_block( 'core/text', self::$post_without_blocks ) );
     257
     258                $this->assertFalse( has_block( 'core/weird-space', $invalid_content ) );
     259
     260                $this->assertFalse( has_block( 'core/untrimmed-left', $invalid_content ) );
     261
     262                $this->assertFalse( has_block( 'core/untrimmed-right', $invalid_content ) );
     263
     264                $this->assertTrue( has_block( 'core/fake', $invalid_content ) );
     265        }
     266
     267        /**
     268         * @ticket 45097
     269         */
     270        public function test_post_has_block() {
     271                // should fail for a non-existent block `custom/fake`.
     272                $this->assertFalse( has_block( 'custom/fake', self::$post_with_blocks ) );
     273
     274                // this functions should not work without the second param until the $post global is set.
     275                $this->assertFalse( has_block( 'core/text' ) );
     276                $this->assertFalse( has_block( 'core/fake' ) );
     277
     278                global $post;
     279                $post = get_post( self::$post_with_blocks );
     280
     281                // check if the function correctly detects content from the $post global.
     282                $this->assertTrue( has_block( 'core/text' ) );
     283                // even if it detects a proper $post global it should still be false for a missing block.
     284                $this->assertFalse( has_block( 'core/fake' ) );
     285        }
     286
     287        /**
     288         * Renders a test block without content.
     289         *
     290         * @since 5.0.0
     291         *
     292         * @param array $attributes Block attributes. Default empty array.
     293         * @return string JSON encoded list of attributes.
     294         */
     295        public function render_fake_block( $attributes ) {
     296                return json_encode( $attributes );
     297        }
     298
     299        /**
     300         * Renders a test block with content.
     301         *
     302         * @since 5.0.0
     303         *
     304         * @param array  $attributes Block attributes. Default empty array.
     305         * @param string $content    Block content. Default empty string.
     306         * @return string JSON encoded list of attributes.
     307         */
     308        public function render_fake_block_with_content( $attributes, $content ) {
     309                $attributes['_content'] = $content;
     310
     311                return json_encode( $attributes );
     312        }
     313}