Skip to content
Draft
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
3 changes: 3 additions & 0 deletions backport-changelog/7.0/11410.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
https://github.com/WordPress/wordpress-develop/pull/11410

* https://github.com/WordPress/gutenberg/pull/77344
19 changes: 19 additions & 0 deletions lib/compat/wordpress-7.0/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,22 @@ function gutenberg_update_tax_query_of_query_loop_block( $query, $block ) {
}

add_filter( 'query_loop_block_query_vars', 'gutenberg_update_tax_query_of_query_loop_block', 10, 2 );

/**
* Add the `_wp_ignored_hooked_blocks` post meta to the REST API response for content-like post types.
*
* @param WP_REST_Response $response The REST API response.
* @param WP_Post $post The post object.
* @return WP_REST_Response The modified REST API response.
*/
function gutenberg_set_wp_ignored_hooked_blocks_post_meta_in_rest_response( $response, $post ) {
$updated_post = update_ignored_hooked_blocks_postmeta( (object) $post );
if ( ! empty( $updated_post->meta_input['_wp_ignored_hooked_blocks'] ) ) {
$response->data['meta']['_wp_ignored_hooked_blocks'] = $updated_post->meta_input['_wp_ignored_hooked_blocks'];
}
return $response;
}
add_filter( 'rest_prepare_page', 'gutenberg_set_wp_ignored_hooked_blocks_post_meta_in_rest_response', 11, 2 );
add_filter( 'rest_prepare_post', 'gutenberg_set_wp_ignored_hooked_blocks_post_meta_in_rest_response', 11, 2 );
add_filter( 'rest_prepare_wp_block', 'gutenberg_set_wp_ignored_hooked_blocks_post_meta_in_rest_response', 11, 2 );
add_filter( 'rest_prepare_wp_navigation', 'gutenberg_set_wp_ignored_hooked_blocks_post_meta_in_rest_response', 11, 2 );
232 changes: 123 additions & 109 deletions test/e2e/specs/editor/plugins/block-hooks.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@
*/
const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' );

/**
* Internal dependencies
*/
const {
setCollaboration,
} = require( '../../editor/collaboration/fixtures/collaboration-utils' );

const dummyBlocksContent = `<!-- wp:heading -->
<h2 class="wp-block-heading">This is a dummy heading</h2>
<!-- /wp:heading -->
Expand Down Expand Up @@ -73,12 +66,6 @@ test.describe( 'Block Hooks API', () => {
} else {
containerPost = postObject;
}

/**
* Since the Block Hooks API relies on server-side rendering to insert
* the hooked blocks, there is a fundamental incompatibility with RTC.
*/
await setCollaboration( requestUtils, false );
} );

test.afterAll( async ( { requestUtils } ) => {
Expand All @@ -88,7 +75,6 @@ test.describe( 'Block Hooks API', () => {

await requestUtils.deleteAllPosts();
await requestUtils.deleteAllBlocks();
await setCollaboration( requestUtils, true );
} );

test( `should insert hooked blocks into ${ name } on frontend`, async ( {
Expand Down Expand Up @@ -132,55 +118,73 @@ test.describe( 'Block Hooks API', () => {
},
};

await admin.editPost( postObject.id );
await expect
.poll( editor.getBlocks )
.toMatchObject( [
{ name: 'core/heading' },
expectedHookedBlockAfterHeading,
{ name: 'core/paragraph' },
expectedHookedBlockLastChild,
] );
await test.step( 'Editor contains the hooked blocks in the expected positions', async () => {
await admin.editPost( postObject.id );
await expect
.poll( editor.getBlocks )
.toMatchObject( [
{ name: 'core/heading' },
expectedHookedBlockAfterHeading,
{ name: 'core/paragraph' },
expectedHookedBlockLastChild,
] );
} );

const hookedBlock = editor.canvas.getByText(
getHookedBlockContent( 'last_child', blockType )
);
await editor.selectBlocks( hookedBlock );
await editor.clickBlockToolbarButton( 'Move up' );

// Save updated post.
const saveButton = page
.getByRole( 'region', { name: 'Editor top bar' } )
.getByRole( 'button', { name: 'Save', exact: true } );
await saveButton.click();
await page
.getByRole( 'button', { name: 'Dismiss this notice' } )
.filter( { hasText: 'updated' } )
.waitFor();

// Reload and verify that the new position of the hooked block has been persisted.
await page.reload();
await expect
.poll( editor.getBlocks )
.toMatchObject( [
{ name: 'core/heading' },
expectedHookedBlockAfterHeading,
expectedHookedBlockLastChild,
{ name: 'core/paragraph' },
] );
await test.step( "Hooked blocks aren't duplicated in the editor after a reload", async () => {
await page.reload();
await expect
.poll( editor.getBlocks )
.not.toMatchObject( [
{ name: 'core/heading' },
expectedHookedBlockAfterHeading,
{ name: 'core/paragraph' },
expectedHookedBlockLastChild,
expectedHookedBlockLastChild,
] );
} );

// Verify that the frontend reflects the changes made in the editor.
await page.goto( `/?p=${ containerPost.id }` );
await expect(
page.locator( '.entry-content > *' )
).toHaveClass( [
'wp-block-heading',
getHookedBlockClassName( 'after', 'core/heading' ) +
' wp-block-paragraph',
getHookedBlockClassName( 'last_child', blockType ) +
' wp-block-paragraph',
'dummy-paragraph wp-block-paragraph',
] );
await test.step( 'Moving the last hooked block is persisted upon save', async () => {
const hookedBlock = editor.canvas.getByText(
getHookedBlockContent( 'last_child', blockType )
);
await editor.selectBlocks( hookedBlock );
await editor.clickBlockToolbarButton( 'Move up' );

// Save updated post.
const saveButton = page
.getByRole( 'region', { name: 'Editor top bar' } )
.getByRole( 'button', { name: 'Save', exact: true } );
await saveButton.click();
await page
.getByRole( 'button', { name: 'Dismiss this notice' } )
.filter( { hasText: 'updated' } )
.waitFor();

// Reload and verify that the new position of the hooked block has been persisted.
await page.reload();
await expect
.poll( editor.getBlocks )
.toMatchObject( [
{ name: 'core/heading' },
expectedHookedBlockAfterHeading,
expectedHookedBlockLastChild,
{ name: 'core/paragraph' },
] );
} );

await test.step( 'Frontend reflects the changes made in the editor', async () => {
await page.goto( `/?p=${ containerPost.id }` );
await expect(
page.locator( '.entry-content > *' )
).toHaveClass( [
'wp-block-heading',
getHookedBlockClassName( 'after', 'core/heading' ) +
' wp-block-paragraph',
getHookedBlockClassName( 'last_child', blockType ) +
' wp-block-paragraph',
'dummy-paragraph wp-block-paragraph',
] );
} );
} );
} );

Expand Down Expand Up @@ -214,12 +218,6 @@ test.describe( 'Block Hooks API', () => {
} else {
containerPost = postObject;
}

/**
* Since the Block Hooks API relies on server-side rendering to insert
* the hooked blocks, there is a fundamental incompatibility with RTC.
*/
await setCollaboration( requestUtils, false );
} );

test.afterAll( async ( { requestUtils } ) => {
Expand All @@ -229,7 +227,6 @@ test.describe( 'Block Hooks API', () => {

await requestUtils.deleteAllPosts();
await requestUtils.deleteAllBlocks();
await setCollaboration( requestUtils, true );
} );

test( `should insert hooked blocks into ${ name } on frontend`, async ( {
Expand Down Expand Up @@ -261,49 +258,66 @@ test.describe( 'Block Hooks API', () => {
},
};

await admin.editPost( postObject.id );
await expect
.poll( editor.getBlocks )
.toMatchObject( [
{ name: 'core/freeform' },
expectedHookedBlockLastChild,
] );
await test.step( 'Editor contains the hooked block in the expected position', async () => {
await admin.editPost( postObject.id );
await expect
.poll( editor.getBlocks )
.toMatchObject( [
{ name: 'core/freeform' },
expectedHookedBlockLastChild,
] );
} );

const hookedBlock = editor.canvas.getByText(
getHookedBlockContent( 'last_child', blockType )
);
await editor.selectBlocks( hookedBlock );
await editor.clickBlockToolbarButton( 'Move up' );

// Save updated post.
const saveButton = page
.getByRole( 'region', { name: 'Editor top bar' } )
.getByRole( 'button', { name: 'Save', exact: true } );
await saveButton.click();
await page
.getByRole( 'button', { name: 'Dismiss this notice' } )
.filter( { hasText: 'updated' } )
.waitFor();

// Reload and verify that the new position of the hooked block has been persisted.
await page.reload();
await expect
.poll( editor.getBlocks )
.toMatchObject( [
expectedHookedBlockLastChild,
{ name: 'core/freeform' },
] );
await test.step( "Hooked block isn't duplicated in the editor after a reload", async () => {
await page.reload();
await expect
.poll( editor.getBlocks )
.not.toMatchObject( [
{ name: 'core/freeform' },
expectedHookedBlockLastChild,
expectedHookedBlockLastChild,
] );
} );

// Verify that the frontend reflects the changes made in the editor.
await page.goto( `/?p=${ containerPost.id }` );
await expect(
page.locator( '.entry-content > *' )
).toHaveClass( [
getHookedBlockClassName( 'last_child', blockType ) +
' wp-block-paragraph',
'dummy-classic-heading',
'dummy-classic-paragraph',
] );
await test.step( 'Moving the last hooked block is persisted upon save', async () => {
const hookedBlock = editor.canvas.getByText(
getHookedBlockContent( 'last_child', blockType )
);
await editor.selectBlocks( hookedBlock );
await editor.clickBlockToolbarButton( 'Move up' );

// Save updated post.
const saveButton = page
.getByRole( 'region', { name: 'Editor top bar' } )
.getByRole( 'button', { name: 'Save', exact: true } );
await saveButton.click();
await page
.getByRole( 'button', { name: 'Dismiss this notice' } )
.filter( { hasText: 'updated' } )
.waitFor();

// Reload and verify that the new position of the hooked block has been persisted.
await page.reload();
await expect
.poll( editor.getBlocks )
.toMatchObject( [
expectedHookedBlockLastChild,
{ name: 'core/freeform' },
] );
} );

await test.step( 'Frontend reflects the changes made in the editor', async () => {
// Verify that the frontend reflects the changes made in the editor.
await page.goto( `/?p=${ containerPost.id }` );
await expect(
page.locator( '.entry-content > *' )
).toHaveClass( [
getHookedBlockClassName( 'last_child', blockType ) +
' wp-block-paragraph',
'dummy-classic-heading',
'dummy-classic-paragraph',
] );
} );
} );
} );
} );
Expand Down
Loading