Are there or could there be added JavaScript events (for example on publish) we as theme / plugin developers could hook onto to run our own callback functions?
There are times when on pre or post publishing there are additional custom steps we want to run.
As an example of where this would be useful is on a project I am currently working on. We have a custom publishing workflow:
So what we need is to be able to do in this case is following the publish capture the response from WordPress REST API, and perform a redirect based on the new post ID that is returned.
As an example of how this could work as a plugin / theme developer would be to register for an event, something like this:
window.wp.events.registerListener( 'postPublish', ( xmlHttpRequestObj ) => {
// my code here...
} );
We are able to work around this by capturing all ajax requests with something like the following, but to have event provided by Gutenberg would be much more desirable as this is pretty much a hack:
const thisObject = this;
window.XMLHttpRequest.prototype.send = function() {
const request = this;
const intervalId = window.setInterval( () => {
// If this is not a response or meetings the given criteria.
if ( request.readyState !== 4 || ! thisObject.testFunction( request ) ) {
return;
}
// Call the call back function.
thisObject.callback( request );
clearInterval( intervalId );
}, 1 );
return thisObject.originalSend.apply( this, [].slice.call( arguments ) );
};
Apologies in advance if this already exists and I have missed it!
Yes 100% agree with you @IeuanCaseyNewton
We could use @wordpress/hooks
package which is JS implementation of WordPress hooks. This library is already integrated into new editor. You can find full API here. I'm still not sure what would be the best way to use it. How is it implemented in the current editor?
In the classic editor updates are performed as post backs rather than ajax requests. This meant we were able to just send a 301 redirect to the editor on publish when we want to switch the editor between the post and the amendment, something like this:
add_action( 'pre_post_update', array( $this, 'maybe_create_amendment' ), 50, 2 );
...
function maybe_create_amendment( $post_id, $data ) {
...
wp_safe_redirect( get_edit_post_link( $amendment_id, null ) );
}
In the classic editor updates are performed as post backs rather than ajax requests. This meant we were able to just send a 301 redirect to the editor on publish when we want to switch the editor between the post and the amendment, something like this
I'm trying to find out how that could translate to the new editor and the way it works.
I have no idea how WP REST API works, but I would assume that you can use some hook on the PHP side which would return a different result from the request when necessary. In the example you shared, it would return the redirect url when the amendment is created. Then we would need to have another hook on JS side which could intercept the result of the API call and execute custom JS code which would be able to use the returned redirect url to perform redirect on the client. Does it make sense what I'm saying? I want to make sure we can identify where we exactly need to add extensibility points and how much we can defer to the existing architecture.
Hey @gziolo
So in our workaround we are using the WordPress REST API. So what we are doing is instead of performing the redirect on publish, we are responding with the ID of the created amendment:
// If this is the WordPress REST API (Gutenberg).
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
$response = array(
'data' => array(
'id' => $post_id,
),
);
wp_send_json( $response );
Then we are using the JS ajax intercept code I have in the issue description to then detect this change in ID to then perform a redirect. This intercept code is capturing all ajax requests to find the one that was for publish and checking if in the response if ID has changed.
What would be better is if Gutenberg provided a hook that could call a custom callback function on post publish, passing the server response as a parameter to that call back.
So it sounds like all you would need would be a doAction
event fired with the newPost
data here -
https://github.com/WordPress/gutenberg/blob/master/editor/store/effects.js#L89 - after the post is successfully saved that passed the value returned from the request, does that sound right?
@IeuanCaseyNewton & @gziolo
Something like this would leverage hooks by triggering an explicit action:
https://github.com/WordPress/gutenberg/commit/0b5c712ed4c80410132149d9969947ddbb5b781d
You would then hook in to that action to handle the updated id.
Ultimately we would want to add similar actions for other events, perhaps a more clever solution could do actions for every redux effect automatically.
Hey @adamsilverstein - This sounds just like what we need - thanks! I will try using your branch later and let you know. Although as you mention others will probably need more events than just this, such as pre-post update (before it sends the update request to the server).
Ultimately we would want to add similar actions for other events, perhaps a more clever solution could do actions for every redux effect automatically.
@aduth or @youknowriad - can you confirm whether proposed solution by @adamsilverstein would be the way to go for all effects or should we rather add hooks case by case?
I'd like also to share one concern about the proposed solution by @adamsilverstein. In this particular case, I would expect to see a completely different behavior when action result is returned from the server, so we might not want to dispatch all default actions. We might want to rethink how we handle all the side-effects in general if we want to support hooks in here.
@adamsilverstein, I should start with many thanks for your valuable input here 馃挴 This is a very interesting use case, I'm sure we will find a way to make this flexible enough to support more sophisticated user flows.
One advantage I can see to adding desired hooks case-by-case is that this allows us to document them inline (with JSDoc). This was hugely successful for the php hooks in WordPress core and is now used to generate the reference here: https://developer.wordpress.org/reference/hooks/.
One advantage I can see to adding desired hooks case-by-case is that this allows us to document them inline (with JSDoc). This was hugely successful for the php hooks in WordPress core and is now used to generate the reference here: https://developer.wordpress.org/reference/hooks/.
@adamsilverstein yes, it makes sense what you shared. Do you plan to open a PR with some proposals how to tackle hooks inside effects?
Do you plan to open a PR with some proposals how to tackle hooks inside effects?
Yes, I'll work on a PR.
@IeuanCaseyNewton I started working on a PR to add an action, then realized I think you can detect the post status change to published using the existing wp.data
api. Can you try this and see if it solves your use case:
const { subscribe } = wp.data;
const initialPostStatus = wp.data.select( 'core/editor' ).getEditedPostAttribute( 'status' );
if ( 'publish' !== initialPostStatus ) {
// Watch for the publish event.
const unssubscribe = subscribe( () => {
const currentPostStatus = wp.data.select( 'core/editor' ).getEditedPostAttribute( 'status' );
if ( 'publish' === currentPostStatus ) {
// ...do something here - the post has been published
}
} );
}
how do you want to use the pre Publish event you mentioned? Are you trying to make publish-ability conditional?
Hey @adamsilverstein
Sorry for the delay in getting back to you - I did not see your message. Yes - this works well for us! I was not aware of wp.data.subscribe. Thanks for your help!
I can now remove my ajax intercept code.
@adamsilverstein, awesome tip 馃憤
Can we close this one? Do we track a similar use case where we would like to prevent publish until some certain action or state change happens? I think this is the last missing bit to make all this publish flow easy to customize. An example would be, keep Publish
button disabled until the user ticks checkbox field.
From my point of view my initial issue has been resolved so can be closed.
@IeuanCaseyNewton 馃憤
Most helpful comment
@IeuanCaseyNewton I started working on a PR to add an action, then realized I think you can detect the post status change to published using the existing
wp.data
api. Can you try this and see if it solves your use case:how do you want to use the pre Publish event you mentioned? Are you trying to make publish-ability conditional?