Add more sanity checks to prevent PUC from inadvertently triggering a fatal error if one of its hook callbacks is called while the containing plugin/theme is being deleted.

PUC already used `upgrader_process_complete` to remove hooks when  the plugin version it was part of was deleted during an update. However, that did not catch more obscure situations, such as apparently being called from an unrelated AJAX request while the host plugin version was being deleted (a user sent a stack trace where it seems that was what happened).
This commit is contained in:
Yahnis Elsts 2023-11-15 18:49:00 +02:00
parent 9c1bddcd46
commit 5f251be064
2 changed files with 21 additions and 1 deletions

View File

@ -187,6 +187,21 @@ if ( !class_exists(Scheduler::class, false) ):
$state = $this->updateChecker->getUpdateState();
$shouldCheck = ($state->timeSinceLastCheck() >= $this->getEffectiveCheckPeriod());
if ( $shouldCheck ) {
//Sanity check: Do not proceed if one of the critical classes is missing.
//That can happen - theoretically and extremely rarely - if maybeCoreUpdate()
//is called before the old version of our plugin has been fully deleted, or
//called from an independent AJAX request during deletion.
if ( !(
class_exists(Utils::class)
&& class_exists(Metadata::class)
&& class_exists(Plugin\Update::class)
&& class_exists(Theme\Update::class)
) ) {
return;
}
}
//Let plugin authors substitute their own algorithm.
$shouldCheck = apply_filters(
$this->updateChecker->getUniqueName('check_now'),

View File

@ -163,7 +163,12 @@ if ( !class_exists(StateStore::class, false) ):
$state = get_site_option($this->optionName, null);
if ( !is_object($state) ) {
if (
!is_object($state)
//Sanity check: If the Utils class is missing, the plugin is probably in the process
//of being deleted (e.g. the old version gets deleted during an update).
|| !class_exists(Utils::class)
) {
$this->lastCheck = 0;
$this->checkedVersion = '';
$this->update = null;