| 1 |
<?php |
| 2 |
/** |
| 3 |
* Health check: the pre-4.x Pro monolith is not loaded alongside the addons. |
| 4 |
* |
| 5 |
* @package Forge12\DoubleOptIn\Health |
| 6 |
* @since 5.5.0 |
| 7 |
*/ |
| 8 |
|
| 9 |
declare( strict_types=1 ); |
| 10 |
|
| 11 |
namespace Forge12\DoubleOptIn\Health; |
| 12 |
|
| 13 |
if ( ! defined( 'ABSPATH' ) ) { |
| 14 |
exit; |
| 15 |
} |
| 16 |
|
| 17 |
/** |
| 18 |
* Reports the state that produces "There has been a critical error on this |
| 19 |
* website" after a customer upgrades from Pro 3.x to Pro 4.x. |
| 20 |
* |
| 21 |
* The monolith and the addons declare the same class names in the same |
| 22 |
* namespace. With both active, whichever loads second used to be a fatal; |
| 23 |
* since Core 5.5.0 the compatibility loader skips the duplicate instead |
| 24 |
* ({@see \forge12\contactform7\CF7DoubleOptIn\Compatibility::registerComponents}). |
| 25 |
* That keeps the site up — but it also means one of the two copies is |
| 26 |
* silently not running, so the state still has to be fixed, and now there |
| 27 |
* is an admin left standing to fix it in. |
| 28 |
* |
| 29 |
* Severity is deliberately split: |
| 30 |
* |
| 31 |
* - **active** → `critical`. Something is not running, and which half it |
| 32 |
* is depends on load order. That is not a state anyone should stay in. |
| 33 |
* - **on disk but deactivated** → `recommended`. Nothing is broken right |
| 34 |
* now, but one click on "Activate" brings it all back. |
| 35 |
*/ |
| 36 |
final class LegacyMonolithCheck implements HealthCheckInterface { |
| 37 |
|
| 38 |
public function getId(): string { |
| 39 |
return 'f12_doi_legacy_pro_monolith'; |
| 40 |
} |
| 41 |
|
| 42 |
public function getLabel(): string { |
| 43 |
return __( 'Old Double Opt-In Pro plugin', 'double-opt-in' ); |
| 44 |
} |
| 45 |
|
| 46 |
public function getPackage(): string { |
| 47 |
return 'core'; |
| 48 |
} |
| 49 |
|
| 50 |
public function run(): HealthCheckResult { |
| 51 |
$installed = LegacyProEnvironment::legacyInstallations(); |
| 52 |
|
| 53 |
if ( empty( $installed ) ) { |
| 54 |
return new HealthCheckResult( |
| 55 |
HealthCheckResult::STATUS_GOOD, |
| 56 |
__( 'No outdated Pro plugin is installed', 'double-opt-in' ), |
| 57 |
__( 'The pre-4.0 version of Double Opt-In Pro is not present on this site. Nothing to do.', 'double-opt-in' ), |
| 58 |
'none' |
| 59 |
); |
| 60 |
} |
| 61 |
|
| 62 |
$active = LegacyProEnvironment::activeLegacyInstallations(); |
| 63 |
|
| 64 |
if ( ! empty( $active ) ) { |
| 65 |
return new HealthCheckResult( |
| 66 |
HealthCheckResult::STATUS_CRITICAL, |
| 67 |
__( 'An outdated Double Opt-In Pro plugin is active', 'double-opt-in' ), |
| 68 |
sprintf( |
| 69 |
/* translators: 1: plugin folder name, 2: version number. */ |
| 70 |
__( 'The plugin folder "%1$s" contains Double Opt-In Pro %2$s. That version ships program parts under the same names as the current modules, so with both active one of the two is not running, and older releases fail with "There has been a critical error on this website". Deactivate it — your consent records are stored separately and are not affected.', 'double-opt-in' ), |
| 71 |
$this->describeFolders( $active ), |
| 72 |
$this->describeVersions( $active ) |
| 73 |
), |
| 74 |
'active:' . $this->describeFolders( $active ), |
| 75 |
__( 'Deactivate the old plugin now', 'double-opt-in' ), |
| 76 |
HealthRepairController::repairUrl( HealthRepairController::ACTION_DEACTIVATE_LEGACY ) |
| 77 |
); |
| 78 |
} |
| 79 |
|
| 80 |
return new HealthCheckResult( |
| 81 |
HealthCheckResult::STATUS_RECOMMENDED, |
| 82 |
__( 'An outdated Double Opt-In Pro plugin is still installed', 'double-opt-in' ), |
| 83 |
sprintf( |
| 84 |
/* translators: 1: plugin folder name, 2: version number. */ |
| 85 |
__( 'The folder "%1$s" still holds Double Opt-In Pro %2$s. It is deactivated, so nothing is broken right now, but activating it again would collide with the current modules. Remove the folder over FTP or SSH. Important: do not delete it through the WordPress plugin screen — that version\'s uninstall routine drops the opt-out database table, and the records in it are gone for good.', 'double-opt-in' ), |
| 86 |
$this->describeFolders( $installed ), |
| 87 |
$this->describeVersions( $installed ) |
| 88 |
), |
| 89 |
'inactive:' . $this->describeFolders( $installed ) |
| 90 |
); |
| 91 |
} |
| 92 |
|
| 93 |
/** |
| 94 |
* @param array<int,array<string,string>> $entries |
| 95 |
*/ |
| 96 |
private function describeFolders( array $entries ): string { |
| 97 |
$folders = array(); |
| 98 |
|
| 99 |
foreach ( $entries as $entry ) { |
| 100 |
$folders[] = $entry['folder']; |
| 101 |
} |
| 102 |
|
| 103 |
return implode( ', ', $folders ); |
| 104 |
} |
| 105 |
|
| 106 |
/** |
| 107 |
* @param array<int,array<string,string>> $entries |
| 108 |
*/ |
| 109 |
private function describeVersions( array $entries ): string { |
| 110 |
$versions = array(); |
| 111 |
|
| 112 |
foreach ( $entries as $entry ) { |
| 113 |
$versions[] = $entry['version'] !== '' ? $entry['version'] : __( 'unknown version', 'double-opt-in' ); |
| 114 |
} |
| 115 |
|
| 116 |
return implode( ', ', $versions ); |
| 117 |
} |
| 118 |
} |
| 119 |
|