Description
Plugins using the framework experience a fatal error when updated via /wp-admin/update-core.php:
Uncaught Error: Class 'SkyVerge\WooCommerce\PluginFramework\v5_15_2\Admin\Notes_Helper' not found
at woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:825.
The error does not occur when updating via /wp-admin/plugins.php. The site recovers after the update completes (the error is transient).
Steps to Reproduce
- Install a gateway plugin that uses the framework (e.g. version A with framework namespace
v5_15_X)
- Prepare an update that ships a different framework version (namespace
v5_15_Y)
- Go to
/wp-admin/update-core.php
- Update the plugin
- WordPress sends a "Your Site is Experiencing a Technical Issue" email with the fatal error above
Does NOT occur when updating via /wp-admin/plugins.php.
Root Cause
When updating via update-core.php, the update happens mid-request:
- WordPress loads the old plugin code into PHP memory (with old framework namespace, e.g.
v5_15_X)
- The upgrader replaces all plugin files on disk with the new version (namespace
v5_15_Y)
- The
admin_footer hook fires, calling add_delayed_admin_notices() → add_gateway_not_configured_notices()
- For a configured gateway, execution reaches line 825 — an unguarded
Admin\Notes_Helper::note_with_name_exists() call
- The in-memory Composer autoloader tries to load
v5_15_X\Admin\Notes_Helper, finds the file on disk, but the file now declares v5_15_Y\Admin\Notes_Helper — namespace mismatch → class not found → fatal \Error
This doesn't happen via plugins.php because that path uses AJAX, so the old plugin code is never loaded in the same request that writes the new files.
Affected Locations
1. woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:825 (crash site)
} elseif ( $is_enhanced_admin_available && Admin\Notes_Helper::note_with_name_exists( $note_name ) ) {
No class_exists() guard. No try-catch.
2. Same file, line 813
} catch ( \Exception $exception ) {}
Catches \Exception but a "class not found" throws \Error (which is \Throwable, not \Exception). This path (for unconfigured gateways) would also fatal during an update.
3. woocommerce/Plugin/Lifecycle.php:199,205 (deactivation handler)
if ( SV_WC_Plugin_Compatibility::is_enhanced_admin_available() ) {
Notes_Helper::delete_notes_with_source( ... );
}
No class_exists() guard. Called during plugin deactivation, which is part of the update process.
Suggested Fix
Add class_exists() guards before each unguarded Notes_Helper usage, and widen the catch to \Throwable:
Location 1 (class-sv-wc-payment-gateway-plugin.php:825):
} elseif ( $is_enhanced_admin_available && class_exists( Admin\Notes_Helper::class ) && Admin\Notes_Helper::note_with_name_exists( $note_name ) ) {
Location 2 (same file, line 813):
} catch ( \Throwable $exception ) {}
Location 3 (Plugin/Lifecycle.php:197):
if ( SV_WC_Plugin_Compatibility::is_enhanced_admin_available() && class_exists( Notes_Helper::class ) ) {
ClassName::class resolves at compile time to the FQN string without triggering autoloading. class_exists() then attempts autoloading but returns false gracefully (no fatal error) if the class can't be loaded due to a namespace mismatch.
Versions
- Confirmed present in 5.15.12 and 6.1.4 (latest)
- Affects all payment gateway plugins using this framework
Description
Plugins using the framework experience a fatal error when updated via
/wp-admin/update-core.php:at
woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:825.The error does not occur when updating via
/wp-admin/plugins.php. The site recovers after the update completes (the error is transient).Steps to Reproduce
v5_15_X)v5_15_Y)/wp-admin/update-core.phpDoes NOT occur when updating via
/wp-admin/plugins.php.Root Cause
When updating via
update-core.php, the update happens mid-request:v5_15_X)v5_15_Y)admin_footerhook fires, callingadd_delayed_admin_notices()→add_gateway_not_configured_notices()Admin\Notes_Helper::note_with_name_exists()callv5_15_X\Admin\Notes_Helper, finds the file on disk, but the file now declaresv5_15_Y\Admin\Notes_Helper— namespace mismatch → class not found → fatal\ErrorThis doesn't happen via
plugins.phpbecause that path uses AJAX, so the old plugin code is never loaded in the same request that writes the new files.Affected Locations
1.
woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:825(crash site)No
class_exists()guard. No try-catch.2. Same file, line 813
Catches
\Exceptionbut a "class not found" throws\Error(which is\Throwable, not\Exception). This path (for unconfigured gateways) would also fatal during an update.3.
woocommerce/Plugin/Lifecycle.php:199,205(deactivation handler)No
class_exists()guard. Called during plugin deactivation, which is part of the update process.Suggested Fix
Add
class_exists()guards before each unguardedNotes_Helperusage, and widen the catch to\Throwable:Location 1 (
class-sv-wc-payment-gateway-plugin.php:825):Location 2 (same file, line 813):
Location 3 (
Plugin/Lifecycle.php:197):ClassName::classresolves at compile time to the FQN string without triggering autoloading.class_exists()then attempts autoloading but returnsfalsegracefully (no fatal error) if the class can't be loaded due to a namespace mismatch.Versions