Skip to content

Commit

Permalink
Add possibility to manage innerBlocks while migrating deprecated bloc…
Browse files Browse the repository at this point in the history
…ks. Added migration logic to migrate existing cover images into the new nested version.

Before the migrate function received the existing attributes and returned the new attributes now, migrate receives an object with attributes and innerBlocks and returns another object with the migrated attributes & innerBlocks.
  • Loading branch information
jorgefilipecosta committed Apr 4, 2018
1 parent 991e56c commit 291d97c
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 47 deletions.
17 changes: 10 additions & 7 deletions blocks/api/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export function getBlockAttributes( blockType, innerHTML, attributes ) {
*
* @return {Object} Block attributes.
*/
export function getAttributesFromDeprecatedVersion( blockType, innerHTML, attributes ) {
export function getAttributesAndInnerBlocksFromDeprecatedVersion( blockType, innerHTML, attributes, innerBlocks ) {
// Not all blocks need a deprecated definition so avoid unnecessary computational cycles
// as early as possible when `deprecated` property is not supplied.
if ( ! blockType.deprecated || ! blockType.deprecated.length ) {
Expand All @@ -181,12 +181,14 @@ export function getAttributesFromDeprecatedVersion( blockType, innerHTML, attrib
try {
// Handle migration of older attributes into current version if necessary.
const deprecatedBlockAttributes = getBlockAttributes( deprecatedBlockType, innerHTML, attributes );
const migratedBlockAttributes = deprecatedBlockType.migrate ? deprecatedBlockType.migrate( deprecatedBlockAttributes ) : deprecatedBlockAttributes;
const migratedBlockAttributesAndInnerBlocks = deprecatedBlockType.migrate ?
deprecatedBlockType.migrate( { attributes: deprecatedBlockAttributes, innerBlocks } ) :
{ attributes: deprecatedBlockAttributes, innerBlocks };

// Attempt to validate the parsed block. Ignore if the the validation step fails.
const isValid = isValidBlock( innerHTML, deprecatedBlockType, deprecatedBlockAttributes );
if ( isValid ) {
return migratedBlockAttributes;
return migratedBlockAttributesAndInnerBlocks;
}
} catch ( error ) {
// Ignore error, it means this deprecated version is invalid.
Expand Down Expand Up @@ -275,13 +277,14 @@ export function createBlockWithFallback( blockNode ) {
// This enables blocks to modify its attributes and markup structure without
// invalidating content written in previous formats.
if ( ! block.isValid ) {
const attributesParsedWithDeprecatedVersion = getAttributesFromDeprecatedVersion(
blockType, innerHTML, attributes
const attributesAndInnerBlocksParsedWithDeprecatedVersion = getAttributesAndInnerBlocksFromDeprecatedVersion(
blockType, innerHTML, attributes, block.innerBlocks
);

if ( attributesParsedWithDeprecatedVersion ) {
if ( attributesAndInnerBlocksParsedWithDeprecatedVersion ) {
block.isValid = true;
block.attributes = attributesParsedWithDeprecatedVersion;
block.attributes = attributesAndInnerBlocksParsedWithDeprecatedVersion.attributes;
block.innerBlocks = attributesAndInnerBlocksParsedWithDeprecatedVersion.innerBlocks || [];
}
}

Expand Down
109 changes: 83 additions & 26 deletions blocks/library/cover-image/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import { omit } from 'lodash';

/**
* WordPress dependencies
*/
Expand Down Expand Up @@ -197,36 +202,88 @@ export const settings = {
);
},

deprecated: [ {
attributes: {
...blockAttributes,
title: {
type: 'array',
source: 'children',
selector: 'h2',
deprecated: [
{
attributes: {
...blockAttributes,
title: {
type: 'array',
source: 'children',
selector: 'p',
},
contentAlign: {
type: 'string',
default: 'center',
},
},

save( { attributes, className } ) {
const { url, title, hasParallax, dimRatio, align, contentAlign } = attributes;
const style = backgroundImageStyles( url );
const classes = classnames(
className,
dimRatioToClass( dimRatio ),
{
'has-background-dim': dimRatio !== 0,
'has-parallax': hasParallax,
[ `has-${ contentAlign }-content` ]: contentAlign !== 'center',
},
align ? `align${ align }` : null,
);

return (
<div className={ classes } style={ style }>
{ title && title.length > 0 && (
<p className="wp-block-cover-image-text">{ title }</p>
) }
</div>
);
},
},

save( { attributes, className } ) {
const { url, title, hasParallax, dimRatio, align } = attributes;
const style = backgroundImageStyles( url );
const classes = classnames(
className,
dimRatioToClass( dimRatio ),
{
'has-background-dim': dimRatio !== 0,
'has-parallax': hasParallax,
migrate( { attributes } ) {
return {
attributes: omit( attributes, [ 'title', 'contentAlign' ] ),
innerBlocks: [ createBlock( 'core/paragraph', {
content: attributes.title,
align: attributes.contentAlign,
fontSize: 'large',
placeholder: __( 'Write title…' ),
textColor: '#fff',
} ) ],
};
},
},
{
attributes: {
...blockAttributes,
title: {
type: 'array',
source: 'children',
selector: 'h2',
},
align ? `align${ align }` : null,
);

return (
<section className={ classes } style={ style }>
<h2>{ title }</h2>
</section>
);
},

save( { attributes, className } ) {
const { url, title, hasParallax, dimRatio, align } = attributes;
const style = backgroundImageStyles( url );
const classes = classnames(
className,
dimRatioToClass( dimRatio ),
{
'has-background-dim': dimRatio !== 0,
'has-parallax': hasParallax,
},
align ? `align${ align }` : null,
);

return (
<section className={ classes } style={ style }>
<h2>{ title }</h2>
</section>
);
},
},
} ],
],
};

function dimRatioToClass( ratio ) {
Expand Down
26 changes: 15 additions & 11 deletions blocks/library/paragraph/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,14 +369,16 @@ export const settings = {

return <p style={ styles } className={ className ? className : undefined }>{ content }</p>;
},
migrate( attributes ) {
migrate( { attributes } ) {
if ( isFinite( attributes.fontSize ) ) {
return omit( {
...attributes,
customFontSize: attributes.fontSize,
}, 'fontSize' );
return {
attributes: omit( {
...attributes,
customFontSize: attributes.fontSize,
}, 'fontSize' ),
};
}
return attributes;
return { attributes };
},
},
{
Expand All @@ -391,12 +393,14 @@ export const settings = {
save( { attributes } ) {
return <RawHTML>{ attributes.content }</RawHTML>;
},
migrate( attributes ) {
migrate( { attributes } ) {
return {
...attributes,
content: [
<RawHTML key="html">{ attributes.content }</RawHTML>,
],
attributes: {
...attributes,
content: [
<RawHTML key="html">{ attributes.content }</RawHTML>,
],
},
};
},
},
Expand Down
102 changes: 99 additions & 3 deletions docs/deprecated-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ registerBlockType( 'gutenberg/block-with-deprecated-version', {
}
},

migrate: function( attributes ) {
migrate: function( attributesAndInnerBlocks ) {
var attributes = attributesAndInnerBlocks;
return {
content: attributes.text
};
Expand Down Expand Up @@ -157,9 +158,9 @@ registerBlockType( 'gutenberg/block-with-deprecated-version', {
}
},

migrate( { text } ) {
migrate( { attributes } ) {
return {
content: text
content: attributes.text
};
},

Expand All @@ -173,3 +174,98 @@ registerBlockType( 'gutenberg/block-with-deprecated-version', {
{% end %}

In the example above we updated the markup of the block to use a `div` instead of `p` and rename the `text` attribute to `content`.


## Changing the innerBlocks

Situations may exist where when migrating the block we may need to add or remove innerBlocks.
E.g: a block wants to migrate a title attribute to a paragraph innerBlock.

### Example:

{% codetabs %}
{% ES5 %}
```js
var el = wp.element.createElement,
registerBlockType = wp.blocks.registerBlockType;

registerBlockType( 'gutenberg/block-with-deprecated-version', {

// ... block properties go here

deprecated: [
{
attributes: {
title: {
type: 'array',
source: 'children',
selector: 'p',
},
},

migrate: function( attributesAndInnerBlocks ) {
var attributes = attributesAndInnerBlocks;
var innerBlocks = attributesAndInnerBlocks.innerBlocks;
return {
attributes: omit( attributes, 'title' ),
innerBlocks: [
createBlock( 'core/paragraph', {
content: attributes.title,
fontSize: 'large',
} ),
].concat( innerBlocks ),
};
},

save: function( props ) {
return el( 'p', {}, props.attributes.title );
},
}
]
} );
```
{% ESNext %}
```js
const { registerBlockType } = wp.blocks;

registerBlockType( 'gutenberg/block-with-deprecated-version', {

// ... block properties go here

save( props ) {
return <p>{ props.attributes.title }</div>;
},

deprecated: [
{
attributes: {
title: {
type: 'array',
source: 'children',
selector: 'p',
},
},

migrate( { attributes, innerBlocks } ) {
return {
attributes: omit( attributes, 'title' ),
innerBlocks: [
createBlock( 'core/paragraph', {
content: attributes.title,
fontSize: 'large',
} ),
...innerBlocks,
],
};
},

save( props ) {
return <p>{ props.attributes.title }</div>;
},
}
]
} );
```
{% end %}

In the example above we updated the the block to use an inner paragraph block with a title instead of a title attribute.

0 comments on commit 291d97c

Please sign in to comment.