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

Improve handling of validation errors in response cache and admin display #1190

Merged
merged 10 commits into from
Jun 1, 2018

Conversation

westonruter
Copy link
Member

  • Ensure response cache is varied by validation error sanitization status. If the response had been cached when all validation errors had marked as rejected (not-sanitized), then when one or more of those validation errors have their status changed to accepted (sanitized) then needs to make sure that the response cache will be updated. Otherwise, a validation error's status could change but no change would be reflected on the frontend.
  • Improve searchability of validation errors in invalid AMP URL posts by storing full text of validation error in the post_content, instead of just storing the sources. Note that this means the validation error data is duplicated in the amp_validation_error term description as well as in the post_content of the amp_invalid_url post type. This is not concerning because the size is small, the data will not be updated once written, and denormalization improves performance for searching.
  • Improve the “incompatible sources” summary so it shows more than just “core: wp-includes”.
  • Account for amp_validation_error_sanitized filter when displaying validation errors in admin. (And let second filter argument be flatter as just a $error array, instead of $context containing $error.) Prevent offering to change validation error status when filter is forcing a certain status. For example, if I want to make sure that invalid_attribute validation errors are always sanitized, I could add this:
add_filter( 'amp_validation_error_sanitized', function( $sanitized, $error ) {
	if ( $error['code'] === 'invalid_attribute' ) {
		$sanitized = true;
	}
	return $sanitized;
}, 10, 2 );

In the UI now, when looking at an invalid AMP URL post, this is indicated:

image

Likewise, in the list of validation errors, the checkboxes for doing bulk actions on such sanitization-forced errors are removed, as are the row actions:

image

@westonruter westonruter added this to the v1.0 milestone Jun 1, 2018
@westonruter westonruter requested a review from ThierryA June 1, 2018 06:00
@westonruter
Copy link
Member Author

Unit tests are still needed for the validation classes, but let's not let that hold this up.

continue;
}
$errors[] = array(
if ( $term && null !== $forced_sanitization ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional statement on line 213 is strict conditioning against true while here it is against null, is that on purpose?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. true means that the validation error is forced to be accepted (sanitized), whereasfalse means that the validation error is forced to be rejected (not sanitized). A null value means that there is no forcing because no filter is applying to force the sanitized state.

}
if ( $args['ignore_accepted'] && AMP_Validation_Error_Taxonomy::VALIDATION_ERROR_ACCEPTED_STATUS === $term->term_group ) {

if ( $args['ignore_accepted'] && ( true === $forced_sanitization || ( $term && AMP_Validation_Error_Taxonomy::VALIDATION_ERROR_ACCEPTED_STATUS === $term->term_group ) ) ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since $term->term_group is used in the conditional statement, it would be more bullet proof to check for isset( $term->term_group ) instead of just $term.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the $term->term_group property is always set because it is defined on the WP_Term class:

https://github.com/WordPress/wordpress-develop/blob/a26c24226c6b131a0ed22c722a836c100d3ba254/src/wp-includes/class-wp-term.php#L43-L49


$forced_sanitization = null;
if ( $args['check_forced_sanitization'] ) {
$error = $stored_validation_error['data'];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will throw PHP warning if $stored_validation_error['data'] isn't set. While probability is low, it would more bullet proof to check. In fact, this is what I got when reload a validation page before "Re-checking" it https://cloudup.com/cPPds8QsYVL.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right but you only had this problem because the data format of the post type is changed as of 3b484e8. Now that the validation errors are stored in the post type itself, we don't need to parse it out of the term as well. So it is expected that there would be a PHP warning as you observed. But it will go away once re-checking. Since we're in alpha I didn't think it was important to ensure back-compat for a previous alpha state.

@@ -966,33 +968,49 @@ public static function print_validation_errors_meta_box( $post ) {
} );
</script>

<?php
$forced_sanitized_count = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the notice is displayed if $forced_sanitized_count is bigger than 0, we could display the notice as soon as a $validation_error['forced_sanitization'] is found and break to avoid unnecessarily continuing the loop.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally I showed a different message when all of the sanitizations were forced vs some. So yes, this could break now.

<div class="amp-validation-errors">
<ul>
<?php foreach ( $validation_errors as $error ) : ?>
<?php
$collapsed_details = array();
$term = $error['term'];
$select_name = sprintf( '%s[%s]', AMP_Validation_Manager::VALIDATION_ERROR_TERM_STATUS_QUERY_VAR, $term->slug );
$term_status = $term->term_group;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I see the reason to store this in a variable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. It's no longer needed since the term_group is overridden in get_invalid_url_validation_errors.

@@ -155,11 +155,43 @@ public static function register() {
),
) );

add_filter( 'user_has_cap', array( __CLASS__, 'filter_user_has_cap_for_hiding_term_list_table_checkbox' ), 10, 3 );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this filter reset somewhere?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. It should not be reset. This is a permanent filter for the user caps.

$term = get_term_by( 'slug', $term_data['slug'], AMP_Validation_Error_Taxonomy::TAXONOMY_SLUG );
if ( isset( self::$validation_error_status_overrides[ $term_data['slug'] ] ) ) {
$sanitized = AMP_Validation_Error_Taxonomy::VALIDATION_ERROR_ACCEPTED_STATUS === self::$validation_error_status_overrides[ $term_data['slug'] ];
} elseif ( ! empty( $term ) && AMP_Validation_Error_Taxonomy::VALIDATION_ERROR_ACCEPTED_STATUS === $term->term_group ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be simplified to:

// ...
else {
	$sanitized = ! empty( $term ) && AMP_Validation_Error_Taxonomy::VALIDATION_ERROR_ACCEPTED_STATUS === $term->term_group;
}

* @param bool|null $sanitized Whether sanitized, or null if no default predetermined.
* @param array $error Validation error being sanitized.
*/
$sanitized = apply_filters( 'amp_validation_error_sanitized', $sanitized, $error );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return apply_filters( 'amp_validation_error_sanitized', $sanitized, $error );

@@ -966,33 +968,49 @@ public static function print_validation_errors_meta_box( $post ) {
} );
</script>

<?php
$forced_sanitized_count = 0;
foreach ( $validation_errors as $validation_error ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another approach:

$forced_sanitized_count = array_reduce(
	$validation_errors,
	function( $sum, $validation_error ) {
		return $sum + (int) isset( $validation_error['forced_sanitization'] );
	}
);

@westonruter
Copy link
Member Author

@ThierryA there, I'm feeling way better about this after https://github.com/Automattic/amp-wp/pull/1190/files/3e2ba8a..5458e9a

@westonruter
Copy link
Member Author

In 6dbdb0d a key improvement is made when accepting/rejecting validation errors from the invalid URL screen: now the URL will be automatically re-checked after the validation errors have been updated. This is very important in the case of errors like removed_unused_css_rules in particular, because if it is sanitized then all of the subsequent excessive_css validation errors automatically go away:

image

Now when changing the status of just removed_unused_css_rules and clicking Update, the result is then:

image

…error's sanitization status

Also prevent removable query vars from erroneously being carried into subsequent requests via referrer
@westonruter westonruter force-pushed the fix/response-cache-varying branch from 6dbdb0d to 2b089f3 Compare June 1, 2018 18:24
@kienstra kienstra self-assigned this Jun 1, 2018
Copy link
Contributor

@kienstra kienstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

Hi @westonruter,
This looks good. There are some minor points, but no blocker as long as you're happy with this.

}
$actions[ self::RECHECK_ACTION ] = sprintf(
'<a href="%s">%s</a>',
self::get_recheck_url( $post, get_edit_post_link( $post->ID, 'raw' ) ),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this use esc_url()?

@@ -708,9 +693,9 @@ public static function print_admin_notice() {
$errors_remain = ! empty( $_GET[ self::REMAINING_ERRORS ] ); // WPCS: CSRF ok.
if ( $errors_remain ) {
$class = 'notice-warning';
$message = _n( 'The rechecked URL still has validation errors.', 'The rechecked URLs still have validation errors.', $count_urls_tested, 'amp' );
$message = _n( 'The rechecked URL still has blocking validation errors.', 'The rechecked URLs still have validation errors.', $count_urls_tested, 'amp' );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of _n() to account for singular and plural.

@@ -792,6 +806,10 @@ public static function handle_validation_error_status_update() {
if ( empty( $_POST[ AMP_Validation_Manager::VALIDATION_ERROR_TERM_STATUS_QUERY_VAR ] ) || ! is_array( $_POST[ AMP_Validation_Manager::VALIDATION_ERROR_TERM_STATUS_QUERY_VAR ] ) ) {
return;
}
$post = get_post();
if ( ! $post || self::POST_TYPE_SLUG !== get_post_type( $post ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very minor point, but could this use $post->post_type instead of get_post_type( $post )?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it wouldn't make any difference though. 👍

<?php
$has_forced_sanitized = false;
foreach ( $validation_errors as $validation_error ) {
if ( $validation_error['forced'] ) {
Copy link
Contributor

@kienstra kienstra Jun 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're probably aware of this, but I saw notices on an "Invalid AMP Page (URL)" pages:

( ! ) Notice: Undefined index: forced in /srv/www/loc/public_html/wp-content/plugins/amp/includes/validation/class-amp-invalid-url-post-type.php on line 1015

amp-invalid-url

This occurred even after clicking "Re-check."

These could be from errors saved from before this PR. I tried bulk moving "Invalid Pages" to the trash, but this didn't help.

Still, you mentioned that we don't need backwards compatibility with an earlier "checkout" of 1.0. And the way validation errors are stored is very different from in 0.7.

@kienstra kienstra removed their assignment Jun 1, 2018
@westonruter
Copy link
Member Author

Aside, it's a good idea to reset validation state to a blank slate after this:

wp post delete --force $( wp post list --post_type=amp_invalid_url --format=ids );
wp term delete amp_validation_error $( wp term list amp_validation_error --format=ids );

@westonruter westonruter merged commit 90acca4 into develop Jun 1, 2018
@westonruter westonruter deleted the fix/response-cache-varying branch June 1, 2018 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants