diff --git a/public_html/wp-content/plugins/pattern-directory/bootstrap.php b/public_html/wp-content/plugins/pattern-directory/bootstrap.php index ef7200d93..ac8e46f4b 100644 --- a/public_html/wp-content/plugins/pattern-directory/bootstrap.php +++ b/public_html/wp-content/plugins/pattern-directory/bootstrap.php @@ -9,3 +9,4 @@ namespace WordPressdotorg\Pattern_Directory; require_once __DIR__ . '/includes/pattern-post-type.php'; +require_once __DIR__ . '/includes/pattern-validation.php'; diff --git a/public_html/wp-content/plugins/pattern-directory/includes/pattern-validation.php b/public_html/wp-content/plugins/pattern-directory/includes/pattern-validation.php new file mode 100644 index 000000000..aa075ce4f --- /dev/null +++ b/public_html/wp-content/plugins/pattern-directory/includes/pattern-validation.php @@ -0,0 +1,73 @@ +post_content; + if ( ! $content ) { + return new \WP_Error( + 'rest_pattern_empty', + __( 'Pattern content cannot be empty.', 'wporg-patterns' ), + array( 'status' => 400 ) + ); + } + + // The editor adds in linebreaks between blocks, but parse_blocks thinks those are invalid blocks. + $content = str_replace( "\n\n", '', $content ); + $blocks = parse_blocks( $content ); + $registry = \WP_Block_Type_Registry::get_instance(); + + // $blocks contains a list of the blocks in the content. By default it will always have one item, even if it's + // not valid block content. Instead, we should check that each block in the list has a blockName. + $invalid_blocks = array_filter( $blocks, function( $block ) use ( $registry ) { + $block_type = $registry->get_registered( $block['blockName'] ); + return is_null( $block['blockName'] ) || is_null( $block_type ); + } ); + if ( count( $invalid_blocks ) ) { + return new \WP_Error( + 'rest_pattern_invalid_blocks', + __( 'Pattern content contains invalid blocks.', 'wporg-patterns' ), + array( 'status' => 400 ) + ); + } + + // 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; + } ); + + if ( ! count( $real_blocks ) ) { + return new \WP_Error( + 'rest_pattern_empty_blocks', + __( 'Pattern content contains only empty blocks.', 'wporg-patterns' ), + array( 'status' => 400 ) + ); + } + + return $prepared_post; +} diff --git a/public_html/wp-content/plugins/pattern-directory/tests/phpunit/basic-test.php b/public_html/wp-content/plugins/pattern-directory/tests/phpunit/basic-test.php deleted file mode 100644 index e05537093..000000000 --- a/public_html/wp-content/plugins/pattern-directory/tests/phpunit/basic-test.php +++ /dev/null @@ -1,20 +0,0 @@ -assertEquals( POST_TYPE, 'wporg-pattern' ); - } -} diff --git a/public_html/wp-content/plugins/pattern-directory/tests/phpunit/pattern-content-validation-test.php b/public_html/wp-content/plugins/pattern-directory/tests/phpunit/pattern-content-validation-test.php new file mode 100644 index 000000000..48945dcd4 --- /dev/null +++ b/public_html/wp-content/plugins/pattern-directory/tests/phpunit/pattern-content-validation-test.php @@ -0,0 +1,232 @@ +post->create( + array( 'post_type' => POST_TYPE ) + ); + self::$user = $factory->user->create( + array( + 'role' => 'administrator', + ) + ); + } + + /** + * Verify the pattern & API are set up correctly. + */ + public function test_pattern_directory_api() { + $request = new WP_REST_Request( 'GET', '/wp/v2/wporg-pattern/' . self::$pattern_id ); + $response = rest_do_request( $request ); + $this->assertFalse( $response->is_error() ); + } + + /** + * Helper function to handle REST requests to save the pattern. + */ + protected function save_block_content( $content ) { + $request = new WP_REST_Request( 'POST', '/wp/v2/wporg-pattern/' . self::$pattern_id ); + $request->set_header( 'content-type', 'application/json' ); + $request->set_body( json_encode( array( + 'content' => $content, + ) ) ); + return rest_do_request( $request ); + } + + /** + * Test valid block content: simple paragraph. + */ + public function test_valid_simple_block() { + wp_set_current_user( self::$user ); + $response = $this->save_block_content( + "\n
This is a block.
\n" + ); + $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( + "\n\n" + ); + $this->assertFalse( $response->is_error() ); + } + + /** + * Test valid block content: paragraph with only an image. + */ + public function test_valid_block_with_image() { + wp_set_current_user( self::$user ); + $response = $this->save_block_content( + "\nSome block content
\n" + ); + $this->assertFalse( $response->is_error() ); + } + + /** + * Test valid block content: real content with an extra empty paragraph (end). + */ + public function test_valid_extra_empty_paragraph_end() { + wp_set_current_user( self::$user ); + $response = $this->save_block_content( + "\nSome block content
\n\n\n" + ); + $this->assertFalse( $response->is_error() ); + } + + /** + * 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( + "\nThis is not blocks.
' ); + $this->assertTrue( $response->is_error() ); + $data = $response->get_data(); + $this->assertSame( 'rest_pattern_invalid_blocks', $data['code'] ); + } + + /** + * Test invalid block content: empty paragraph (default block). + */ + public function test_invalid_empty_paragraph() { + wp_set_current_user( self::$user ); + $response = $this->save_block_content( "\n\n" ); + $this->assertTrue( $response->is_error() ); + $data = $response->get_data(); + $this->assertSame( 'rest_pattern_empty_blocks', $data['code'] ); + } + + /** + * Test invalid block content: empty paragraphs (multiple). + */ + public function test_invalid_empty_paragraphs() { + wp_set_current_user( self::$user ); + $response = $this->save_block_content( "\n\n\n\n\n\n" ); + $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). + */ + public function test_invalid_empty_list() { + wp_set_current_user( self::$user ); + $response = $this->save_block_content( "\nThis is some content.
\n" + ); + $this->assertTrue( $response->is_error() ); + $data = $response->get_data(); + $this->assertSame( 'rest_pattern_invalid_blocks', $data['code'] ); + } +} +