PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 5.5.0
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v5.5.0
5.5.0 5.4.0 5.3.2 5.3.1 5.1.6 5.1.5 trunk 2.1.5 2.11 2.12 2.13 2.15 3.0.0 3.0.1 3.0.2 3.0.3 3.0.5 3.0.51 3.0.60 3.0.61 3.0.62 3.0.70 3.0.71 3.0.72 3.1.0 All 34 releases
double-opt-in / src / Health / LegacyProEnvironment.php

LegacyProEnvironment.php in Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification 5.5.0, at src/Health/LegacyProEnvironment.php

142 lines 3.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Reads the Pro-related state of this installation.
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 * One place to ask "what does the Pro side of this site look like right
19 * now?" — shared by {@see LegacyMonolithCheck}, {@see StaleProMarkersCheck}
20 * and {@see HealthRepairController} so the three cannot drift apart on what
21 * counts as active or stale.
22 *
23 * Reads `active_plugins` (and the network equivalent) directly instead of
24 * calling `is_plugin_active()`. That function lives in
25 * `wp-admin/includes/plugin.php`, which is not loaded on every request this
26 * code runs in, and pulling it in just to answer a boolean would be the
27 * kind of side effect a health check must not have.
28 */
29 final class LegacyProEnvironment {
30
31 /**
32 * bundle-pro's main file, relative to the plugins directory.
33 */
34 public const SUCCESSOR_FILE = 'double-opt-in-pro/double-opt-in-pro.php';
35
36 /**
37 * One-shot markers written by bundle-pro's migration and addon
38 * installer.
39 *
40 * bundle-pro ships no `uninstall.php`, so these survive deleting and
41 * reinstalling the plugin. While they stand, neither the licence
42 * migration nor the addon auto-install ever runs again — which is why
43 * "I reinstalled everything" reliably changes nothing for the customers
44 * who end up in this state.
45 *
46 * The bundle licence key is deliberately NOT in this list. Clearing it
47 * would be self-defeating: `MigrationFromMonolith` reads it, and a
48 * self-service repair that logs the customer out of their licence is a
49 * worse ticket than the one it closes. `tools/support/doi-reset.php`
50 * does clear it, but that is a full reset run by support, with a
51 * backup, not a button in the admin.
52 *
53 * @var array<int,string>
54 */
55 public const ONE_SHOT_MARKERS = array(
56 'f12_doi_pro_migration_complete',
57 'f12_doi_pro_migration_autoinstall_pending',
58 'f12_doi_addon_installer_state',
59 'f12_doi_addon_auto_install_done',
60 );
61
62 /**
63 * Cached validation state. Harmless to drop — it is re-fetched.
64 *
65 * @var array<int,string>
66 */
67 public const STALE_TRANSIENTS = array(
68 'f12_doi_bundle_license_validation',
69 'f12_doi_bundle_site_registered',
70 'f12_doi_pro_migration_notice_pending',
71 );
72
73 /**
74 * Every legacy monolith found on disk.
75 *
76 * @return array<int,array<string,string>>
77 */
78 public static function legacyInstallations(): array {
79 return LegacyMonolithDetector::scan();
80 }
81
82 /**
83 * The subset of those that WordPress is actually loading.
84 *
85 * @return array<int,array<string,string>>
86 */
87 public static function activeLegacyInstallations(): array {
88 $active = array();
89
90 foreach ( self::legacyInstallations() as $entry ) {
91 if ( self::isPluginActive( $entry['file'] ) ) {
92 $active[] = $entry;
93 }
94 }
95
96 return $active;
97 }
98
99 /**
100 * Is bundle-pro 4.x currently active?
101 */
102 public static function isSuccessorActive(): bool {
103 return self::isPluginActive( self::SUCCESSOR_FILE );
104 }
105
106 /**
107 * @param string $file `folder/main-file.php`, as WordPress stores it.
108 */
109 public static function isPluginActive( string $file ): bool {
110 $active = get_option( 'active_plugins', array() );
111
112 if ( is_array( $active ) && in_array( $file, $active, true ) ) {
113 return true;
114 }
115
116 if ( ! function_exists( 'get_site_option' ) ) {
117 return false;
118 }
119
120 $network = get_site_option( 'active_sitewide_plugins', array() );
121
122 return is_array( $network ) && isset( $network[ $file ] );
123 }
124
125 /**
126 * Which one-shot markers are currently set.
127 *
128 * @return array<int,string>
129 */
130 public static function burnedMarkers(): array {
131 $found = array();
132
133 foreach ( self::ONE_SHOT_MARKERS as $marker ) {
134 if ( get_option( $marker, null ) !== null ) {
135 $found[] = $marker;
136 }
137 }
138
139 return $found;
140 }
141 }
142