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

Block Transforms: Use of async functions in a transform #14755

Open
ryelle opened this issue Apr 1, 2019 · 5 comments
Open

Block Transforms: Use of async functions in a transform #14755

ryelle opened this issue Apr 1, 2019 · 5 comments
Labels
[Feature] Block API API that allows to express the block paradigm. Needs Dev Ready for, and needs developer efforts [Type] Enhancement A suggestion for improvement.

Comments

@ryelle
Copy link
Contributor

ryelle commented Apr 1, 2019

Is your feature request related to a problem? Please describe.

I'm trying to build a transform from a WooCommerce block that displays a product using API data into the newly updated Cover block. Unfortunately, in the source block I only have the product ID attribute, and need to get the data for Cover's innerBlocks via an API request. You can see the start of this at this PR, currently using a mocked product: woocommerce/woocommerce-blocks#490

Describe the solution you'd like

It would be great if transforms could support async functions, so that I could write something like:

transform: async ( { productId } , innerBlocks ) => {
	const product = await apiFetch( {
		path: `/wc-blocks/v1/products/${ productId }`,
	} );
	
	// now I can use the values in `product` to populate some
	// innerBlocks in the Cover block.

But that makes switchToBlockType more complex.

Describe alternatives you've considered

My best alternative so far would be to populate some attributes for the product values I need (name, description, image src, etc), but these would not actually be editable attributes - the block would always have to pull from the product in case the source product has been updated. So that seems like an anti-pattern for attribute use.

@youknowriad
Copy link
Contributor

Thanks for opening the issue.

The transforms API grew bit by bit as we needed to solve precise use-cases. It might be the right time to rethink it at a global level to bring more consistency and coherence. In addition to the use-case raised in this issue, I can think of some other missing pieces:

  • How to handle temporary attributes (we use right now for the file transforms)? How can we create "temporary blocks" to disable the saving while the process is being performed?
  • How can we access the block editor settings from the transforms API. What If I want to build a block that receives the block editor upload handler __experimentalMediaUpload.

Seems like a good subject for an RFC.

@grappler
Copy link
Member

I wanted to use async too to convert a page ID to a link. As an alternative I was able to do the conversion in PHP using rest_prepare_widget.

I look forward for the new convert feature.

@noisysocks
Copy link
Member

noisysocks commented Jan 23, 2023

Just ran into a need for async transforms myself.

Perhaps we could soft-deprecate transform, stabilise __experimentalConvert and allow convert to be async? Nobody seemed opposed to this in #19401, there were just questions surrounding how to approach deprecation.

  • How to handle temporary attributes (we use right now for the file transforms)? How can we create "temporary blocks" to disable the saving while the process is being performed?

This is a good question but I think it a shortcoming in the blocks API not the transforms API.

One idea I had is to allow passing "constructor arguments" to a block.

// packages/block-library/src/file/transforms.js
const blocks = createBlock( { // passing an object allows passing advanced options to createBlock
	name: 'core/file',
	attributes: { fileName: file.name },
	innerBlocks: [],
	arguments: { blobURL },
} );

// packages/block-library/src/file/edit.js
function FileEdit( { attributes, arguments } ) {
	useEffect( () => {
		// upload blob and call markNextChangeAsNotPersistent() & setAttributes()
	}, [ arguments.blobURL ] };
}

I've also seen proposals for "private" attributes which could help too.

How can we access the block editor settings from the transforms API. What If I want to build a block that receives the block editor upload handler __experimentalMediaUpload.

This is a fun question. Obviously you can use the getSettings() selector but that isn't aware of context. We can't really replace the transforms array with React components since some blocks define valid transforms even when not mounted.

Maybe we could add a way to look up the block editor store by a block.

const settings = getBlockEditorStoreForBlock( block ).getSettings();

@noisysocks
Copy link
Member

Dug into this a little more. I don't think it's practical to make transform or __experimentalConvert async. They're called by switchToBlockType(). switchToBlockType() is public and widely used so immediately there's a backwards compatibility concern about changing its behaviour. More problematic though is that switchToBlockType() is used in very low-level parts of the codebase that handle copy/paste and merging selected blocks.

So I am thinking we flip this and make it so that transforms can be updated at runtime. Similar to what we already do for block styles and block variations. Then, extenders can make an API call and update the transforms when the request is fulfilled.

Pseudo code:

import apiFetch from '@wordpress/api-fetch';
import { addBlockTransform } from '@wordpress/blocks';

apiFetch( {
	path: `/wc-blocks/v1/products/${ productId }`,
} ).then( ( product ) => {
	addBlockTransform(
		'from', // 'from' or 'to'
		'woo/product', // identifies the transform so it can be removed later
		{
			type: 'block',
			blocks: [ 'core/cover' ],
			transform( attributes, innerBlocks ) {
				// do stuff with product
				return createBlock( ... );
			},
		}
	);
} );

@mrleemon
Copy link
Contributor

mrleemon commented Jun 8, 2024

I also need to be able to make API requests inside a transform to get data from the database.

@noisysocks noisysocks added the Needs Dev Ready for, and needs developer efforts label Jun 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. Needs Dev Ready for, and needs developer efforts [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

No branches or pull requests

5 participants