Sometimes it is crucial to validate input values on the server side, e.g. check if an email address is valid within the company by checking against an LDAP-Directory. (Server side because "Never trust the client" rules).
I could not figure out (overlooked?) a way to do that with Gutenberg.
return new WP_Error( 'rest_invalid_param', 'E-Mail not found in directory', array( 'status' => 400) );
In a second step it would be helpful to trigger a JS event in the corresponding block, so that a visual feedback can be given in the right place.
PS.
Is there some kind of validation framework present/planned in Gutenberg that i did not see?
π I agree with the general premise that it should be possible to validate block values (either client-side or server-side) and display an error when they're invalid.
@adamsilverstein can you help answer this question? I'm not familiar enough with REST API integration with Gutenberg but I would assume you can use server-side hooks. The only remaining question is how to propagate that response to the client properly, i.e. how to shape the response to make sure it can be understood by Gutenberg. I think we use notices to display messages, so this might work out of the box.
Worth noting: the Customizer already has a validation API like this. As Gutenberg and the Customizer will eventually need to reconcile, it might be worth cribbing from the Customizer if we can.
cc @westonruter
And the Customizer's validation API is designed to feel like the REST API's validation API. With the move to defining all block attributes server-side and having them exported to the client (see #2751) then this means we can amend the attributes schema with things like sanitize_callback
and validate_callback
to use during validation. The REST API endpoint to insert/update a post could run through the block validate/sanitize callbacks prior to saving the post content.
@westonruter, I started working on moving the definition of all block attributes server-side in #5802. The idea is to have also a filter on the server which allows plugins to add some automated changes to all blocks. I was thinking about adding validation step just before all those definitions are exposed to the client. If you have some insights how this should be implemented, please leave a comment on #5802. In general, this blocks definition should be exposed as new REST API endpoint in the near future. So all that you shared aligns with what we are exploring at the moment.
@gziolo
can you help answer this question? I'm not familiar enough with REST API integration with
Gutenberg but I would assume you can use server-side hooks.
yes, the current REST API endpoints all include hooks at multiple points - before the query, on the response, etc. as long as you can identify the request, you can add whatever filter you want.
@gziolo @adamsilverstein @danielbachhuber Something else that comes to mind in relation to block validation is allowing pre-parsed blocks to be exposed in the REST API response. I think this was previously talked about as /wp/v2/posts/:id/blocks
or something. But that seems to be disconnected from the fact that the blocks are (for now) mostly managed as part of content
. So what if just as we have content.raw
and content.rendered
we also had content.blocks
? This could be an array data structure of blocks (and their nested blocks). A client could then manipulate the blocks in their parsed representations and then PUT
back the modified content.blocks
data to update the post. This is where the validate_callback
and sanitize_callback
functions could be called on the blocks, in the rest_pre_insert_{$this->post_type}
filter. If there is a validation error the filter could return a WP_Error
to cause prepare_item_for_database
to return an error and thus cause update_item
to be rejected.
what if just as we have content.raw and content.rendered we also had content.blocks?
@westonruter what i was proposing as a read only form in https://github.com/WordPress/gutenberg/pull/2649... I like your idea of making it writable as well.
So what if just as we have
content.raw
andcontent.rendered
we also hadcontent.blocks
?
@mtias and @mcsf, I think this is something you should respond to. I personally don't feel like we should reimplement all the logic we already have on the client, but I don't know the bigger picture and in particular, I'm not aware of any use case where it could be used.
My gut tells me we should be cautious with what we implement on the server, for a couple of reasons:
ServerSideRender
(see #5602) β but by optimizing and providing out-of-the-box tooling for certain server-side scenarios we create impetus for those flows.wp:paragraph
. It lends itself to a better user experience for a number of reasons (as cited for ServerSideRender
, namely no-latency interactivity).wp:block
) and the way they reuse WordPress tools (CPT, REST endpoint) to potentially retain control over every datum. Yes, this requires some added boilerplate, but that may be justified for more ambitious blocks that need to validate and guard a lot of information.Just some quotes:
The bottom line is that anything client side can be manipulated (disabled/completely got rid of/bypassed or modified) by the end-user. So any sort of "client side validation" is totally useless from a security perspective. You must always validate things server side.
And you must do it in the same request that would finally save the data, not in a seperate ajax request before.
Client side validation is purely about user experience
So any sort of "client side validation" is totally useless from a security perspective.
Yes, though this is about more than security (e.g. validation is also about correctness or about successfully guiding the user). If you depend on block-level or field-level validation even for privileged users (can_edit_post
, etc.) _for security_, then you probably have a larger issue at hand. The same goes with user content up predating Gutenberg.
In any case, all content should always be sanitized and escaped regardless of block adoption.
not in a seperate ajax request before.
My mentioning endpoints and PHP APIs didn't imply relying on _ad hoc_ or _post hoc_ server requests to "fix" saved data βΒ that would be bad. I meant either PHP-side APIs to be used in server-side hook callbacks, or an altogether separate transaction for saving certain blocks (like Reusable Blocks).
Yes, though this is about more than security (e.g. validation is also about correctness or about successfully guiding the user)
Sure, but imho the integrity of data is as important. E.g. the integrity of an email address may be crucial because secret internal infos will be sent to it. So there should be no way to manipulate it. Should have mentioned that in my reply, sorry.
the integrity of data is as important. E.g. the integrity of an email address may be crucial because secret internal infos will be sent to it. So there should be no way to manipulate it.
That's fair.
I'm still inclined to say that, for now, developers (and third-party solutions which are likely to emerge) should be left to solve this as most fitting for their use cases, provided we ship the basic tooling as mentioned in my original comment. What are your thoughts on that, @wsydney76?
@mcsf I would like to see a "how to do validations in Gutenberg" - guide.
For server side validations (a bit high level, as i am not so up-to-date any more):
I think most developers would finally like to see an approach that is so close as possible to well known MVC-patterns e.g.
public function getElementValidationRules(): array
{
$rules = parent::getElementValidationRules(); // the default rules from parent email field
$rules[] = ['validateEmail'];
return ['validateEmail'];
}
public function validateEmail($element){
$fieldname = $this->handle;
$email = $element->$fieldname;
$service = addonsPlugin::getInstance()->myHelpers;
if ( ! $service->validateEmail($email) ) {
$element->addError($fieldname , \Craft::t('addons', 'Please use a valid corporate email'));
}
resulting in
but i definitely understand that a more low level approach is more appropriate right now.
Thanks for your effort.
PS.
Having read the announcement of ACF blocks yesterday and knowing that ACF heavily relies on validations (including server side), maybe the two of you could join forces?
@wsydney76, thanks for your reply and for your patience. I don't have a straight answer before sharing some open questions I still have. Below are some thoughts on my mind, followed by my best approach at answering your doubts. Sorry for the long reply, but I hope it can be helpful in the end.
$ldap_directory->validate_address
) should run on the server and not on the client? Why? I ask because by addressing this on the client (whether locally or, in this case, via remote call to your LDAP service) we can provide a more immediate and granular experience that would satisfy one of the definitions of "validation". This pattern is the one we see with <ContrastChecker />
(see gif), and one that I'd like to see more widely used.Sure, but imho the integrity of data is as important. E.g. the integrity of an email address may be crucial because secret internal infos will be sent to it.
This brings me to:
a) What is the threat model here? What would constitute a breach of security, and how is WordPress's basic capabilities model inadequate? Is the page we're editing to be edited by other users that are not trustworthy?
b) When and how will the provided fields be used aside from display? You suggested e-mail delivery, which makes sense, but we would always be expected to sanitize our data anyway, e.g.
$address = sanitize_email( $user_input->email_address );
$address = $ldap_directory->validate_address( $address );
if ( is_wp_error( $address ) ) return $address;
$mailer->send_to( $address, $subject, $body );
Blocks are pretty versatile in the ability to deal with both more visual and more behavioral information, but also in the ability to deal with information of varying scope: block attributes are by default local to each block, but they can be local to the post thanks to meta attributes β see meta paragraph in docs).
It seems to me that, assuming that we could have client-side handling of the validation (read: the validation could be provided by a remote service, but the client mediates the request), the rest would nicely be accomplished with meta-based block attributes:
address
attribute, which maps to my_address
in post meta.'updated_post_meta'
), thereby guaranteeing integrity.my_address_validation_error
) if the address is invalid β upon saving, this new value would be added to the POST response sent back to the client, possibly triggering an error notice.Having read the announcement of ACF blocks yesterday and knowing that ACF heavily relies on validations (including server side), maybe the two of you could join forces?
From the beginning, Gutenberg wanted to bring users and devs a world of possibilities in terms of block development, hence the rollout of the JS APIs β particularly, the functional nature of edit
and save
β as the primary extensibility methods. That said, the idea is definitely on the table of providing good defaults in the form of a server-side-capable block description language with automated data binding and rendering is definitely on the table. That is, in the future we may be able to call register_block_type
on the server and pass it a deep object that will render on the server as an interactive block that handles user data.
However, that falls well outside the scope of 5.0, which is also why I'm happy to see efforts from ACF and any other player to provide specialized interfaces mindful of their users' specific needs. However, I don't expect Gutenberg to join efforts with any particular plugin, for two main reasons:
@mcsf Thanks for your answer,
for your patience.
No problem, i opened this and some other issues back in december when we (some companies and agencies) were evaluating the (continued) use of WordPress and Gutenberg as a platform for more advanced and sophisticated applictions, where validation is a crucial part. Since then all of our clients figured out that WP in it's between-the-worlds state does not fulfill their requirements of having a proven, stable, comprohensive solution and switched to other CMS's.
Don't ge me wrong, that does not mean that WP/GB is a bad product, not at all, it's simple not the right choice for every task. (And no, you can't sell this classic editor thing to companies).
As i am no longer involved with GB right now, please understand that i am not able to answer your questions in every detail. Sorry if i understood something wrong.
Is it a requirement that a validation service .. should run on the server and not on the client?
Yes.
Server side: Mandatory. Assures the integrity of data. Client request's can always be manipulated and come from other sources than GB.
Client side: Optional. Provide a better User Experience.
What is the threat model here?
That malicious people are always cleverer then i am and will find ways that i don't even think of.
but we would always be expected to sanitize our data anyway
Yes, that is an additional level but used as the only validation it does not give a user feedback and you don't want to have unchecked data in your db.
Before Gutenberg, what would a solution for this have entailed?
Something like described in #3964 .
but they can be local to the post thanks to meta attributes
Yes, always assumig the data is stored as meta attributes. Accessing data local to a block is ... (insert your own wording here).
Since we're consulting an external service for the address validation, we didn't need to duplicate business logic between client and server.
Yes, the mandatory server side validations could be exposed to a client via a service provided by our application, which may encapsulate a call to a corporate ldap service. The client should not contact an external service directly. It may not even be allowed to do so. I am no security expert and cannot say if methods like hashing a value for the final submission to protect it from being tampered is secure enough.
but we'd need to build the tooling to send them on one end and receive and display them on the other,
Yes, i think there are some issues around something like a notification api ?
So with that i am out of the game, and want to thank everybody for their work.
PS.
Personally i would be fine with closing this issue, but i am very sure this topic will continue to pop up, so you may want to leave it open.
Since then all of our clients figured out that WP in it's between-the-worlds state does not fulfill their requirements of having a proven, stable, comprohensive solution and switched to other CMS's.
Don't ge me wrong, that does not mean that WP/GB is a bad product, not at all, it's simple not the right choice for every task. (And no, you can't sell this classic editor thing to companies).
No worries, thanks for being upfront about it.
Yes, i think there are some issues around something like a notification api ?
Yes, #5975.
Personally i would be fine with closing this issue, but i am very sure this topic will continue to pop up, so you may want to leave it open.
Thanks. My idea is to close this one, since its scope is more ambitious, and open a more focused issue suggesting some documentation around possible practices to guide developers around server-side block operation.
Closing per #9463.
Most helpful comment
Worth noting: the Customizer already has a validation API like this. As Gutenberg and the Customizer will eventually need to reconcile, it might be worth cribbing from the Customizer if we can.
cc @westonruter