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

createUpgradedEmbedBlock breaks when block type is unregistered #15883

Closed
swissspidy opened this issue May 29, 2019 · 0 comments · Fixed by #15885
Closed

createUpgradedEmbedBlock breaks when block type is unregistered #15883

swissspidy opened this issue May 29, 2019 · 0 comments · Fixed by #15885
Labels
[Block] Embed Affects the Embed Block [Block] Video Affects the Video Block [Feature] Block Transforms Block transforms from one block to another [Type] Bug An existing feature does not function as intended

Comments

@swissspidy
Copy link
Member

Describe the bug

When creating a Video block and pasting a YouTube URL in the "Insert from URL" field, the editor automatically creates a YouTube block for it.

Here's where this happens:

onSelectURL( newSrc ) {
const { attributes, setAttributes } = this.props;
const { src } = attributes;
// Set the block's src from the edit component's state, and switch off
// the editing UI.
if ( newSrc !== src ) {
// Check if there's an embed block that handles this URL.
const embedBlock = createUpgradedEmbedBlock(
{ attributes: { url: newSrc } }
);
if ( undefined !== embedBlock ) {
this.props.onReplace( embedBlock );
return;
}
setAttributes( { src: newSrc, id: undefined } );
}
this.setState( { editing: false } );
}

And here's the function in question:

/***
* Creates a more suitable embed block based on the passed in props
* and attributes generated from an embed block's preview.
*
* We require `attributesFromPreview` to be generated from the latest attributes
* and preview, and because of the way the react lifecycle operates, we can't
* guarantee that the attributes contained in the block's props are the latest
* versions, so we require that these are generated separately.
* See `getAttributesFromPreview` in the generated embed edit component.
*
* @param {Object} props The block's props.
* @param {Object} attributesFromPreview Attributes generated from the block's most up to date preview.
* @return {Object|undefined} A more suitable embed block if one exists.
*/
export const createUpgradedEmbedBlock = ( props, attributesFromPreview ) => {
const { preview, name } = props;
const { url } = props.attributes;
if ( ! url ) {
return;
}
const matchingBlock = findBlock( url );
// WordPress blocks can work on multiple sites, and so don't have patterns,
// so if we're in a WordPress block, assume the user has chosen it for a WordPress URL.
if ( WORDPRESS_EMBED_BLOCK !== name && DEFAULT_EMBED_BLOCK !== matchingBlock ) {
// At this point, we have discovered a more suitable block for this url, so transform it.
if ( name !== matchingBlock ) {
return createBlock( matchingBlock, { url } );
}
}
if ( preview ) {
const { html } = preview;
// We can't match the URL for WordPress embeds, we have to check the HTML instead.
if ( isFromWordPress( html ) ) {
// If this is not the WordPress embed block, transform it into one.
if ( WORDPRESS_EMBED_BLOCK !== name ) {
return createBlock(
WORDPRESS_EMBED_BLOCK,
{
url,
// By now we have the preview, but when the new block first renders, it
// won't have had all the attributes set, and so won't get the correct
// type and it won't render correctly. So, we pass through the current attributes
// here so that the initial render works when we switch to the WordPress
// block. This only affects the WordPress block because it can't be
// rendered in the usual Sandbox (it has a sandbox of its own) and it
// relies on the preview to set the correct render type.
...attributesFromPreview,
}
);
}
}
}
};

Now, in our environment we unregistered all embed blocks, but kept the video block.

Since neither createUpgradedEmbedBlock nor createBlock verify whether the block type exists, this results in errors because blockType is not an object here, and thus it cannot access blockType.attributes:

// Get the type definition associated with a registered block.
const blockType = getBlockType( name );
// Ensure attributes contains only values defined by block type, and merge
// default values for missing attributes.
const sanitizedAttributes = reduce( blockType.attributes, ( result, schema, key ) => {

Suggested fix

createBlock could be considered being a bit too low level for adding a check here, so I think adding a if ( ! getBlockType( matchingBlock ) ) { return; } check to createUpgradedEmbedBlock would be the appropriate solution.

To reproduce
Steps to reproduce the behavior:

  1. Unregister embed blocks.
  2. Insert video block
  3. Paste YouTube URL in the "Insert from URL" field
  4. See error in console

Expected behavior
No upgrade is attempted / no error happens.

Screenshots
Screenshot 2019-05-29 at 11 56 40

Desktop:

  • OS: macOS
  • Browser Chrome
  • Version 74
  • Gutenberg 5.8 / current master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Embed Affects the Embed Block [Block] Video Affects the Video Block [Feature] Block Transforms Block transforms from one block to another [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant