first commit

This commit is contained in:
User A0264400
2026-04-01 23:20:16 +03:00
commit a766acdc90
23071 changed files with 4933189 additions and 0 deletions

View File

@@ -0,0 +1,512 @@
<?php
// phpcs:disable Generic.Commenting.DocComment.MissingShort
/** @noinspection PhpIllegalPsrClassPathInspection */
/** @noinspection AutoloadingIssuesInspection */
// phpcs:enable Generic.Commenting.DocComment.MissingShort
namespace WPForms\Migrations;
use ReflectionClass;
use WPForms\Helpers\DB;
/**
* Class Migrations handles both Lite and Pro plugin upgrade routines.
*
* @since 1.7.5
*/
abstract class Base {
/**
* WP option name to store the migration versions.
* Must have 'versions' in the name defined in extending classes,
* like 'wpforms_versions', 'wpforms_versions_lite, 'wpforms_stripe_versions', etc.
*
* @since 1.7.5
*/
protected const MIGRATED_OPTION_NAME = '';
/**
* Current plugin version.
*
* @since 1.7.5
*/
protected const CURRENT_VERSION = WPFORMS_VERSION;
/**
* WP option name to store the upgraded from version number.
*
* @since 1.8.8
* @deprecated 1.9.8
*
* @todo Delete this option later. There is no sense to creating a separate migration for it.
* @noinspection PhpUnusedPrivateFieldInspection
*/
private const UPGRADED_FROM_OPTION_NAME = 'wpforms_version_upgraded_from';
/**
* WP option name to store the previous plugin version.
*
* @since 1.8.8
*/
public const PREVIOUS_CORE_VERSION_OPTION_NAME = 'wpforms_version_previous';
/**
* Name of the core plugin used in log messages.
*
* @since 1.7.5
*/
protected const PLUGIN_NAME = '';
/**
* Upgrade classes.
*
* @since 1.7.5
*/
protected const UPGRADE_CLASSES = [];
/**
* Migration started status.
*
* @since 1.7.5
*/
private const STARTED = - 1;
/**
* Migration failed status.
*
* @since 1.7.5
*/
private const FAILED = - 2;
/**
* Initial fake version for comparisons.
*
* @since 1.7.5
*/
private const INITIAL_FAKE_VERSION = '0.0.1';
/**
* Reflection class instance.
*
* @since 1.7.5
*
* @var ReflectionClass
*/
protected $reflector;
/**
* Migrated versions.
*
* @since 1.7.5
*
* @var string[]
*/
protected $migrated = [];
/**
* Whether tables' check was done.
*
* @since 1.8.7
*
* @var bool
*/
private $tables_check_done;
/**
* Primary class constructor.
*
* @since 1.7.5
*/
public function __construct() {
$this->reflector = new ReflectionClass( $this );
}
/**
* Class init.
*
* @since 1.7.5
*/
public function init(): void {
if ( ! $this->is_allowed() ) {
return;
}
$this->maybe_convert_migration_option();
$this->hooks();
}
/**
* General hooks.
*
* @since 1.7.5
*/
protected function hooks(): void {
$priority = $this->is_core_plugin() ? - 9999 : 100;
add_action( 'wpforms_loaded', [ $this, 'migrate' ], $priority );
add_action( 'wpforms_loaded', [ $this, 'update_versions' ], $priority + 1 );
}
/**
* Run the migrations of the core plugin for a specific version.
*
* @since 1.7.5
*
* @noinspection NotOptimalIfConditionsInspection
*/
public function migrate(): void { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
$classes = $this->get_upgrade_classes();
$namespace = $this->reflector->getNamespaceName() . '\\';
foreach ( $classes as $class ) {
$upgrade_version = $this->get_upgrade_version( $class );
$plugin_name = $this->get_plugin_name( $class );
$class = $namespace . $class;
if (
( isset( $this->migrated[ $upgrade_version ] ) && $this->migrated[ $upgrade_version ] >= 0 ) ||
version_compare( $upgrade_version, static::CURRENT_VERSION, '>' ) ||
! class_exists( $class )
) {
continue;
}
$this->maybe_create_tables();
if ( ! isset( $this->migrated[ $upgrade_version ] ) ) {
$this->migrated[ $upgrade_version ] = self::STARTED;
$this->log( sprintf( 'Migration of %1$s to %2$s started.', $plugin_name, $upgrade_version ) );
}
// Run upgrade.
$migrated = ( new $class( $this ) )->run();
// Some migration methods can be called several times to support AS action,
// so do not log their completion here.
if ( $migrated === null ) {
continue;
}
$this->migrated[ $upgrade_version ] = $migrated ? time() : self::FAILED;
$this->log_migration_message( $migrated, $plugin_name, $upgrade_version );
}
}
/**
* If an upgrade has occurred, update a version option in the database.
*
* @since 1.7.5
*/
public function update_versions(): void {
$this->update_previous_core_version();
// Retrieve the last migrated versions.
$last_migrated = get_option( static::MIGRATED_OPTION_NAME, [] );
$migrated = array_merge( $last_migrated, $this->migrated );
/**
* Store the current version upgrade timestamp even if there were no migrations to it.
* We need it in wpforms_get_upgraded_timestamp() for further usage in Event Driven Plugin Notifications.
*/
$migrated[ static::CURRENT_VERSION ] = $migrated[ static::CURRENT_VERSION ] ?? time();
uksort( $last_migrated, 'version_compare' );
uksort( $migrated, 'version_compare' );
if ( $migrated === $last_migrated ) {
return;
}
update_option( static::MIGRATED_OPTION_NAME, $migrated );
$fully_completed = array_reduce(
$migrated,
static function ( $carry, $status ) {
return $carry && ( $status >= 0 );
},
true
);
if ( ! $fully_completed ) {
return;
}
$this->log(
sprintf( 'Migration of %1$s to %2$s is fully completed.', static::PLUGIN_NAME, static::CURRENT_VERSION )
);
}
/**
* Update previous core version.
*
* @since 1.9.8
*
* @return void
*/
private function update_previous_core_version(): void {
if ( ! $this->is_core_plugin() ) {
return;
}
// Retrieve the last migrated versions.
$last_migrated = get_option( static::MIGRATED_OPTION_NAME, [] );
$previous_core_version = $this->get_max_version( $last_migrated );
if (
$previous_core_version === self::INITIAL_FAKE_VERSION ||
version_compare( $previous_core_version, static::CURRENT_VERSION, '>=' )
) {
return;
}
// Store the previous core version in the option.
update_option( self::PREVIOUS_CORE_VERSION_OPTION_NAME, $previous_core_version );
/**
* Fires after the core plugin has been upgraded.
* Please note: some of the migrations that run via Active Scheduler can be not completed yet.
*
* @since 1.8.8
*
* @param string $previous_core_version The core version from which the plugin was upgraded.
* @param Base $migration_obj The migration class instance.
*/
do_action( 'wpforms_migrations_base_core_upgraded', $previous_core_version, $this );
}
/**
* Get upgrade classes.
*
* @since 1.7.5
*
* @return string[]
*/
protected function get_upgrade_classes(): array {
$classes = static::UPGRADE_CLASSES;
sort( $classes );
return $classes;
}
/**
* Get an upgrade version from the class name.
*
* @since 1.7.5
*
* @param string $class_name Class name.
*
* @return string
*/
public function get_upgrade_version( string $class_name ): string {
// Find only the digits and underscores to get the version number.
if ( ! preg_match( '/(\d_?)+/', $class_name, $matches ) ) {
return '';
}
$raw_version = $matches[0];
if ( strpos( $raw_version, '_' ) ) {
// Modern notation: 1_10_0_3 means 1.10.0.3 version.
return str_replace( '_', '.', $raw_version );
}
// Legacy notation, with 1-digit subversion numbers: 1751 means 1.7.5.1 version.
return implode( '.', str_split( $raw_version ) );
}
/**
* Get a plugin /addon name.
*
* @since 1.7.5
*
* @param string $class_name Upgrade class name.
*
* @return string
* @noinspection PhpUnusedParameterInspection
*/
protected function get_plugin_name( string $class_name ): string { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
return static::PLUGIN_NAME;
}
/**
* Force log message to WPForms logger.
*
* @since 1.7.5
*
* @param string $message The error message that should be logged.
*/
protected function log( string $message ): void {
wpforms_log(
'Migration',
$message,
[
'type' => 'log',
'force' => true,
]
);
}
/**
* Determine if migration is allowed.
*
* @since 1.7.5
*/
private function is_allowed(): bool {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( isset( $_GET['service-worker'] ) ) {
return false;
}
return wp_doing_cron() || is_admin() || wpforms_doing_wp_cli();
}
/**
* Maybe create custom plugin tables.
*
* @since 1.7.6
*/
public function maybe_create_tables(): void {
if ( $this->tables_check_done ) {
/**
* We should do table check only once - when the first migration has been started.
* The DB::get_existing_custom_tables() without caching causes performance issue
* on huge multisite with thousands of tables.
*/
return;
}
DB::create_custom_tables( true );
$this->tables_check_done = true;
}
/**
* Maybe convert the migration option format.
*
* @since 1.7.5
*/
private function maybe_convert_migration_option(): void {
/**
* Retrieve the migration option and check its format.
* Old format: a string 'x.y.z' containing the last migrated version.
* New format: [ 'x.y.z' => {status}, 'x1.y1.z1' => {status}... ],
* where {status} is a migration status.
* Negative means some status (-1 for 'started' etc.),
* zero means completed earlier at an unknown time,
* positive means completion timestamp.
*/
$this->migrated = get_option( static::MIGRATED_OPTION_NAME );
// If the option is an array, it means that it is already converted to the new format.
if ( is_array( $this->migrated ) ) {
return;
}
/**
* Convert the option to the new format.
*
* Old option names contained 'version',
* like 'wpforms_version', 'wpforms_version_lite', 'wpforms_stripe_version', etc.
* We preserve old options for downgrade cases.
* New option names should contain 'versions' and be like 'wpforms_versions', etc.
*/
$this->migrated = get_option(
str_replace( 'versions', 'version', static::MIGRATED_OPTION_NAME )
);
$version = $this->migrated === false ? self::INITIAL_FAKE_VERSION : (string) $this->migrated;
$timestamp = $version === static::CURRENT_VERSION ? time() : 0;
$this->migrated = [ $version => $timestamp ];
$max_version = $this->get_max_version( $this->migrated );
foreach ( $this->get_upgrade_classes() as $upgrade_class ) {
$upgrade_version = $this->get_upgrade_version( $upgrade_class );
if (
! isset( $this->migrated[ $upgrade_version ] ) &&
version_compare( $upgrade_version, $max_version, '<' )
) {
$this->migrated[ $upgrade_version ] = 0;
}
}
unset( $this->migrated[ self::INITIAL_FAKE_VERSION ] );
ksort( $this->migrated );
update_option( static::MIGRATED_OPTION_NAME, $this->migrated );
}
/**
* Get the max version.
*
* @since 1.7.5
*
* @param array $versions Versions.
*
* @return string
*/
private function get_max_version( array $versions ): string {
// phpcs:ignore WPForms.Formatting.EmptyLineBeforeReturn.RemoveEmptyLineBeforeReturnStatement
return array_reduce(
array_keys( $versions ),
static function ( $carry, $version ) {
return version_compare( $version, $carry, '>' ) ? $version : $carry;
},
self::INITIAL_FAKE_VERSION
);
}
/**
* Determine if it is the core plugin (Lite or Pro).
*
* @since 1.7.5
*
* @return bool True if it is the core plugin.
*/
protected function is_core_plugin(): bool {
// phpcs:ignore WPForms.Formatting.EmptyLineBeforeReturn.RemoveEmptyLineBeforeReturnStatement
return strpos( static::MIGRATED_OPTION_NAME, 'wpforms_versions' ) === 0;
}
/**
* Log migration message.
*
* @since 1.8.2.3
*
* @param bool $migrated Migration status.
* @param string $plugin_name Plugin name.
* @param string $upgrade_version Upgrade version.
*
* @return void
*/
private function log_migration_message( bool $migrated, string $plugin_name, string $upgrade_version ): void {
$message = $migrated ?
sprintf( 'Migration of %1$s to %2$s completed.', $plugin_name, $upgrade_version ) :
sprintf( 'Migration of %1$s to %2$s failed.', $plugin_name, $upgrade_version );
$this->log( $message );
}
}

View File

@@ -0,0 +1,53 @@
<?php
// phpcs:disable Generic.Commenting.DocComment.MissingShort
/** @noinspection PhpIllegalPsrClassPathInspection */
/** @noinspection AutoloadingIssuesInspection */
// phpcs:enable Generic.Commenting.DocComment.MissingShort
namespace WPForms\Migrations;
/**
* Class Migrations handles Lite plugin upgrade routines.
*
* @since 1.7.5
*/
class Migrations extends Base {
/**
* WP option name to store the migration version.
*
* @since 1.5.9
*/
public const MIGRATED_OPTION_NAME = 'wpforms_versions_lite';
/**
* Name of the core plugin used in log messages.
*
* @since 1.7.5
*/
protected const PLUGIN_NAME = 'WPForms';
/**
* Upgrade classes.
*
* @since 1.7.5
*/
public const UPGRADE_CLASSES = [
'Upgrade159',
'Upgrade1672',
'Upgrade168',
'Upgrade175',
'Upgrade1751',
'Upgrade177',
'Upgrade182',
'Upgrade183',
'Upgrade184',
'Upgrade186',
'Upgrade187',
'Upgrade1_9_1',
'Upgrade1_9_2',
'Upgrade1_9_7',
'Upgrade1_9_8_6',
];
}

View File

@@ -0,0 +1,304 @@
<?php
namespace WPForms\Migrations\Tasks;
use RuntimeException;
use WPForms\Tasks\Task;
use WPForms\Tasks\Meta;
/**
* Upgrade task base class.
*
* @since 1.9.5
*/
abstract class UpgradeBaseTask extends Task {
/**
* Start status.
*
* @since 1.9.5
*/
private const START = 'start';
/**
* In progress status.
*
* @since 1.9.5
*/
private const IN_PROGRESS = 'in progress';
/**
* Completed status.
*
* @since 1.9.5
*/
private const COMPLETED = 'completed';
/**
* Task action name.
*
* @since 1.9.5
*
* @var string
*/
private $action;
/**
* Option name to store the task status.
*
* @since 1.9.5
*
* @var string
*/
private $status_option;
/**
* Class constructor.
*
* @since 1.9.5
*
* @throws RuntimeException If class name doesn't contain a version.
*/
public function __construct() {
$class_parts = explode( '\\', static::class );
$short_class_name = end( $class_parts );
$short_class_name = strtolower( preg_replace( '/(?<!^)[A-Z]/', '_$0', $short_class_name ) );
$this->action = 'wpforms_process_migration_' . $short_class_name;
$this->status_option = $this->action . '_status';
parent::__construct( $this->action );
}
/**
* Get current task status.
*
* @since 1.9.5
*
* @return string
*/
private function get_status(): string {
return (string) get_option( $this->status_option );
}
/**
* Update task status.
* Use the constants self::START, self::IN_PROGRESS, self::COMPLETED.
*
* @since 1.9.5
*
* @param string $status New status.
*
* @return void
*/
private function update_status( string $status ): void {
update_option( $this->status_option, $status );
}
/**
* Initialize the task with all the proper checks.
*
* @since 1.9.5
*/
public function init(): void {
$status = $this->get_status();
if ( ! $status || $status === self::COMPLETED ) {
return;
}
$this->set_task_properties();
$this->hooks();
if ( $status !== self::START ) {
return;
}
$this->update_status( self::IN_PROGRESS );
$this->init_migration();
}
/**
* Create a task.
*
* @param array $args Task arguments.
*
* @since 1.9.5
*
* @return void
*/
protected function create_task( array $args = [] ): void {
$tasks = wpforms()->obj( 'tasks' );
if ( ! $tasks ) {
wpforms_log(
'Migration error',
[
'error' => "Object is not available: `null` returned by `wpforms()->obj( 'tasks' )`",
'class' => static::class,
'method' => __METHOD__,
],
[
'type' => 'error',
'force' => true,
]
);
return;
}
$tasks
->create( $this->action )
->async()
->params( ...$args )
->register();
}
/**
* Set task properties.
*
* @since 1.9.5
*
* @return void
*/
abstract protected function set_task_properties(): void;
/**
* Add hooks.
*
* @since 1.9.5
*/
protected function hooks(): void {
add_action( $this->action, [ $this, 'migrate' ] );
add_action( 'action_scheduler_after_process_queue', [ $this, 'after_process_queue' ] );
}
/**
* Migrate an entry.
*
* @since 1.9.5
*
* @param int $meta_id Action meta id.
*
* @noinspection PhpMissingParamTypeInspection
*/
public function migrate( $meta_id ): void {
$params = ( new Meta() )->get( $meta_id );
if ( ! $params || ! isset( $params->data ) ) {
return;
}
$this->process_migration( (array) $params->data );
}
/**
* Execute an async migration task.
*
* @since 1.9.5
*
* @param array $data Migration data.
*
* @return void
*/
abstract protected function process_migration( array $data ): void;
/**
* Set the status as completed after processing all queue action.
*
* @since 1.9.5
*
* @return void
*/
public function after_process_queue(): void {
$tasks = wpforms()->obj( 'tasks' );
if ( ! $tasks ) {
wpforms_log(
'Migration error',
[
'error' => "Object is not available: `null` returned by `wpforms()->obj( 'tasks' )`",
'class' => static::class,
'method' => __METHOD__,
],
[
'type' => 'error',
'force' => true,
]
);
return;
}
if ( $tasks->is_scheduled( $this->action ) ) {
return;
}
$this->finish_migration();
}
/**
* Finish migration.
*
* @since 1.9.5
*
* @return void
*/
protected function finish_migration(): void {
$this->update_status( self::COMPLETED );
}
/**
* Create migration tasks using the `create_task` method
* or `finish_migration` method to complete it.
*
* @since 1.9.5
*
* @return void
*/
abstract protected function init_migration(): void;
/**
* Determine if the task is completed.
* Remove the status option to allow running the task again.
*
* @since 1.9.5
*
* @return bool True if a task is completed.
*/
public function is_completed(): bool {
$status = $this->get_status();
$is_completed = $status === self::COMPLETED;
if ( $is_completed ) {
delete_option( $this->status_option );
}
return $is_completed;
}
/**
* Maybe start the task.
*
* @since 1.9.5
*/
public function maybe_start(): void {
$status = $this->get_status();
if ( ! $status ) {
$this->update_status( self::START );
}
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace WPForms\Migrations;
/**
* Class v1.5.9 upgrade.
*
* @since 1.7.5
*
* @noinspection PhpUnused
*/
class Upgrade159 extends UpgradeBase {
/**
* Create tasks_meta table.
*
* @since 1.7.5
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
public function run() {
$meta = wpforms()->obj( 'tasks_meta' );
if ( ! $meta ) {
return false;
}
// Create the table if it doesn't exist.
if ( ! $meta->table_exists() ) {
$meta->create_table();
}
return true;
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace WPForms\Migrations;
/**
* Class v1.6.7.2 upgrade.
*
* @since 1.7.5
*
* @noinspection PhpUnused
*/
class Upgrade1672 extends UpgradeBase {
/**
* Run upgrade.
*
* @since 1.7.5
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
public function run() {
$review = get_option( 'wpforms_review' );
if ( empty( $review ) ) {
return true;
}
$notices = get_option( 'wpforms_admin_notices', [] );
if ( isset( $notices['review_request'] ) ) {
return true;
}
$notices['review_request'] = $review;
update_option( 'wpforms_admin_notices', $notices, true );
delete_option( 'wpforms_review' );
return true;
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace WPForms\Migrations;
/**
* Class v1.6.8 upgrade.
*
* @since 1.7.5
*
* @noinspection PhpUnused
*/
class Upgrade168 extends UpgradeBase {
/**
* Run upgrade.
*
* @since 1.7.5
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
public function run() {
$current_opened_date = get_option( 'wpforms_builder_opened_date', null );
// Do not run migration twice as 0 is a default value for all old users.
if ( $current_opened_date === '0' ) {
return true;
}
// We don't want users to report to us if they already previously used the builder by creating a form.
$form_handler = wpforms()->obj( 'form' );
if ( ! $form_handler ) {
return false;
}
$forms = $form_handler->get(
'',
[
'posts_per_page' => 1,
'nopaging' => false,
'fields' => 'ids',
'update_post_meta_cache' => false,
]
);
// At least 1 form exists - set the default value.
if ( ! empty( $forms ) ) {
add_option( 'wpforms_builder_opened_date', 0, '', 'no' );
}
return true;
}
}

View File

@@ -0,0 +1,93 @@
<?php
namespace WPForms\Migrations;
use WPForms\Tasks\Meta;
use WPForms\Tasks\Tasks;
/**
* Class v1.7.5 upgrade.
*
* @since 1.7.5
*
* @noinspection PhpUnused
*/
class Upgrade175 extends UpgradeBase {
/**
* Delete all task meta of not active tasks.
*
* @since 1.7.5
*
* @noinspection ElvisOperatorCanBeUsedInspection
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
public function run() {
global $wpdb;
if ( ! $this->as_tables_exist() ) {
return true;
}
$group = Tasks::GROUP;
$sql = "SELECT DISTINCT a.args FROM {$wpdb->prefix}actionscheduler_actions a
JOIN {$wpdb->prefix}actionscheduler_groups g ON g.group_id = a.group_id
WHERE g.slug = '$group' AND a.status IN ( 'pending', 'in-progress' )";
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
$results = $wpdb->get_results( $sql, 'ARRAY_A' );
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
$results = $results ? $results : [];
$meta_ids = [];
foreach ( $results as $result ) {
$args = isset( $result['args'] ) ? json_decode( $result['args'], true ) : null;
if ( $args && ! empty( $args['tasks_meta_id'] ) ) {
$meta_ids[] = $args['tasks_meta_id'];
}
}
$table_name = Meta::get_table_name();
$not_in = $meta_ids ? wpforms_wpdb_prepare_in( $meta_ids ) : '0';
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
$wpdb->query( "DELETE FROM $table_name WHERE id NOT IN ( $not_in )" );
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
return true;
}
/**
* Check whether AS tables exist.
*
* @since 1.7.6
*
* @return bool
*/
private function as_tables_exist() {
global $wpdb;
$required_tables = [
$wpdb->prefix . 'actionscheduler_actions',
$wpdb->prefix . 'actionscheduler_groups',
];
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$tables = $wpdb->get_col( "SHOW TABLES LIKE '{$wpdb->prefix}actionscheduler%'" );
$intersect = array_values( array_intersect( $tables, $required_tables ) );
sort( $intersect );
sort( $required_tables );
return $intersect === $required_tables;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace WPForms\Migrations;
/**
* Class v1.7.5.1 upgrade.
*
* @since 1.7.5.1
*
* @noinspection PhpUnused
*/
class Upgrade1751 extends UpgradeBase {
/**
* Repeat 1.7.5 migration.
*
* @since 1.7.5.1
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
public function run() {
return ( new Upgrade175( $this->migrations ) )->run();
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace WPForms\Migrations;
/**
* Class v1.7.7 upgrade.
*
* @since 1.7.7
*/
class Upgrade177 extends UpgradeBase {
/**
* Run upgrade.
*
* @since 1.7.7
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
public function run() {
$settings = (array) get_option( 'wpforms_settings', [] );
$new_inputmask_key = 'validation-inputmask-incomplete';
$old_inputmask_key = 'validation-input-mask-incomplete';
$is_updated = false;
if ( isset( $settings[ $new_inputmask_key ] ) && in_array( $settings[ $new_inputmask_key ], [ 'Please fill out all blanks.', esc_html__( 'Please fill out all blanks.', 'wpforms-lite' ) ], true ) ) {
unset( $settings[ $new_inputmask_key ] );
$is_updated = true;
}
if ( empty( $settings[ $new_inputmask_key ] ) && ! empty( $settings[ $old_inputmask_key ] ) ) {
$settings[ $new_inputmask_key ] = $settings[ $old_inputmask_key ];
$is_updated = true;
}
if ( $is_updated ) {
update_option( 'wpforms_settings', $settings );
}
return true;
}
}

View File

@@ -0,0 +1,110 @@
<?php
// phpcs:ignore Generic.Commenting.DocComment.MissingShort
/** @noinspection PhpUnused */
namespace WPForms\Migrations;
use WPForms\Helpers\Transient;
/**
* Class v1.8.2 upgrade.
*
* @since 1.8.2
*/
class Upgrade182 extends UpgradeBase {
/**
* Run upgrade.
*
* @since 1.8.2
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
public function run() {
$cache_dir = $this->get_cache_dir();
$templates_cache_dir = $cache_dir . 'templates/';
$this->set_cache_time( $cache_dir, 'addons.json', 'wpforms_admin_addons_cache_ttl' );
$this->set_cache_time( $cache_dir, 'docs.json', 'wpforms_admin_builder_help_cache_ttl' );
$this->set_cache_time( $cache_dir, 'templates.json', 'wpforms_admin_builder_templates_cache_ttl' );
$files = glob( $templates_cache_dir . '*.json' );
foreach ( $files as $filename ) {
$this->set_cache_time( $templates_cache_dir, basename( $filename ), 'wpforms_admin_builder_templates_cache_ttl' );
}
return true;
}
/**
* Set cache time to transient.
*
* @since 1.8.2
*
* @param string $cache_dir Cache directory.
* @param string $cache_file Cache filename.
* @param string $filter Filter name.
*
* @return void
*/
private function set_cache_time( $cache_dir, $cache_file, $filter ) {
// phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName, WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
$cache_ttl = (int) apply_filters( $filter, WEEK_IN_SECONDS );
$cache_file_path = $cache_dir . $cache_file;
$cache_modified_time = 0;
$transient = $cache_file;
$time = time();
if ( is_file( $cache_file_path ) && is_readable( $cache_file_path ) ) {
clearstatcache( true, $cache_file_path );
// On WPVIP and similar filesystems, filemtime() could return false.
$cache_modified_time = (int) filemtime( $cache_file_path );
}
if ( $cache_modified_time === 0 || $cache_modified_time + $cache_ttl <= $time ) {
// Do not set transient for non-existing or expired cache.
return;
}
$expiration = $cache_modified_time + $cache_ttl - $time;
Transient::set( $transient, $cache_modified_time, $expiration );
}
/**
* Get cache directory path.
* Copy of the CacheBase method.
*
* @since 1.8.2
*/
private function get_cache_dir() {
static $cache_dir;
if ( $cache_dir ) {
/**
* Since wpforms_upload_dir() relies on hooks, and hooks can be added unpredictably,
* we need to cache the result of this method.
* Otherwise, it is the risk to save cache file to one dir and try to get from another.
*/
return $cache_dir;
}
$upload_dir = wpforms_upload_dir();
$upload_path = ! empty( $upload_dir['path'] )
? trailingslashit( wp_normalize_path( $upload_dir['path'] ) )
: trailingslashit( WP_CONTENT_DIR ) . 'uploads/wpforms/';
$cache_dir = $upload_path . 'cache/';
return $cache_dir;
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace WPForms\Migrations;
use WPForms\Tasks\Actions\IconChoicesFontAwesomeUpgradeTask;
/**
* Class upgrade for Lite.
*
* @since 1.8.3
*
* @noinspection PhpUnused
*/
class Upgrade183 extends UpgradeBase {
/**
* Run upgrade.
*
* We run migration as Action Scheduler task.
* Class Tasks does not exist at this point, so here we can only check task completion status.
*
* @since 1.8.3
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
public function run() {
return $this->run_async( IconChoicesFontAwesomeUpgradeTask::class );
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace WPForms\Migrations;
use WPForms\Integrations\Stripe\Helpers;
use WPForms\Tasks\Actions\WebhooksAutoConfigurationTask;
/**
* Class upgrade for 1.8.4 release.
*
* @since 1.8.4
*
* @noinspection PhpUnused
*/
class Upgrade184 extends UpgradeBase {
/**
* Run upgrade.
*
* @since 1.8.4
*
* @return bool|null
*/
public function run() {
$this->set_webhooks_settings();
return $this->run_async( WebhooksAutoConfigurationTask::class );
}
/**
* Set Stripe webhooks settings.
*
* @since 1.8.4
*/
private function set_webhooks_settings() {
$settings = (array) get_option( 'wpforms_settings', [] );
// Enable Stripe webhooks by default if account is connected.
if ( ! isset( $settings['stripe-webhooks-enabled'] ) && Helpers::has_stripe_keys() ) {
$settings['stripe-webhooks-enabled'] = true;
update_option( 'wpforms_settings', $settings );
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace WPForms\Migrations;
use WPForms\Tasks\Actions\DomainAutoRegistrationTask;
/**
* Class upgrade for 1.8.6 release.
*
* @since 1.8.6
*
* @noinspection PhpUnused
*/
class Upgrade186 extends UpgradeBase {
/**
* Run upgrade.
*
* @since 1.8.6
*
* @return bool|null
*/
public function run() {
return $this->run_async( DomainAutoRegistrationTask::class );
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace WPForms\Migrations;
use WPForms\Admin\Builder\TemplatesCache;
use WPForms\Tasks\Actions\StripeLinkSubscriptionsTask;
/**
* Class upgrade for 1.8.7 release.
*
* @since 1.8.7
*
* @noinspection PhpUnused
*/
class Upgrade187 extends UpgradeBase {
/**
* Run upgrade.
*
* @since 1.8.7
*
* @return bool|null
*/
public function run() {
$sync_result = $this->update_templates_cache() && $this->maybe_create_logs_table();
$async_result = $this->run_async( StripeLinkSubscriptionsTask::class );
return $async_result === null ? null : $sync_result && $async_result;
}
/**
* Update templates' cache.
*
* @since 1.8.7
*
* @return bool
*/
private function update_templates_cache(): bool {
$templates_cache = new TemplatesCache();
$templates_cache->init();
$templates_cache->update();
return true;
}
/**
* Maybe create logs' table.
* Previously, logs' table was created dynamically on the first access to the Tools->Logs admin page.
* As from 1.8.7, we create it only once during the activation of the plugin.
* So, the table may not exist, and we must maybe create it during migration to 1.8.7.
*
* @since 1.8.7
*
* @return bool
*/
private function maybe_create_logs_table(): bool {
$log = wpforms()->obj( 'log' );
if ( ! $log ) {
return false;
}
$log->create_table();
return true;
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace WPForms\Migrations;
/**
* Class upgrade for 1.9.1 release.
*
* @since 1.9.1
*/
class Upgrade1_9_1 extends UpgradeBase {
/**
* Delete existed notifications for the customer.
*
* @since 1.9.1
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
public function run() {
$this->clean_summaries_cron_event();
$notifications_option_key = 'wpforms_notifications';
$notifications = get_option( $notifications_option_key, [] );
if ( empty( $notifications['events'] ) ) {
return true;
}
$notifications['events'] = [];
update_option( 'wpforms_notifications', $notifications );
return true;
}
/**
* Clean summaries and entries count cron events,
* Since the 1.9.1 release these cron events recurrences have been changed to single event.
* The events will be recreated on the next page load.
*
* @since 1.9.1
*/
private function clean_summaries_cron_event() {
if ( wp_next_scheduled( 'wpforms_weekly_entries_count_cron' ) ) {
wp_clear_scheduled_hook( 'wpforms_weekly_entries_count_cron' );
}
if ( wp_next_scheduled( 'wpforms_email_summaries_cron' ) ) {
wp_clear_scheduled_hook( 'wpforms_email_summaries_cron' );
}
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace WPForms\Migrations;
use WPForms\Integrations\Stripe\Helpers;
use WPForms\Tasks\Actions\WebhooksAutoConfigurationTask;
/**
* Class upgrade for 1.9.2 release.
*
* @since 1.9.2
*
* @noinspection PhpUnused
*/
class Upgrade1_9_2 extends UpgradeBase {
/**
* Run upgrade.
*
* @since 1.9.2
*
* @return bool|null
*/
public function run() {
$this->set_webhooks_settings();
return $this->run_async( WebhooksAutoConfigurationTask::class );
}
/**
* Set Stripe webhooks settings.
*
* @since 1.9.2
*/
private function set_webhooks_settings() {
$settings = (array) get_option( 'wpforms_settings', [] );
// Enable Stripe webhooks by default if account is connected.
if ( ! isset( $settings['stripe-webhooks-enabled'] ) && Helpers::has_stripe_keys() ) {
$settings['stripe-webhooks-enabled'] = true;
update_option( 'wpforms_settings', $settings );
}
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace WPForms\Migrations;
/**
* Class upgrade for 1.9.7 release.
*
* @since 1.9.7
*/
class Upgrade1_9_7 extends UpgradeBase {
/**
* Run upgrade.
*
* @since 1.9.7
*/
public function run(): bool {
// Force update splash data cache.
wpforms()->obj( 'splash_cache' )->update( true );
return true;
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace WPForms\Migrations;
/**
* Class upgrade for 1.9.8.6 release.
*
* @since 1.9.8.6
*/
class Upgrade1_9_8_6 extends UpgradeBase {
/**
* Run upgrade.
*
* @since 1.9.8.6
*/
public function run(): bool {
$activated_plugins = [];
$this->check_wpconsent_activation( $activated_plugins );
$this->check_sugar_calendar_activation( $activated_plugins );
$this->check_duplicator_activation( $activated_plugins );
$this->check_uncanny_automator_activation( $activated_plugins );
add_option( 'wpforms_rotation_activated_plugins', $activated_plugins );
return true;
}
/**
* Check WPConsent plugin activation time.
*
* @since 1.9.8.6
*
* @param array $activated_plugins Reference to activated plugins array.
*/
private function check_wpconsent_activation( array &$activated_plugins ): void {
$wpconsent = get_option( 'wpconsent_activated' );
$wpconsent_time = $wpconsent['wpconsent'] ?? null;
if ( empty( $wpconsent_time ) ) {
$wpconsent_time = $wpconsent['wpconsent_pro'] ?? null;
}
if ( ! empty( $wpconsent_time ) ) {
$activated_plugins['wpconsent'] = $wpconsent_time;
}
}
/**
* Check Sugar Calendar plugin activation time.
*
* @since 1.9.8.6
*
* @param array $activated_plugins Reference to activated plugins array.
*/
private function check_sugar_calendar_activation( array &$activated_plugins ): void {
$sugar_calendar_activated_time = get_option( 'sugar_calendar_activated_time' );
if ( ! empty( $sugar_calendar_activated_time ) ) {
$activated_plugins['sugar-calendar'] = (int) $sugar_calendar_activated_time;
}
}
/**
* Check Duplicator plugin activation time.
*
* @since 1.9.8.6
*
* @param array $activated_plugins Reference to activated plugins array.
*/
private function check_duplicator_activation( array &$activated_plugins ): void {
$duplicator_install_info = get_option( 'duplicator_install_info' );
$duplicator_time = $duplicator_install_info['time'] ?? null;
if ( empty( $duplicator_time ) ) {
$duplicator_pro_install_info = get_option( 'duplicator_pro_install_info' );
$duplicator_time = $duplicator_pro_install_info['time'] ?? null;
}
if ( ! empty( $duplicator_time ) ) {
$activated_plugins['duplicator'] = $duplicator_time;
}
}
/**
* Check Uncanny Automator plugin activation time.
*
* @since 1.9.8.6
*
* @param array $activated_plugins Reference to activated plugins array.
*/
private function check_uncanny_automator_activation( array &$activated_plugins ): void {
$uncanny_automator_v6_options_migrated = get_option( 'uncanny_automator_v6_options_migrated' );
if ( ! empty( $uncanny_automator_v6_options_migrated ) ) {
$activated_plugins['uncanny-automator'] = (int) $uncanny_automator_v6_options_migrated;
}
}
}

View File

@@ -0,0 +1,148 @@
<?php
// phpcs:disable Generic.Commenting.DocComment.MissingShort
/** @noinspection PhpExpressionResultUnusedInspection */
/** @noinspection PhpPropertyOnlyWrittenInspection */
/** @noinspection UnusedConstructorDependenciesInspection */
/** @noinspection PhpUnusedAliasInspection */
// phpcs:enable Generic.Commenting.DocComment.MissingShort
namespace WPForms\Migrations;
// phpcs:disable WPForms.PHP.UseStatement.UnusedUseStatement
use WPForms\Migrations\Migrations;
use WPForms\Migrations\Tasks\UpgradeBaseTask;
use WPForms\Pro\Migrations\Migrations as MigrationsPro;
// phpcs:enable WPForms.PHP.UseStatement.UnusedUseStatement
/**
* Class UpgradeBase contains both Lite and Pro plugin upgrade methods.
*
* @since 1.7.5
*/
abstract class UpgradeBase {
/**
* Migration class instance.
*
* @since 1.7.5
*
* @var Migrations|MigrationsPro
*/
protected $migrations;
/**
* Primary class constructor.
*
* @since 1.7.5
*
* @param Migrations|MigrationsPro $migrations Instance of Migrations class.
*/
public function __construct( $migrations ) {
$this->migrations = $migrations;
}
/**
* Run upgrade.
*
* @since 1.7.5
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
abstract public function run();
/**
* Run the async upgrade via an Action Scheduler (AS) task.
* The AS task has to support STATUS option with START, IN_PROGRESS, and COMPLETED values.
* Also, the AS task must have the init() method.
*
* @since 1.7.5
*
* @param string $classname Classname of an async AS task.
*
* @return bool|null Upgrade result:
* true - the upgrade completed successfully,
* false - in the case of failure,
* null - upgrade started but not yet finished (background task).
*/
protected function run_async( string $classname ) { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
$instance = new $classname();
if ( $this->is_completed( $instance ) ) {
return true;
}
$this->maybe_start( $instance );
// Class Tasks does not exist at this point, so we have to add an action on init.
add_action(
'init',
static function () use ( $instance ) {
$instance->init();
},
PHP_INT_MAX
);
return null;
}
/**
* Determine if the async AS task is completed.
*
* @since 1.9.5
*
* @param object $instance Instance of an async AS task.
*
* @use UpgradeBaseTask::is_completed()
*
* @return bool
*/
private function is_completed( $instance ): bool {
if ( method_exists( $instance, 'is_completed' ) ) {
return $instance->is_completed();
}
// Legacy tasks.
$status = get_option( $instance::STATUS );
if ( $status === $instance::COMPLETED ) {
delete_option( $instance::STATUS );
return true;
}
return false;
}
/**
* Start the async AS task if it wasn't started yet.
*
* @since 1.9.5
*
* @param object $instance Instance of an async AS task.
*
* @use UpgradeBaseTask::maybe_start()
*/
private function maybe_start( $instance ): void {
if ( method_exists( $instance, 'maybe_start' ) ) {
$instance->maybe_start();
return;
}
// Legacy tasks.
$status = get_option( $instance::STATUS );
if ( ! $status ) {
update_option( $instance::STATUS, $instance::START );
}
}
}