PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 4.0.0
WP 2FA – Two-factor authentication for WordPress v4.0.0
4.0.0 1.7.1 2.0.0 2.0.1 2.1.0 2.2.0 2.2.1 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.8.0 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0 3.0.1 3.1.0 3.1.1 3.1.1.2 trunk 1.2.0 1.3.0 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.1 1.6.2 1.7.0
wp-2fa / includes / classes / Utils / class-abstract-migration.php
wp-2fa / includes / classes / Utils Last commit date
class-abstract-migration.php 13 hours ago class-date-time-utils.php 13 hours ago class-debugging.php 13 hours ago class-generate-modal.php 13 hours ago class-migration.php 13 hours ago class-request-utils.php 13 hours ago class-settings-utils.php 13 hours ago class-upgrade-guard.php 13 hours ago class-user-utils.php 13 hours ago class-validator.php 13 hours ago class-white-label.php 13 hours ago index.php 13 hours ago
class-abstract-migration.php
241 lines
1 <?php
2 /**
3 * Abstract migration class.
4 *
5 * @package wp2fa
6 * @subpackage utils
7 * @copyright 2026 Melapress
8 * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
9 * @link https://wordpress.org/plugins/wp-2fa/
10 *
11 * @since 1.6
12 */
13
14 declare(strict_types=1);
15
16 namespace WP2FA\Utils;
17
18 use WP2FA\Utils\Settings_Utils;
19
20 defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
21
22 /**
23 * Abstract AMigration class
24 */
25 if ( ! class_exists( '\WP2FA\Utils\Abstract_Migration' ) ) {
26
27 /**
28 * Utility class to ease the migration process.
29 *
30 * Every migration must go in its own method
31 * The naming convention is migrateUpTo_XXX where XXX is the number of the version,
32 * format is numbers only.
33 * Example: migration for version upto 1.4 must be in migrateUpTo_14 method
34 *
35 * The numbers in the names of the methods must have exact numbers count as in the selected
36 * version in use, even if there are silent numbers for some of the major versions as 1, 2, 3 etc. (the .0.0 is skipped / silent)
37 * Example:
38 * - if X.X.X is selected for version number, then for version 1.1 method must have "...migrateUpTo_110..." in its name
39 * - if X.X is selected for version number, then for version 1, method must have "...migrateUpTo_10..." in its name
40 *
41 * Note: you can add prefix to the migration method, if that is necessary, but "migrateUpTo_" is a must -
42 * the name must contain that @see getAllMigrationMethodsAsNumbers of that class.
43 * For version extraction the number following the last '_' will be used
44 * TODO: the mandatory part of the method name can be a setting in the class, but is that a good idea?
45 *
46 * Note: order of the methods is not preserved - version numbers will be used for ordering
47 *
48 * @package WP2FA\Utils
49 *
50 * @since 1.6
51 */
52 class Abstract_Migration {
53
54 /**
55 * That is a global constant used for showing the upgrade notice.
56 */
57 public const UPGRADE_NOTICE = 'upgrade-notice-show';
58
59 /**
60 * Extracted version from the DB (WP option)
61 *
62 * @var string
63 *
64 * @since 1.6.0
65 */
66 protected static $stored_version = '';
67
68 /**
69 * The name of the option from which we should extract version
70 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
71 * Note: only numbers will be processed
72 *
73 * @var string
74 *
75 * @since 1.6.0
76 */
77 protected static $version_option_name = '';
78
79 /**
80 * The constant name where the plugin version is stored
81 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
82 * Note: only numbers will be processed
83 *
84 * @var string
85 *
86 * @since 2.2.0
87 */
88 protected static $const_name_of_plugin_version = '';
89
90 /**
91 * Used for adding proper pads for the missing numbers
92 * Version number format used here depends on selection for how many numbers will be used for representing version
93 *
94 * For X.X use 2;
95 * For X.X.X use 3;
96 * For X.X.X.X use 4;
97 *
98 * etc.
99 *
100 * Example: if selected version format is X.X.X that means that 3 digits are used for versioning.
101 * And current version is stored as 2 (no suffix 0.0) that means that it will be normalized as 200.
102 *
103 * @var integer
104 *
105 * @since 1.6.0
106 */
107 protected static $pad_length = 4;
108
109 /**
110 * Collects all the migration methods which needs to be executed in order and executes them
111 *
112 * @return void
113 *
114 * @since 1.6.0
115 */
116 public static function migrate() {
117
118 if ( version_compare( static::get_stored_version(), \constant( static::$const_name_of_plugin_version ), '<' ) ) {
119
120 $stored_version_as_number = static::normalize_version( static::get_stored_version() );
121 $target_version_as_number = static::normalize_version( \constant( static::$const_name_of_plugin_version ) );
122 $method_as_version_numbers = static::get_all_migration_methods_as_numbers();
123
124 $stored = (int) $stored_version_as_number;
125 $target = (int) $target_version_as_number;
126 $migrate_methods = array_filter(
127 $method_as_version_numbers,
128 function ( $method, $key ) use ( $stored, $target ) {
129 $ver = (int) self::normalize_version( (string) $key );
130 return ( $target > $stored ) && ( $ver > $stored ) && ( $ver <= $target );
131 },
132 ARRAY_FILTER_USE_BOTH
133 );
134
135 if ( ! empty( $migrate_methods ) ) {
136 \ksort( $migrate_methods );
137 foreach ( $migrate_methods as $method ) {
138 static::{$method}();
139 }
140 }
141
142 self::store_updated_version();
143 }
144
145 /**
146 * Downgrading the plugin? Set the version number.
147 * Leave the rest as is.
148 *
149 * @return void
150 *
151 * @since 2.2.0
152 */
153 if ( version_compare( static::get_stored_version(), \constant( static::$const_name_of_plugin_version ), '>' ) ) {
154 self::store_updated_version();
155 }
156 }
157
158 /**
159 * Extracts currently stored version from the DB
160 *
161 * @return string
162 *
163 * @since 1.6.0
164 */
165 private static function get_stored_version() {
166
167 if ( '' === trim( (string) static::$stored_version ) ) {
168 static::$stored_version = (string) Settings_Utils::get_option( static::$version_option_name, '0.0.0' );
169 }
170
171 return static::$stored_version;
172 }
173
174 /**
175 * Stores the version to which we migrated
176 *
177 * @return void
178 *
179 * @since 1.6.0
180 */
181 private static function store_updated_version() {
182 Settings_Utils::update_option( static::$version_option_name, \constant( static::$const_name_of_plugin_version ) );
183
184 if ( '0.0.0' !== (string) static::$stored_version ) {
185 Settings_Utils::update_option( self::UPGRADE_NOTICE, 1 );
186 }
187 }
188
189 /**
190 * Normalized the version numbers to numbers
191 *
192 * Version format is expected to be as follows:
193 * X.X.X
194 *
195 * All non numeric values will be removed from the version string
196 *
197 * Note: version is expected in version format - 1.0.0; 1; 1.0; 1.0.0.0
198 * Note: only numbers will be processed
199 *
200 * @param string $version - The version string we have to use.
201 *
202 * @return string
203 *
204 * @since 1.6.0
205 */
206 private static function normalize_version( string $version ) {
207 $version_as_number = (int) filter_var( $version, FILTER_SANITIZE_NUMBER_INT );
208
209 if ( self::$pad_length > strlen( (string) $version_as_number ) ) {
210 $version_as_number = str_pad( (string) $version_as_number, static::$pad_length, '0', STR_PAD_RIGHT );
211 }
212
213 return $version_as_number;
214 }
215
216 /**
217 * Collects all the migration methods from the class and stores them in the array
218 * Array is in following format:
219 * key - number of the version
220 * value - name of the method
221 *
222 * @return array
223 *
224 * @since 1.6.0
225 */
226 private static function get_all_migration_methods_as_numbers() {
227 $class_methods = \get_class_methods( get_called_class() );
228
229 $method_as_version_numbers = array();
230 foreach ( $class_methods as $method ) {
231 if ( false !== \strpos( $method, 'migrate_up_to_' ) ) {
232 $ver = \substr( $method, \strrpos( $method, '_' ) + 1, \strlen( $method ) );
233 $method_as_version_numbers[ $ver ] = $method;
234 }
235 }
236
237 return $method_as_version_numbers;
238 }
239 }
240 }
241