-
Notifications
You must be signed in to change notification settings - Fork 10.8k
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
Reduce risk of prematurely dropping meta box error messages #32540
Conversation
💡 Please ignore linting errors. They either relate to lines I did not change or are false positives connected with PHP 7.0 compatibility (I created this PR to address the latter issue). |
38fb3d8
to
1d0c35d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pre-approving, as this PR fixes one class of problems with this code, but as noted in the description, there are more problematic scenarios that can occur, and even after this PR, the mechanism is still vulnerable to race conditions. While not perfect, I agree that this reduces the potential for errors.
I wonder if we should (can we?) hook the append_to_error_store
to some other action... maybe to admin_footer
or something like that? That way, the AJAX, cron and REST API requests won't interfere?
} | ||
|
||
$existing_errors = get_option( self::ERROR_STORE, array() ); | ||
update_option( self::ERROR_STORE, array_unique( array_merge( $existing_errors, self::$meta_box_errors ) ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit unfortunate that this is still vulnerable to race conditions. Perhaps out of scope for this change, but I wonder if it wouldn't be better to use the self::ERROR_STORE
as a prefix and store each msg with a unique string id e.g. by using uniqid
and then get the relevant option only for this request... Not sure what would be the best way to pass the id around, though. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes ... or a keyed array, and the code responsible for generating the message would be responsible for building it in a non repetitive way (ie, the existing bad mime-type error is very long, we probably wouldn't want to repeat it 10 times for 10 problematic URLs but instead include it once and reference each URL that was an issue—or just generalize it in some other way).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly user sessions and/or pinning messages to a specific user ID (see also this comment—imho we should do a deeper think about our needs and expectations).
@@ -104,7 +128,7 @@ public function output_errors() { | |||
echo '</div>'; | |||
|
|||
// Clear. | |||
delete_option( 'woocommerce_meta_box_errors' ); | |||
delete_option( self::ERROR_STORE ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still a problem, as another request can pick up the error message and deletes the option before the originating request gets to it. When I tested this, it's rather easy to trigger this by putting a breakpoint just after update option from tab/request 1, then opening another tab from the same admin and seeing the error on an unrelated screen and no error in tab 1. I wonder if we could fix this by outputting the error only if referer is the same (and storing it along with the message in the option table)? Maybe an idea for future improvement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree (see also this comment).
* | ||
* @since 6.5.0 | ||
*/ | ||
public const ERROR_STORE = 'woocommerce_meta_box_errors'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice touch here!
💯 All valid points, thank you for the review (@peterfabian). Yes, this is very much a partial fix/incremental improvement and doesn't solve all of the problems. I feel we should follow-up with more work, and perhaps it would even be a nice idea to start with an RFC as there are a few angles we might consider.
|
Added a task to scope further improvements to our waiting list (internal link: p7bje6-3Uh-p2). |
Hi @barryhughes, thanks for merging this pull request. Please take a look at these follow-up tasks you may need to perform:
|
Changes proposed in this Pull Request:
Within the product editor—and perhaps some other admin screens we own—we use flash messaging to display errors. That is, we add error messages in one request, temporarily storing them via the options API, then retrieve and render them on a subsequent request. However, in some cases this fails:
How to test the changes in this Pull Request:
Owing to the nature of the problem, it's hard to contrive a test. You may or may not encounter this issue depending on how lucky or unlucky you are. However, we can at least confirm that, with this change in place, flash errors still work as expected within the product editor:
Additionally, with reference to the tests I added, temporarily changing this line from:
To:
Mimics how things previously worked (in that the
save_errors()
method was being called during request shutdown), and will cause that test to fail. Could be helpful as a different way to see the problem and the fix.Other information:
This closes off one scenario, but I'd note there are other failings it doesn't touch. For instance, in a busy multi-user system one person could make an edit to a product resulting in an error, and another could open the same product for editing a split-second later and be presented with the error (could be confusing for them), which the first user would then not see (and they may then move on without addressing the problem, which they would be unaware of).
We aren't fixing that here, however. Perhaps aspects like this would be better dealt with when we rebuild more of the admin environment.
FOR PR REVIEWER ONLY: