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

Filterable behavior for Image Block raw transformations #8473

Open
danielbachhuber opened this issue Aug 3, 2018 · 5 comments
Open

Filterable behavior for Image Block raw transformations #8473

danielbachhuber opened this issue Aug 3, 2018 · 5 comments
Labels
Backwards Compatibility Issues or PRs that impact backwards compatability [Feature] Blocks Overall functionality of blocks [Feature] Extensibility The ability to extend blocks or the editing experience [Feature] Media Anything that impacts the experience of managing media [Feature] Paste [Type] Enhancement A suggestion for improvement.
Milestone

Comments

@danielbachhuber
Copy link
Member

danielbachhuber commented Aug 3, 2018

One of the plugins I work on, Tasty Pins, offers the ability to add "Pinterest Text" to an image (related #8472). When the image ends up in the Classic Editor, its markup looks like this:

image

Notice the inclusion of data-pin-description="This cashew coffee is delicious, creamy, and easy. Perfect for a chilly morning! | pinchof yum.com".

When this image is transformed to an Image Block, the data-pin-description attribute is lost, even though I've registered it as a custom attribute to the block (related #8470, #6878).

pinterestconversion

What's the best way to filter the Image Block transform behavior? It doesn't appear plugins have much control over the behavior:

transform: ( node ) => {
// Search both figure and image classes. Alignment could be
// set on either. ID is set on the image.
const className = node.className + ' ' + node.querySelector( 'img' ).className;
const alignMatches = /(?:^|\s)align(left|center|right)(?:$|\s)/.exec( className );
const align = alignMatches ? alignMatches[ 1 ] : undefined;
const idMatches = /(?:^|\s)wp-image-(\d+)(?:$|\s)/.exec( className );
const id = idMatches ? idMatches[ 1 ] : undefined;
const anchorElement = node.querySelector( 'a' );
const linkDestination = anchorElement && anchorElement.href ? 'custom' : undefined;
const href = anchorElement && anchorElement.href ? anchorElement.href : undefined;
const blockType = getBlockType( 'core/image' );
const attributes = getBlockAttributes( blockType, node.outerHTML, { align, id, linkDestination, href } );
return createBlock( 'core/image', attributes );

@danielbachhuber danielbachhuber added [Type] Enhancement A suggestion for improvement. [Feature] Blocks Overall functionality of blocks [Feature] Extensibility The ability to extend blocks or the editing experience [Feature] Paste Backwards Compatibility Issues or PRs that impact backwards compatability labels Aug 3, 2018
@danielbachhuber danielbachhuber added the [Feature] Media Anything that impacts the experience of managing media label Aug 3, 2018
@WordPress WordPress deleted a comment Aug 4, 2018
@designsimply
Copy link
Member

Noting I deleted a comment which was saying the same thing over and over many times per minute in various locations. Spamming and unacceptable behavior towards anyone, or this community, will not be allowed. If you want to give feedback, please do it without spamming or personal attacks.

My apologies for those who were effected during this. Please know we have a zero tolerance policy over this type of behavior.

@danielbachhuber
Copy link
Member Author

I made some progress on an implementation:

if ( 'core/image' !== name ) {
    return settings;
}

const newTransforms = [];
settings.transforms.from.forEach(( transformObj ) => {
    if ( 'raw' === transformObj.type ) {
        const origTransform = transformObj.transform;
        const transformWrap = ( node ) => {

            // Parse the Pinterest attributes and add to our central store.
            const img = node.querySelector( 'img' );
            const className = node.className + ' ' + img.className;
            const idMatches = /(?:^|\s)wp-image-(\d+)(?:$|\s)/.exec( className );
            const id = idMatches ? Number( idMatches[ 1 ] ) : undefined;
            if ( id ) {
                const valueKey = 'image_' + id;
                // img.dataset['pin-description'] is undefined because it's already been sanitized
                setStoreValue( 'descriptions', valueKey, img.dataset['pin-description'] );
            }

            return origTransform( node );
        };
        transformObj = Object.assign( transformObj, {
            transform: transformWrap,
        });
    } else if ( 'shortcode' === transformObj.type ) {
        // todo handle this too
    }
    newTransforms.push( transformObj );
});
settings.transforms.from = newTransforms;

However, the node HTML is unexpectedly sanitized before the transformation is called, which means my data is already missing.

@antpb antpb added the [Priority] High Used to indicate top priority items that need quick attention label Oct 31, 2018
@mcsf
Copy link
Contributor

mcsf commented Nov 5, 2018

HTML is unexpectedly sanitized before the transformation is called

@danielbachhuber, is this helpful?

#8648 (comment)

@danielbachhuber
Copy link
Member Author

@danielbachhuber, is this helpful?

#8648 (comment)

Yes, I think this would solve the problem I ran into with #8473 (comment). However, I want to see how #11440 transforms into actionable tasks before I spend too much time on this.

@danielbachhuber
Copy link
Member Author

danielbachhuber commented Nov 16, 2018

Along with #10204 (comment), I've gone with this:

const { merge } = lodash;

const { hooks } = wp;

const pinAttributes = {
	pinterestText: {
		type: 'string',
		source: 'attribute',
		selector: 'img',
		attribute: 'data-pin-description',
		default: '',
	}
};

const modifyRegistration = ( settings, name ) => {

	if ( 'core/image' !== name ) {
		return settings;
	}

	// Register our attributes to the Image Block.
	settings.attributes = Object.assign( settings.attributes, pinAttributes );

	const imageAttributes = [
		'src',
		'alt',
		'data-pin-description',
	];

	// Extend raw <img> HTML transformation.
	settings.transforms.from[0] = merge( settings.transforms.from[0], {
		schema: {
			figure: {
				children: {
					a: {
						children: {
							img: {
								attributes: imageAttributes
							}
						}
					},
					img: {
						attributes: imageAttributes
					}
				}
			}
		}
	} );

	// Extend [caption] shortcode transformation
	settings.transforms.from[2].attributes = Object.assign( settings.transforms.from[2].attributes, pinAttributes );

	return settings;
};

hooks.addFilter( 'blocks.registerBlockType', 'wp-tasty/tasty-pins', modifyRegistration );

@jorgefilipecosta jorgefilipecosta removed the [Priority] High Used to indicate top priority items that need quick attention label Jan 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backwards Compatibility Issues or PRs that impact backwards compatability [Feature] Blocks Overall functionality of blocks [Feature] Extensibility The ability to extend blocks or the editing experience [Feature] Media Anything that impacts the experience of managing media [Feature] Paste [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

No branches or pull requests

7 participants