Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pattern Directory: Allow container blocks to pass validation if they have child-blocks #85

Merged
merged 6 commits into from
Apr 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,63 @@
add_filter( 'rest_pre_insert_' . POST_TYPE, __NAMESPACE__ . '\validate_content', 10, 2 );
add_filter( 'rest_pre_insert_' . POST_TYPE, __NAMESPACE__ . '\validate_title', 11, 2 );

/**
* Strip out basic HTML to get at the manually-entered content in block content.
*
* First, remove class attributes, since custom class names will be caught by attribute checks.
* Next, remove empty alt tags, which are present on default image blocks.
* Lastly, remove any HTML tags without attributes- this regex catches opening, closing, and self-closing tags.
* After all this, any block_content left should be there intentionally by the author.
*
* @param string $html The block content, from `innerHTML` of a parsed block.
* @return string Any content that doesn't match the cases described above.
*/
function strip_basic_html( $html ) {
$to_replace = array( '/class="[^"]*"/', '/alt=""/', '/<\/?[a-zA-Z]+\s*\/?>/' );
return trim( preg_replace( $to_replace, '', $html ) );
}

/**
* Check if a block has been edited by the user, as opposed to an empty/placeholder block.
*
* @param array $block A parsed block object.
* @return bool Whether the block has been edited.
*/
function is_not_empty_block( $block ) {
$registry = \WP_Block_Type_Registry::get_instance();
$block_type = $registry->get_registered( $block['blockName'] );

// Paragraphs are a special case, these should never be empty.
if ( 'core/paragraph' === $block['blockName'] ) {
$block_content = strip_basic_html( $block['innerHTML'] );
if ( empty( $block_content ) ) {
return false;
}
}

// Check if the attributes are different from the default attributes.
$block_attrs = $block_type->prepare_attributes_for_render( $block['attrs'] );
$default_attrs = $block_type->prepare_attributes_for_render( array() );
if ( $block_attrs != $default_attrs ) {
return true;
}

// If there are any child blocks, check those. Only return if there are real child blocks,
// otherwise continue on to check for any other content.
if ( count( $block['innerBlocks'] ) >= 1 ) {
$child_blocks = array_filter( $block['innerBlocks'], __NAMESPACE__ . '\is_not_empty_block' );
if ( count( $child_blocks ) ) {
return true;
}
}

$block_content = strip_basic_html( $block['innerHTML'] );
if ( ! empty( $block_content ) ) {
return true;
}
return false;
}

/**
* Validate the pattern content.
*/
Expand Down Expand Up @@ -43,28 +100,7 @@ function validate_content( $prepared_post, $request ) {
}

// Next, we should check that we have at least one non-empty block.
$real_blocks = array_filter( $blocks, function( $block ) use ( $registry ) {
$block_type = $registry->get_registered( $block['blockName'] );

// Check if the attributes are different from the default attributes.
$block_attrs = $block_type->prepare_attributes_for_render( $block['attrs'] );
$default_attrs = $block_type->prepare_attributes_for_render( array() );
if ( $block_attrs != $default_attrs ) {
return true;
}

// Try to judge whether a block has text content, or a valid image.
// First, remove class attributes, since custom class names would be caught above.
// Next, remove empty alt tags, which are present on default image blocks.
// Lastly, remove HTML tags without attributes- this regex catches opening, closing, and self-closing tags.
// After all this, any block_content left should be there intentionally by the author.
$to_replace = array( '/class="[^"]*"/', '/alt=""/', '/<\/?[a-zA-Z]+\s*\/?>/' );
$block_content = trim( preg_replace( $to_replace, '', $block['innerHTML'] ) );
if ( ! empty( $block_content ) ) {
return true;
}
return false;
} );
$real_blocks = array_filter( $blocks, __NAMESPACE__ . '\is_not_empty_block' );

if ( ! count( $real_blocks ) ) {
return new \WP_Error(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,6 @@ public function test_valid_simple_block() {
$this->assertFalse( $response->is_error() );
}

/**
* Test valid block content: empty paragraph, with a class.
*/
public function test_valid_block_with_class() {
wp_set_current_user( self::$user );
$response = $this->save_block_content(
"<!-- wp:paragraph {\"className\":\"foo\"} -->\n<p class=\"foo\"></p>\n<!-- /wp:paragraph -->"
);
$this->assertFalse( $response->is_error() );
}

/**
* Test valid block content: paragraph with only an image.
*/
Expand Down Expand Up @@ -106,13 +95,35 @@ public function test_valid_extra_empty_paragraph_end() {
* Test valid block content: a group block with an image.
*/
public function test_valid_group_block() {
wp_set_current_user( self::$user );
$response = $this->save_block_content(
"<!-- wp:group -->\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container\"><!-- wp:image {\"sizeSlug\":\"large\"} -->\n<figure class=\"wp-block-image size-large\"><img src=\"https://s.w.org/style/images/wporg-logo.svg?3\" alt=\"\"/></figure>\n<!-- /wp:image --></div></div>\n<!-- /wp:group -->"
);
$this->assertFalse( $response->is_error() );
}

/**
* Test valid block content: a group block with an image and a background color.
*/
public function test_valid_group_block_with_color() {
wp_set_current_user( self::$user );
$response = $this->save_block_content(
"<!-- wp:group {\"backgroundColor\":\"black\",\"textColor\":\"cyan-bluish-gray\"} -->\n<div class=\"wp-block-group has-cyan-bluish-gray-color has-black-background-color has-text-color has-background\"><div class=\"wp-block-group__inner-container\"><!-- wp:image {\"sizeSlug\":\"large\"} -->\n<figure class=\"wp-block-image size-large\"><img src=\"https://s.w.org/style/images/wporg-logo.svg?3\" alt=\"\"/></figure>\n<!-- /wp:image --></div></div>\n<!-- /wp:group -->"
);
$this->assertFalse( $response->is_error() );
}

/**
* Test valid block content: two columns, one empty, should still be valid.
*/
public function test_valid_columns_block() {
wp_set_current_user( self::$user );
$response = $this->save_block_content(
"<!-- wp:columns -->\n<div class=\"wp-block-columns\"><!-- wp:column -->\n<div class=\"wp-block-column\"><!-- wp:spacer -->\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"></div>\n<!-- /wp:spacer -->\n\n<!-- wp:paragraph {\"style\":{\"typography\":{\"fontSize\":\"21px\"},\"color\":{\"text\":\"#000000\"}}} -->\n<p class=\"has-text-color\" style=\"color:#000000;font-size:21px\"><strong>We have worked with:</strong></p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph {\"style\":{\"typography\":{\"fontSize\":\"24px\",\"lineHeight\":\"1.2\"}}} -->\n<p style=\"font-size:24px;line-height:1.2\"><a href=\"https://wordpress.org\">EARTHFUND™<br>ARCHWEEKLY<br>FUTURE ROADS<br>BUILDING NY</a></p>\n<!-- /wp:paragraph -->\n\n<!-- wp:spacer -->\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"></div>\n<!-- /wp:spacer --></div>\n<!-- /wp:column -->\n\n<!-- wp:column -->\n<div class=\"wp-block-column\"></div>\n<!-- /wp:column --></div>\n<!-- /wp:columns -->"
);
$this->assertFalse( $response->is_error() );
}

/**
* Test valid block content: an audio block.
*/
Expand Down Expand Up @@ -168,6 +179,19 @@ public function test_invalid_empty_paragraphs() {
$this->assertSame( 'rest_pattern_empty_blocks', $data['code'] );
}

/**
* Test invalid block content: empty paragraph, with a class.
*/
public function test_invalid_block_with_class() {
wp_set_current_user( self::$user );
$response = $this->save_block_content(
"<!-- wp:paragraph {\"className\":\"foo\"} -->\n<p class=\"foo\"></p>\n<!-- /wp:paragraph -->"
);
$this->assertTrue( $response->is_error() );
$data = $response->get_data();
$this->assertSame( 'rest_pattern_empty_blocks', $data['code'] );
}

/**
* Test invalid block content: empty list (not default).
*/
Expand Down Expand Up @@ -217,7 +241,7 @@ public function test_invalid_empty_media_text_block() {
}

/**
* Test invalid block content: an empty media & text block.
* Test invalid block content: a block that doesn't exist on this site.
*/
public function test_invalid_fake_block() {
wp_set_current_user( self::$user );
Expand Down