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

Extensibility: Add a way for third parties to perform additional save validation #13413

Closed
noisysocks opened this issue Jan 22, 2019 · 25 comments · Fixed by #58022
Closed

Extensibility: Add a way for third parties to perform additional save validation #13413

noisysocks opened this issue Jan 22, 2019 · 25 comments · Fixed by #58022
Assignees
Labels
[Feature] Extensibility The ability to extend blocks or the editing experience [Status] In Progress Tracking issues with work in progress [Type] Enhancement A suggestion for improvement.

Comments

@noisysocks
Copy link
Member

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

Plugins like Advanced Custom Fields require a way to perform additional validation when a post is published or updated. This validation can be asynchronous.

Describe the solution you'd like

I'm thinking that the most flexible solution here would be to wrap the call to apiFetch() made by requestPostUpdate() with a filter. This will let third parties perform as much additional asynchronous validation as they would like, or even replace the entire API call with their own.

Example:

wp.hooks.addFilter( 'editor.updatePost', async ( options ) => {
	if ( ! performPreSaveValidation() ) {
		throw 'The post is invalid! A pre-save check failed.';
	}
	const response = await wp.apiFetch( options );
	if ( ! performPostSaveValidation() ) {
		throw 'The post is invalid! A post-save check failed.';
	}
	return response;
} );

Describe alternatives you've considered

I considered an alternative approach using PluginPrePublishPanel but this does not handle the case where validation needs to happen on an update to an already published post.

@noisysocks noisysocks added [Type] Enhancement A suggestion for improvement. [Feature] Extensibility The ability to extend blocks or the editing experience labels Jan 22, 2019
@noisysocks
Copy link
Member Author

@gziolo @youknowriad: Any thoughts or ideas for alternative approaches?

@youknowriad
Copy link
Contributor

Adding @aduth and @adamsilverstein as they may have thoughts on async filters.

@gziolo
Copy link
Member

gziolo commented Jan 22, 2019

I'm not that familiar with all the parties involved in the post save flow. I know that we use all those effects for actions which operate on the store:
https://github.com/WordPress/gutenberg/blob/master/packages/editor/src/store/effects/posts.js

I think @aduth had some thoughts about how to deal with extensibility in that area.

@aduth
Copy link
Member

aduth commented Jan 22, 2019

Previously: #7020

@aduth
Copy link
Member

aduth commented Jan 22, 2019

In what way is lockPostSaving insufficient for achieving this?

@noisysocks
Copy link
Member Author

In what way is lockPostSaving insufficient for achieving this?

Calling lockPostSaving() from a component within PluginPrePublishPanel is insufficient because the pre-publish panel does not appear when an already published post is being updated.

There's no other good opportunity to call lockPostSaving(). ACF needs to do additional server-side validation when the post is being published or updated. This means we'd have to call lockPostSaving() when the Publish or Update button is clicked, by which time it's obviously too late to lock post saving.

@noisysocks
Copy link
Member Author

Have a look at AdvancedCustomFields/acf#113 for some context on the requirements here.

@gziolo
Copy link
Member

gziolo commented Jan 23, 2019

It took me some time to find a very related issue #4674 where TLDR; is

There are times when on pre or post publishing there are additional custom steps we want to run.

The proposed solution by @adamsilverstein was sufficient for the author:

@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
		}
	} );
}

lockPostSaving might still turn out to be useful in such approach. I also recommend reading comments from #4674 to check other ideas.

@noisysocks
Copy link
Member Author

noisysocks commented Jan 25, 2019

Such an approach won't work as it will be too late to lock post saving by time currentPostStatus is 'publish'. We want to prevent post saving after the Update or Publish button is clicked but before the request to PUT /wp/v2/posts/:id is made.

@adamsilverstein
Copy link
Member

Such an approach won't work as it will be too late to lock post saving by time currentPostStatus is 'publish'. We want to prevent post saving after the Update or Publish button is clicked but before the request to PUT /wp/v2/posts/:id is made.

Good point. My original proposal of something like a filter for the 'isPublishable' selector could have addressed this. I am working a similar feature for another plugin (trying to prevent publishing when certain conditions are not met when the user clicks publish or update). I'll report back here if I have a viable approach for this without adding a new filter.

@acafourek
Copy link

My use case for a similar need:

  • Publishing a Product in our WooCommerce setup triggers a sync action with 3rd party fulfillment tools
  • When a Product is published, the values from 2 meta fields and a taxonomy are used to generate/assign a SKU number that is used in syncing with those 3rd party tools
  • We're currently using an approach very similar to the one previously shared above that does some validation (to make sure those meta/tax fields are defined) after publishing, then changes the status back to Draft if validation fails.
  • The result is that the user gets a visual notification that they've forgotten something, but since the Product has been published, it's already triggered the sync to the 3rd party tools.
    • We rely on the user to see our notice and assume that they'll update immediately and update. If not, we have a product that has been synced to the 3rd parties that is no longer published in WC.

We're working around this with subsequent calls to those 3rd party tools when a product is changed back to draft, but ideally the transition to publish wouldn't occur if we were to do a pre-save validation.

@lex127
Copy link

lex127 commented Feb 15, 2019

Sorry, I have a question on my closed case #13620

Why do you not listen MutationObserver for handling all changes in the DOM?

How do you plan to work with native browser spell check?

There are many other third party scripts which make changes using Range API (for changing some part of text). So you will ignore these changes too.

We can emulate changes after replace some part of text with Range API. We do it using fake InputEvent which we fire on editable field. But this is not clear solution. And this fake event doesn't work for Classic block (TinyMCE editor in Gutenberg).

Solutions suggested by you is not applicable in our case.

@aduth
Copy link
Member

aduth commented Feb 15, 2019

@lex127 I've responded to your questions in #13620.

@audiovisuel-uqam
Copy link

There is an issue in trac that seems related, at least server-side.
https://core.trac.wordpress.org/ticket/43019

@adamsilverstein
Copy link
Member

adamsilverstein commented Jun 23, 2019

Related: #16249 which adds the ability to lock (prevent) post autosaving.

@eballeste
Copy link

Any updates on this?

@jenilk
Copy link

jenilk commented Dec 13, 2019

Hello All,

I have created a ticket to WordPress where we can all contribute there. As this issue goes to a blocker we need to find the solutions as earliest.

Ticket: https://core.trac.wordpress.org/ticket/48959

Best
Jenil

@zhitaryksergey
Copy link

Any updates on this?

@adamsilverstein
Copy link
Member

Hi @noisysocks, @zhitaryksergey, @acafourek & @eballeste - I'm still trying to understand what is required here, or if perhaps your needs can be met with existing features - namely post saving/autosaving locks and data store subscriptions.

Such an approach won't work as it will be too late to lock post saving by time currentPostStatus is 'publish'.

Can you start with post saving locked and only unlock it when validation passes?

See my comment on the ACF thread - AdvancedCustomFields/acf#113 (comment)

@acafourek
Copy link

In an easy, perfect world, PHP would be able to easily validate the saving data - like an AJAX call to the back end that fires a filter like pre_save_post_validation($post,$new_data) which could be hooked into from any plugin or theme code.

But, everyone keeps telling me that JavaScript is the present and future :)

We're using some JS validation now that watches for field changes, then uses lockPostSaving, does some AJAX calls (unavoidable because we're validating against 3rd party tools using their PHP SDKs) and finally either allows publishing or dispatches a notice with error messaging.

It's all very doable to people with a lot of WP+Gutenberg knowledge and dev resources but it doesn't seem very straight forward to the less experienced. It would be great to roll everything up into one simple event or filter that lets you check what's being saved and return true/false with error message(s).

@christianMiguez
Copy link

Any of you guys have fixed or hacked it?

@marcwieland95
Copy link

marcwieland95 commented Aug 7, 2023

Hey there, I want to bring some attention to this issue. Advanced Custom Fields is waiting for years (3.5 years to be exact) for a hook to implement the much-used validation prior to Gutenberg (AdvancedCustomFields/acf#113).

Are there any updates on this or a reason why this can't be implemented?

Thanks

@adamsilverstein
Copy link
Member

adamsilverstein commented Jan 17, 2024

As per this comment - #44971 (comment) what is still missing here is an async preSave hook similar to the editor.__unstableSavePost added in that PR. Based on that work, maybe we can add this as experimental hook to start to see if it fits the use case.

@adamsilverstein
Copy link
Member

I took a pass at adding a preSave hook in #58022

@margolisj
Copy link
Contributor

Does editor.__unstableSavePost already work correctly as intended for every type of post/entity record save? I just ran into an issue where wp-calypso was wrapping the saveEntityRecord for metrics in a similar style as I was. I would assume there are other plugins that are doing the same thing and I'd like to cut this off before things get too messy. Also, I can't find any documentation on editor.__unstableSavePost. Does anyone know if there is any?

Thank you @adamsilverstein for your work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Extensibility The ability to extend blocks or the editing experience [Status] In Progress Tracking issues with work in progress [Type] Enhancement A suggestion for improvement.
Projects