Repository navigation
Quote v2: add migration #39844
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
Quote v2: add migration #39844
Changes from all commits
316a4ec
6b891e5
e3445b9
2bdddf1
19a5111
f3cac07
025c85c
f881ea2
ff66abd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| /** | ||
| * External dependencies | ||
| */ | ||
| import classnames from 'classnames'; | ||
| import { omit } from 'lodash'; | ||
|
|
||
| /** | ||
| * WordPress dependencies | ||
| */ | ||
| import { createBlock, parseWithAttributeSchema } from '@wordpress/blocks'; | ||
| import { RichText, useBlockProps } from '@wordpress/block-editor'; | ||
|
|
||
| /** | ||
| * Internal dependencies | ||
| */ | ||
| import deprecationsForV1Block from '../deprecated'; | ||
|
|
||
| export const migrateToQuoteV2 = ( attributes ) => { | ||
| const { value } = attributes; | ||
|
|
||
| return [ | ||
| { | ||
| ...omit( attributes, [ 'value' ] ), | ||
| }, | ||
| value | ||
| ? parseWithAttributeSchema( value, { | ||
|
youknowriad marked this conversation as resolved.
|
||
| type: 'array', | ||
| source: 'query', | ||
| selector: 'p', | ||
| query: { | ||
| content: { | ||
| type: 'string', | ||
| source: 'html', | ||
| }, | ||
| }, | ||
| } ).map( ( { content } ) => | ||
| createBlock( 'core/paragraph', { content } ) | ||
| ) | ||
| : createBlock( 'core/paragraph' ), | ||
| ]; | ||
| }; | ||
|
|
||
| const v3 = { | ||
| attributes: { | ||
| value: { | ||
| type: 'string', | ||
| source: 'html', | ||
| selector: 'blockquote', | ||
| multiline: 'p', | ||
| default: '', | ||
| __experimentalRole: 'content', | ||
| }, | ||
| citation: { | ||
| type: 'string', | ||
| source: 'html', | ||
| selector: 'cite', | ||
| default: '', | ||
| __experimentalRole: 'content', | ||
| }, | ||
| align: { | ||
| type: 'string', | ||
| }, | ||
| }, | ||
| supports: { | ||
| anchor: true, | ||
| __experimentalSlashInserter: true, | ||
| typography: { | ||
| fontSize: true, | ||
| lineHeight: true, | ||
| __experimentalFontStyle: true, | ||
| __experimentalFontWeight: true, | ||
| __experimentalLetterSpacing: true, | ||
| __experimentalTextTransform: true, | ||
| __experimentalDefaultControls: { | ||
| fontSize: true, | ||
| fontAppearance: true, | ||
| }, | ||
| }, | ||
| }, | ||
| save( { attributes } ) { | ||
| const { align, value, citation } = attributes; | ||
|
|
||
| const className = classnames( { | ||
| [ `has-text-align-${ align }` ]: align, | ||
| } ); | ||
|
|
||
| return ( | ||
| <blockquote { ...useBlockProps.save( { className } ) }> | ||
| <RichText.Content multiline value={ value } /> | ||
| { ! RichText.isEmpty( citation ) && ( | ||
| <RichText.Content tagName="cite" value={ citation } /> | ||
| ) } | ||
| </blockquote> | ||
| ); | ||
| }, | ||
| migrate: migrateToQuoteV2, | ||
| }; | ||
|
|
||
| /** | ||
| * New deprecations need to be placed first | ||
| * for them to have higher priority. | ||
| * | ||
| * Old deprecations may need to be updated as well. | ||
| * | ||
| * See block-deprecation.md | ||
| */ | ||
| export default [ v3, ...deprecationsForV1Block ]; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,24 +9,73 @@ import { | |
| store as blockEditorStore, | ||
| } from '@wordpress/block-editor'; | ||
| import { BlockQuotation } from '@wordpress/components'; | ||
| import { useSelect } from '@wordpress/data'; | ||
| import { useDispatch, useSelect, useRegistry } from '@wordpress/data'; | ||
| import { createBlock } from '@wordpress/blocks'; | ||
| import { Platform } from '@wordpress/element'; | ||
| import { Platform, useEffect } from '@wordpress/element'; | ||
| import deprecated from '@wordpress/deprecated'; | ||
|
|
||
| /** | ||
| * Internal dependencies | ||
| */ | ||
| import { migrateToQuoteV2 } from './deprecated'; | ||
|
|
||
| const isWebPlatform = Platform.OS === 'web'; | ||
| const TEMPLATE = [ [ 'core/paragraph', {} ] ]; | ||
|
|
||
| /** | ||
| * At the moment, deprecations don't handle create blocks from attributes | ||
| * (like when using CPT templates). For this reason, this hook is necessary | ||
| * to avoid breaking templates using the old quote block format. | ||
| * | ||
| * @param {Object} attributes Block attributes. | ||
| * @param {string} clientId Block client ID. | ||
| */ | ||
| const useMigrateOnLoad = ( attributes, clientId ) => { | ||
| const registry = useRegistry(); | ||
| const { updateBlockAttributes, replaceInnerBlocks } = useDispatch( | ||
| blockEditorStore | ||
| ); | ||
| useEffect( () => { | ||
| // As soon as the block is loaded, migrate it to the new version. | ||
|
|
||
| if ( ! attributes.value ) { | ||
| // No need to migrate if it doesn't have the value attribute. | ||
| return; | ||
| } | ||
|
|
||
| const [ newAttributes, newInnerBlocks ] = migrateToQuoteV2( | ||
| attributes | ||
| ); | ||
|
oandregal marked this conversation as resolved.
|
||
|
|
||
| deprecated( 'Value attribute on the quote block', { | ||
| since: '6.0', // WP version | ||
| version: '6.5', | ||
| alternative: 'inner blocks', | ||
| } ); | ||
|
|
||
| registry.batch( () => { | ||
| updateBlockAttributes( clientId, newAttributes ); | ||
| replaceInnerBlocks( clientId, newInnerBlocks ); | ||
| } ); | ||
| }, [ attributes.value ] ); | ||
| }; | ||
|
|
||
| export default function QuoteEdit( { | ||
| attributes: { citation }, | ||
| attributes, | ||
| setAttributes, | ||
| isSelected, | ||
| insertBlocksAfter, | ||
| clientId, | ||
| } ) { | ||
| const { citation } = attributes; | ||
|
|
||
| useMigrateOnLoad( attributes, clientId ); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is using the same technique than the list v2 uses https://github.com/WordPress/gutenberg/pull/39799/files#diff-8ca208404bc35d0549ee68bfdb5c87a0d1fa101ddcfad1095d9a3c0e171b0272 |
||
|
|
||
| const isAncestorOfSelectedBlock = useSelect( ( select ) => | ||
| select( blockEditorStore ).hasSelectedInnerBlock( clientId ) | ||
| ); | ||
| const hasSelection = isSelected || isAncestorOfSelectedBlock; | ||
|
|
||
| const blockProps = useBlockProps(); | ||
| const innerBlocksProps = useInnerBlocksProps( blockProps, { | ||
| template: TEMPLATE, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,14 +3,14 @@ | |
| */ | ||
| import { __ } from '@wordpress/i18n'; | ||
| import { quote as icon } from '@wordpress/icons'; | ||
| import { addFilter } from '@wordpress/hooks'; | ||
|
|
||
| /** | ||
| * Internal dependencies | ||
| */ | ||
| import edit from './edit'; | ||
| import save from './save'; | ||
| import transforms from './transforms'; | ||
| import deprecated from './deprecated'; | ||
|
|
||
| const settings = { | ||
| icon, | ||
|
|
@@ -30,37 +30,7 @@ const settings = { | |
| transforms, | ||
| edit, | ||
| save, | ||
| deprecated, | ||
| }; | ||
|
|
||
| export default settings; | ||
|
|
||
| /** | ||
| * This function updates the attributes for the quote v2. | ||
| * This should be moved to block.json when v2 becomes the default. | ||
| * | ||
| * @param {Array} blockSettings The settings of the block to be registered. | ||
| * @param {string} blockName The name of the block to be registered. | ||
| * @return {Array} New settings. | ||
| */ | ||
| function registerQuoteV2Attributes( blockSettings, blockName ) { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Had to remove the filter because it was affecting the deprecation, preventing it from having the We need to remove the attribute from the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't think we can remove it until the |
||
| if ( ! window?.__experimentalEnableQuoteBlockV2 ) { | ||
| return blockSettings; | ||
| } | ||
|
|
||
| if ( blockName !== 'core/quote' ) { | ||
| return blockSettings; | ||
| } | ||
|
|
||
| // Deregister the old ones. | ||
| delete blockSettings.attributes.value; | ||
|
|
||
| return blockSettings; | ||
| } | ||
|
|
||
| // Importing this file includes side effects. | ||
| // This has been declared in block-library/package.json under sideEffects. | ||
| addFilter( | ||
| 'blocks.registerBlockType', | ||
| 'core/quote/v2-attributes', | ||
| registerQuoteV2Attributes | ||
| ); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| /** | ||
| * WordPress dependencies | ||
| */ | ||
| import { | ||
| registerBlockType, | ||
| serialize, | ||
| unregisterBlockType, | ||
| } from '@wordpress/blocks'; | ||
|
|
||
| /** | ||
| * Internal dependencies | ||
| */ | ||
| import { migrateToQuoteV2 } from '../deprecated'; | ||
| import * as paragraph from '../../../paragraph'; | ||
| import * as quote from '../../../quote'; | ||
| import * as quoteV2 from '../../../quote/v2'; | ||
|
|
||
| describe( 'Migrate quote block', () => { | ||
| beforeAll( () => { | ||
| registerBlockType( | ||
| { name: paragraph.name, ...paragraph.metadata }, | ||
| paragraph.settings | ||
| ); | ||
| registerBlockType( | ||
| { name: quote.name, ...quote.metadata }, | ||
| quoteV2.settings | ||
| ); | ||
| } ); | ||
|
|
||
| afterAll( () => { | ||
| unregisterBlockType( paragraph.name ); | ||
| unregisterBlockType( quote.name ); | ||
| } ); | ||
|
|
||
| it( 'should migrate the value attribute to inner blocks', () => { | ||
| const [ attributes, innerBlocks ] = migrateToQuoteV2( { | ||
| value: '<p>First paragraph</p><p>Second paragraph</p>', | ||
| citation: 'Author', | ||
| } ); | ||
| expect( attributes ).toEqual( { | ||
| citation: 'Author', | ||
| } ); | ||
| expect( serialize( innerBlocks ) ).toEqual( | ||
| `<!-- wp:paragraph --> | ||
| <p>First paragraph</p> | ||
| <!-- /wp:paragraph --> | ||
|
|
||
| <!-- wp:paragraph --> | ||
| <p>Second paragraph</p> | ||
| <!-- /wp:paragraph -->` | ||
| ); | ||
| } ); | ||
|
|
||
| it( 'should create a paragraph if value is empty', () => { | ||
| const [ attributes, innerBlocks ] = migrateToQuoteV2( { | ||
| value: undefined, | ||
| citation: 'Author', | ||
| } ); | ||
| expect( attributes ).toEqual( { | ||
| citation: 'Author', | ||
| } ); | ||
| expect( serialize( innerBlocks ) ).toEqual( | ||
| `<!-- wp:paragraph --> | ||
| <p></p> | ||
| <!-- /wp:paragraph -->` | ||
| ); | ||
| } ); | ||
|
|
||
| it( 'should keep the formats of the value', () => { | ||
| const [ attributes, innerBlocks ] = migrateToQuoteV2( { | ||
| value: | ||
| '<p><strong>Bold</strong></p><p> and </p><p><em>italic</em></p>', | ||
| citation: 'Author', | ||
| } ); | ||
| expect( attributes ).toEqual( { | ||
| citation: 'Author', | ||
| } ); | ||
| expect( serialize( innerBlocks ) ).toEqual( | ||
| `<!-- wp:paragraph --> | ||
| <p><strong>Bold</strong></p> | ||
| <!-- /wp:paragraph --> | ||
|
|
||
| <!-- wp:paragraph --> | ||
| <p> and </p> | ||
| <!-- /wp:paragraph --> | ||
|
|
||
| <!-- wp:paragraph --> | ||
| <p><em>italic</em></p> | ||
| <!-- /wp:paragraph -->` | ||
| ); | ||
| } ); | ||
| } ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,7 +29,7 @@ const transforms = { | |
| query: { | ||
| content: { | ||
| type: 'string', | ||
| source: 'text', | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've commited this here because it's the same fix I did for the migration. Thought it doesn't deserve a separate PR. |
||
| source: 'html', | ||
| }, | ||
| }, | ||
| } ).map( ( { content } ) => | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.