diff --git a/lib/class-wp-block.php b/lib/class-wp-block.php index 4e3cf5f17989d0..7374d4f6eafcaa 100644 --- a/lib/class-wp-block.php +++ b/lib/class-wp-block.php @@ -8,7 +8,7 @@ /** * Class representing a parsed instance of a block. */ -class WP_Block implements ArrayAccess { +class WP_Block implements ArrayAccess, JsonSerializable, Serializable, IteratorAggregate, Countable { /** * Name of block. @@ -177,6 +177,10 @@ public function render() { return $block_content; } + /* + * ArrayAccess interface methods. + */ + /** * Returns true if an attribute exists by the specified attribute name, or * false otherwise. @@ -201,9 +205,11 @@ public function offsetExists( $attribute_name ) { * @return mixed|null Attribute value if exists, or null. */ public function offsetGet( $attribute_name ) { - // This may cause an "Undefined index" notice if the attribute name does - // not exist. This is expected, since the purpose of this implementation - // is to align exactly to the expectations of operating on an array. + /* + * This may cause an "Undefined index" notice if the attribute name does + * not exist. This is expected, since the purpose of this implementation + * is to align exactly to the expectations of operating on an array. + */ return $this->attributes[ $attribute_name ]; } @@ -217,9 +223,11 @@ public function offsetGet( $attribute_name ) { */ public function offsetSet( $attribute_name, $value ) { if ( is_null( $attribute_name ) ) { - // This is not technically a valid use-case for attributes. Since - // this implementation is expected to align to expectations of - // operating on an array, it is still supported. + /* + * This is not technically a valid use-case for attributes. Since + * this implementation is expected to align to expectations of + * operating on an array, it is still supported. + */ $this->attributes[] = $value; } else { $this->attributes[ $attribute_name ] = $value; @@ -237,4 +245,77 @@ public function offsetUnset( $attribute_name ) { unset( $this->attributes[ $attribute_name ] ); } + /* + * Serializable interface methods. + */ + + /** + * Returns the string representation of the block attributes. + * + * @link https://www.php.net/manual/en/serializable.serialize.php + * + * @return string String representation of the block attributes. + */ + public function serialize() { + return serialize( $this->attributes ); + } + + /** + * Constructs the object from a serialized representation of block + * attributes. + * + * @link https://www.php.net/manual/en/serializable.unserialize.php + * + * @param string The string representation of the block attributes. + */ + public function unserialize( $serialized ) { + $this->attributes = unserialize( $serialized ); + } + + /* + * JsonSerializable interface methods. + */ + + /** + * Serializes the object to an array of attributes that can be serialized + * natively by json_encode(). + * + * @link https://www.php.net/manual/en/jsonserializable.jsonserialize.php + * + * @return array Array data which can be serialized by json_encode(). + */ + public function jsonSerialize() { + return $this->attributes; + } + + /* + * IteratorAggregate interface methods. + */ + + /** + * Returns an iterator of the block attributes. + * + * @link https://www.php.net/manual/en/iteratoraggregate.getiterator.php + * + * @return Traversable Attributes iterator. + */ + public function getIterator() { + return new ArrayIterator( $this->attributes ); + } + + /* + * Countable interface methods. + */ + + /** + * Returns the count of the block attributes. + * + * @link https://www.php.net/manual/en/countable.count.php + * + * @return int Count of the block attributes. + */ + public function count() { + return count( $this->attributes ); + } + } diff --git a/phpunit/class-wp-block-test.php b/phpunit/class-wp-block-test.php index 242f96f9eb462c..c45954dce39967 100644 --- a/phpunit/class-wp-block-test.php +++ b/phpunit/class-wp-block-test.php @@ -367,4 +367,95 @@ function test_array_access_attributes() { $this->assertEquals( 'invalid, but still supported', $block[0] ); } + function test_block_serializable_as_attributes_array() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'value' => array( + 'type' => 'string', + 'default' => 'ok', + ), + ), + ) + ); + + $parsed_block = array( 'blockName' => 'core/example' ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $result = serialize( $block ); + + $this->assertEquals( 'C:8:"WP_Block":27:{a:1:{s:5:"value";s:2:"ok";}}', $result ); + } + + function test_block_json_serializable_as_attributes_array() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'value' => array( + 'type' => 'string', + 'default' => 'ok', + ), + ), + ) + ); + + $parsed_block = array( 'blockName' => 'core/example' ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $result = json_encode( $block ); + + $this->assertEquals( '{"value":"ok"}', $result ); + } + + function test_iterable_as_attributes_array() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'value' => array( + 'type' => 'string', + 'default' => 'ok', + ), + ), + ) + ); + + $parsed_block = array( 'blockName' => 'core/example' ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $result_attributes = array(); + foreach ( $block as $key => $value ) { + $result_attributes[ $key ] = $value; + } + + $this->assertEquals( array( 'value' => 'ok' ), $result_attributes ); + } + + function test_countable_as_attributes_array() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'value' => array( + 'type' => 'string', + 'default' => 'ok', + ), + ), + ) + ); + + $parsed_block = array( 'blockName' => 'core/example' ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $result = count( $block ); + + $this->assertEquals( 1, $result ); + } + }