Question

Below there is a simplified version of the concept I'm trying to make work.

In a post, I'm manually inserting this core Image block:

<!-- wp:image {"id":7} -->
<figure class="wp-block-image"><img src="[picsum]" alt="ASD" class="wp-image-7"/></figure>
<!-- /wp:image -->

As you see, there is shortcode for the src attribute of the image, so here is the shortcode callback.

add_shortcode( 'picsum', 'picsum_func' );
function picsum_func( $atts ) {
    return "https://picsum.photos/id/237/200/300";
}

Simple, right?

When I open this post on the frontend it renders the image properly. Also, when I open the post on the editor, it renders no image for the image block, but the block is surely there.

What is weird, is that in my console log there is this error

GET http://example.local/wp-admin/[picsum] 404 (Not Found), which I cannot debug because the stack trace is not helpful, at least not to me. This happens with both the latest WP and the editor that it carries and with the latest version from the GB repo.

Can you help me identify what the problem is and how can I prevent this? Where is this request coming from?

The stack trace is this:

Image (async)       
setValueForProperty @   react-dom.development.js:1368
setInitialDOMProperties @   react-dom.development.js:5954
setInitialProperties    @   react-dom.development.js:6149
finalizeInitialChildren @   react-dom.development.js:7622
completeWork    @   react-dom.development.js:19113
completeUnitOfWork  @   react-dom.development.js:22324
performUnitOfWork   @   react-dom.development.js:22300
workLoopSync    @   react-dom.development.js:22265
performSyncWorkOnRoot   @   react-dom.development.js:21891
(anonymous) @   react-dom.development.js:11224
unstable_runWithPriority    @   react.development.js:2685
runWithPriority$1   @   react-dom.development.js:11174
flushSyncCallbackQueueImpl  @   react-dom.development.js:11219
flushSyncCallbackQueue  @   react-dom.development.js:11207
scheduleUpdateOnFiber   @   react-dom.development.js:21334
dispatchAction  @   react-dom.development.js:15795
onStoreChange   @   index.js:201
onChange    @   index.js:217
(anonymous) @   index.js:175
dispatch    @   redux.js:297
(anonymous) @   index.js:24
(anonymous) @   promise-middleware.js:20
(anonymous) @   resolvers-cache-middleware.js:52
dispatch    @   redux.js:659
unhandledActionControl  @   runtime.js:49
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
any @   builtin.js:15
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:37
Promise.then (async)        
(anonymous) @   runtime.js:37
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
(anonymous) @   runtime.js:39
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
iterate @   create.js:51
runtime @   create.js:73
iterator    @   builtin.js:90
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
any @   builtin.js:15
(anonymous) @   create.js:47
next    @   create.js:46
unhandledActionControl  @   runtime.js:50
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
any @   builtin.js:15
(anonymous) @   create.js:47
next    @   create.js:46
unhandledActionControl  @   runtime.js:50
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
iterate @   create.js:51
runtime @   create.js:73
(anonymous) @   runtime.js:59
(anonymous) @   runtime.js:58
(anonymous) @   index.js:27
(anonymous) @   promise-middleware.js:20
(anonymous) @   resolvers-cache-middleware.js:52
(anonymous) @   index.js:298
(anonymous) @   index.js:72
commitHookEffectListMount   @   react-dom.development.js:19866
commitLifeCycles    @   react-dom.development.js:19922
commitLayoutEffects @   react-dom.development.js:22938
callCallback    @   react-dom.development.js:182
invokeGuardedCallbackDev    @   react-dom.development.js:231
invokeGuardedCallback   @   react-dom.development.js:286
commitRootImpl  @   react-dom.development.js:22676
unstable_runWithPriority    @   react.development.js:2685
runWithPriority$1   @   react-dom.development.js:11174
commitRoot  @   react-dom.development.js:22516
finishSyncRender    @   react-dom.development.js:21942
performSyncWorkOnRoot   @   react-dom.development.js:21928
(anonymous) @   react-dom.development.js:11224
unstable_runWithPriority    @   react.development.js:2685
runWithPriority$1   @   react-dom.development.js:11174
flushSyncCallbackQueueImpl  @   react-dom.development.js:11219
flushSyncCallbackQueue  @   react-dom.development.js:11207
scheduleUpdateOnFiber   @   react-dom.development.js:21334
dispatchAction  @   react-dom.development.js:15795
onStoreChange   @   index.js:201
onChange    @   index.js:217
(anonymous) @   index.js:175
dispatch    @   redux.js:297
(anonymous) @   index.js:24
(anonymous) @   promise-middleware.js:20
(anonymous) @   resolvers-cache-middleware.js:52
dispatch    @   redux.js:659
unhandledActionControl  @   runtime.js:49
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
Promise.then (async)        
(anonymous) @   runtime.js:37
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
Promise.then (async)        
(anonymous) @   runtime.js:37
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
any @   builtin.js:15
(anonymous) @   create.js:47
next    @   create.js:46
unhandledActionControl  @   runtime.js:50
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
(anonymous) @   runtime.js:39
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
(anonymous) @   runtime.js:39
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
any @   builtin.js:15
(anonymous) @   create.js:47
next    @   create.js:46
unhandledActionControl  @   runtime.js:50
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
any @   builtin.js:15
(anonymous) @   create.js:47
next    @   create.js:46
unhandledActionControl  @   runtime.js:50
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
any @   builtin.js:15
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:37
any @   builtin.js:15
(anonymous) @   create.js:47
next    @   create.js:46
unhandledActionControl  @   runtime.js:50
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
any @   builtin.js:15
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:37
Promise.then (async)        
(anonymous) @   runtime.js:37
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
iterate @   create.js:51
runtime @   create.js:73
iterator    @   builtin.js:90
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
(anonymous) @   runtime.js:39
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
iterate @   create.js:51
runtime @   create.js:73
iterator    @   builtin.js:90
(anonymous) @   create.js:47
next    @   create.js:46
(anonymous) @   create.js:38
iterate @   create.js:51
runtime @   create.js:73
(anonymous) @   runtime.js:59
(anonymous) @   runtime.js:58
(anonymous) @   index.js:27
(anonymous) @   promise-middleware.js:20
(anonymous) @   resolvers-cache-middleware.js:52
fulfillResolver @   index.js:445
(anonymous) @   index.js:404
setTimeout (async)      
fulfillSelector @   index.js:399
selectorResolver    @   index.js:416
(anonymous) @   editor.js:74
(anonymous) @   index.js:139
__experimentalMarkListeningStores   @   registry.js:99
(anonymous) @   registry.js:158
(anonymous) @   index.js:118
useSelect   @   index.js:138
Editor  @   editor.js:49
renderWithHooks @   react-dom.development.js:14938
mountIndeterminateComponent @   react-dom.development.js:17617
beginWork   @   react-dom.development.js:18731
beginWork$1 @   react-dom.development.js:23314
performUnitOfWork   @   react-dom.development.js:22292
workLoopSync    @   react-dom.development.js:22265
performSyncWorkOnRoot   @   react-dom.development.js:21891
scheduleUpdateOnFiber   @   react-dom.development.js:21323
updateContainer @   react-dom.development.js:24508
(anonymous) @   react-dom.development.js:24893
unbatchedUpdates    @   react-dom.development.js:22038
legacyRenderSubtreeIntoContainer    @   react-dom.development.js:24892
render  @   react-dom.development.js:24975
initializeEditor    @   index.js:141
(anonymous) @   post.php?post=5&action=edit:3649

No correct solution

OTHER TIPS

Can you help me identify what the problem is and how can I prevent this? Where is this request coming from?

The shortcode is only processed on the frontend. As far as the block editor is concerned the URL specified is [picsum] which is an unprocessed shortcode.

There is no simple fix to this, and making it work will require extensive and continuous modifications to the fundamentals of how the block editor works that will lead to problems. For example, you could filter the block and dynamically replace the attribute with an actual URL, but then the new URL would get saved not the shortcode. Additionally, each shortcode will need to be processed via an AJAX call and independently, so they would not interact with each other, breaking a lot of functionality based on shared variables. At any moment the core blocks behaviour may remove all of this, undoing all the work. Also what should happen if the user tries to edit the image, crop/rotate, or replace it? You can't crop a shortcode.

Shortcodes in HTML attributes are not the solution you were hoping for and you have hit a dead end.

In this specific example, it would be easier to create an attachment that has an image URL generated by filters so that it's the equivalent of the picsum shortcode, but this is a separate task and one that likely does not help you as you mention in the comments this is just a simplified example.

Fundamentally this will require either creating custom blocks or implementing alternatives using filters.

For example, if your goal is to dynamically populate the src for the image, you can use JS filters to add props and controls for choosing a data source, then replace core attributes with the dynamic values. You can the use the PHP block rendering filters to place the dynamic values in the src html attribute when the content is rendered.

For inline text, the rich-text format library API can be used to insert a shortcode while displaying the processed value to the user. This is very similar to how inline images work where an image block is inserted inline yet an inline image tag is what gets saved

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top