Is your feature request related to a problem? Please describe.
There is no concise way in Gutenberg to fire a JavaScript callback when a post save operation is finished. You can cobble something together using wp.data.subscribe
, but you have to keep track of state yourself, especially when processing updates to an already published post.
Describe the solution you'd like
It would be helpful to have a hook available to call a user-specified function when a save operation successfully concludes, especially one that is able to fire after both the REST request and the POST operation for metaboxes (if present) have concluded. This could be at least a partial solution to #12903 in that developers could take an action in Gutenberg with the full post object after all save operations have concluded, including sending an additional REST request to perform actions for plugins, like indexing a post in Elasticsearch or publishing/updating it in Apple News.
Describe alternatives you've considered
Using wp.data.subscribe
, but this requires that you manage state yourself so that the callback fires once and only once after the post has fully and successfully saved. The subscribe callback ends up getting called a lot and nearly all of those calls can be ignored. Also, processing data server-side using a save_post
callback, but this is susceptible to the problems outlined in #12903. Especially for developers that are looking for a simple way to say "give me the state of a post after it has saved to the remote," implementation via a hook would be ideal.
Hi @kevinfodness thanks for opening this. This looks like a duplicate of https://github.com/WordPress/gutenberg/issues/13413, can we consolidate the discussion there?
The same has been reported in #15568, which was also closed as a duplicate of #13413. Let's focus on that one 馃憤
@swissspidy @adamsilverstein I think this should stay open as a separate issue. #13413 is about _pre-save validation_, which is distinctly separate from a _post-save event_ (action).
I should also note that this is different from #15568 as well, which is also about validation.
any update on this?
Chiming in that this does feel quite different than the issue it was closed for. wp.data.subscribe()
isn't actually called (at least not in the latest version of Gutenberg) once the saving is completed.
@WPprodigy Good point, this is a slightly different use case, however I would expect to still be able to handle this using subscribe. I'm going to dig a bit further to see if it possible currently. I will report back here once I try.
@WPprodigy
Can you give something like this a try? The snippet leverages isSavingPost
. when we see this event start we set checked to false. when we see it not true and checked is false, we check again.
In this way you can use subscribe like a triggered action, although that is separate from the issue @kevinfodness described here, which I understand as requesting that Gutenberg fire a specific (single) action (eg. wp.hooks.doAction
) after the save to prevent having to use subscribe at all. If does feel like a common enough pattern that we should consider ways to make it easier for developers to tap into.
import { select, subscribe } from '@wordpress/data';
const { isSavingPost } = select( 'core/editor' );
var checked = true; // Start in a checked state.
subscribe( () => {
if ( isSavingPost() ) {
checked = false;
} else {
if ( ! checked ) {
checkPostAfterSave(); // Perform your custom handling here.
checked = true;
}
}
} );
The solution proposed by @adamsilverstein is a good one for post save behavior. That said, this has come up a few times and it was proposed lately on #core-js chats to make this code easier by introducing a subscribeOnChange
API to the data package.
wp.data.subscribeOnChange( () => wp.data.select( 'core/editor' ).isSavingPost(), ( isSaving ) => {
if ( ! isSaving ) {
// saving is finished do something
}
} )
I think we should open a new dedicate issue to track this addition. I'm still not sure whether this belongs to the data package or compose, or something else, since it's just a small JS utility with no dependency.
@youknowriad @adamsilverstein for my own edification, what's the argument against firing a wp.hooks.doAction
? Are there performance concerns, is the Gutenberg team trying to avoid using wp.hooks
, ... something else? Since that would prevent developers from having to use subscribe()
, it seems like a significantly more performant option to me from the extensibility side.
Are there performance concerns, is the Gutenberg team trying to avoid using wp.hooks
yes, we try to avoid hooks because we found that this is not the best abstraction for client side applications (there's some discussions in a previous #core-js meeting). The hooks API is not reactive, it's more suited for single threaded applications, while JavaScript is async by nature, using hooks will quickly result in buggy code that is hard to maintain or make sense of.
We had some specific examples in the past where we used hooks and decided to rollback to more specific APIs (block style variations come to my mind).
in terms of extensibility, the data API is the central layer for client side code, as it has selectors
to retrieve the data (state), actions
to mutate the data and subscribe
to be informed about data change.
The performance argument is a good one but the unique subscribe and global state is at the root of the Redux architecture, and performance is modeled around immutability, which means objects and arrays don't mutate their content (never), instead, we generate new instances each time a change is required, this makes it easier to use strict equality (performant) and prevent the downsides of a unique subscribe. All these patters work well tied to React components where you could use useSelect
that takes care of the subscriptions for you while ensuring performant code.
When hitting update button, the checkPostAfterSave()
from https://github.com/WordPress/gutenberg/issues/17632#issuecomment-583772895 will occur before the server processes the update POST request, and before the 'Updating...' button changes back to 'Update'. This is still too early and not what I need. I'm trying to retrieve data from a REST API endpoint after each post update (ie after the Updating... button turns back to Update and the POST request has returned its 200 response) but it just doesn't seem possible with Gutenberg at this stage.
@swissspidy should not have closed this issue. It's not a duplicate of the one he marked.
It鈥榮 still holding true that this should be done using the subscribe functions
There is no way for subscribe to know that an update has completed. The closest we get is with the code snippet provided here which happens before the POST request has returned or even executed on the server.
I can't do an apiFetch() in every single subscribe call because it's called 50 times after that happens as well as during and before and also when we're not updating.
There is still not a single way anyone has been able to run an action a single time after a post update completes therefore what you're saying is not true. subscribe() can't do what we need it to do.
before the 'Updating...' button changes back to 'Update'.
@Flynsarmy Are you sure about this? "isSavingPost" is the exact check the button uses to determine state and thus what the button reads - https://github.com/WordPress/gutenberg/blob/master/packages/editor/src/components/post-publish-button/index.js#L212.
I can't do an apiFetch() in every single subscribe call because it's called 50 times after that happens as well as during and before and also when we're not updating.
What are you trying to fetch?
You should only call fetch once, when saving happens then is no longer happening. the subscribe code only checks if the saving state has changed.
There is still not a single way anyone has been able to run an action a single time after a post update completes
This is exactly what the linked code describes how to do:
If you need to wait for the next save event, start over at step 1.
That said, this has come up a few times and it was proposed lately on #core-js chats to make this code easier by introducing a subscribeOnChange API to the data package.
@youknowriad is this still something you want to add? Shall I create a follow up issue?
Most helpful comment
@swissspidy @adamsilverstein I think this should stay open as a separate issue. #13413 is about _pre-save validation_, which is distinctly separate from a _post-save event_ (action).