Class for upgrading from legacy versions.
Description
Source
File: src/components/legacy-upgrades.php
class Legacy_Upgrades extends Service { /** * Constructor. * * @since 1.0.0 * * @param string $prefix Instance prefix. */ public function __construct( $prefix ) { $this->set_prefix( $prefix ); } /** * Upgrades legacy settings to new schema. * * @since 1.0.0 */ public function upgrade_legacy_settings() { $prefix = $this->get_prefix(); $general_mappings = array( 'modules' => array( $prefix . 'settings_general_modules', 'modules' ), 'slug' => array( $prefix . 'settings_general_slug', 'string' ), 'frontend_css' => array( $prefix . 'settings_general_frontend_css', 'bool' ), 'hard_uninstall' => array( $prefix . 'settings_general_hard_uninstall', 'bool' ), ); $general = get_option( $prefix . 'general_settings', array() ); foreach ( $general_mappings as $option => $mapping_data ) { // New values already set take precedence. if ( isset( $general[ $option ] ) ) { continue; } $old = get_option( $mapping_data[0] ); if ( false === $old ) { continue; } switch ( $mapping_data[1] ) { case 'bool': $new = ! empty( $old ) && 'no' !== strtolower( $old ) ? true : false; break; case 'modules': $old = (array) $old; $new = array(); if ( in_array( 'actions', $old, true ) ) { $new[] = 'actions'; } if ( in_array( 'results', $old, true ) ) { $new[] = 'evaluators'; } if ( in_array( 'form-settings', $old, true ) ) { $new[] = 'form_settings'; $new[] = 'access_controls'; $new[] = 'protectors'; } break; case 'string': default: $new = $old; } $general[ $option ] = $new; } if ( ! empty( $general ) ) { update_option( $prefix . 'general_settings', $general ); } $mappings = array( 'access_controls' => array( 'members' => array( 'invitation_from_name' => array( $prefix . 'settings_visitors_selectedmembers_invite_from_name', 'string' ), 'invitation_from_email' => array( $prefix . 'settings_visitors_selectedmembers_invite_from', 'string' ), 'invitation_from_subject' => array( $prefix . 'settings_visitors_selectedmembers_invite_from_subject', 'string' ), 'invitation_from_message' => array( $prefix . 'settings_visitors_selectedmembers_invite_from_text', 'string' ), 'reinvitation_from_name' => array( $prefix . 'settings_visitors_selectedmembers_reinvite_from_name', 'string' ), 'reinvitation_from_email' => array( $prefix . 'settings_visitors_selectedmembers_reinvite_from', 'string' ), 'reinvitation_from_subject' => array( $prefix . 'settings_visitors_selectedmembers_reinvite_from_subject', 'string' ), 'reinvitation_from_message' => array( $prefix . 'settings_visitors_selectedmembers_reinvite_from_text', 'string' ), ), ), 'protectors' => array( 'recaptcha' => array( 'site_key' => array( $prefix . 'settings_form_settings_spam_protection_recaptcha_sitekey', 'string' ), 'secret_key' => array( $prefix . 'settings_form_settings_spam_protection_recaptcha_secret', 'string' ), ), ), ); foreach ( $mappings as $module => $module_mappings ) { $settings = get_option( $prefix . 'module_' . $module, array() ); foreach ( $module_mappings as $submodule => $submodule_mappings ) { $option_prefix = ! empty( $submodule ) ? $submodule . '__' : ''; foreach ( $submodule_mappings as $option => $mapping_data ) { // New values already set take precedence. if ( isset( $settings[ $option_prefix . $option ] ) ) { continue; } $old = get_option( $mapping_data[0] ); if ( false === $old ) { continue; } switch ( $mapping_data[1] ) { case 'string': default: $new = $old; } $settings[ $option_prefix . $option ] = $new; } } if ( ! empty( $settings ) ) { update_option( $prefix . 'module_' . $module, $settings ); } } } /** * Upgrades legacy form metadata to new schema. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. * * @param int $form_id ID of the form for which to migrate data. */ public function upgrade_legacy_form_meta( $form_id ) { global $wpdb; $prefix = $this->get_prefix(); $participants = $this->get_full_table_name( 'participants' ); $email_notifications = $this->get_full_table_name( 'email_notifications' ); $mappings = array( 'access_controls' => array( 'user_identification' => array( 'prevent_multiple_submissions' => array( array( 'form_access_controls_allmembers_same_users', 'form_access_controls_selectedmembers_same_users' ), 'bool' ), 'identification_modes' => array( 'ip_address' => 'form_access_controls_check_ip', 'cookie' => 'form_access_controls_check_cookie', ), 'already_submitted_message' => array( 'already_entered_text', 'string' ), ), 'members' => array( 'allowed_users' => 'PARTICIPANTS', 'login_required_message' => array( 'to_be_logged_in_text', 'string' ), ), 'timerange' => array( 'start' => array( 'start_date', 'datetime' ), 'end' => array( 'end_date', 'datetime' ), ), ), 'actions' => array( 'email_notifications' => array( 'notifications' => 'EMAIL_NOTIFICATIONS', ), 'redirection' => array( 'type' => array( 'redirect_type', 'string' ), 'page' => array( 'redirect_page', 'string' ), 'url' => array( 'redirect_url', 'string' ), ), ), 'evaluators' => array(), 'form_settings' => array( '' => array( 'show_container_title' => array( 'show_page_title', 'bool' ), 'previous_button_label' => array( 'previous_button_text', 'string' ), 'next_button_label' => array( 'next_button_text', 'string' ), 'submit_button_label' => array( 'send_button_text', 'string' ), 'success_message' => array( 'redirect_text_content', 'string' ), 'allow_get_params' => array( 'allow_get_param', 'bool' ), ), ), 'protectors' => array( 'honeypot' => array( 'enabled' => array( 'honeypot_enabled', 'bool' ), ), 'linkcount' => array( 'enabled' => array( 'linkcount_enabled', 'bool' ), ), 'recaptcha' => array( 'enabled' => array( 'recaptcha_enabled', 'bool' ), 'type' => array( 'recaptcha_type', 'string' ), 'size' => array( 'recaptcha_size', 'string' ), 'theme' => array( 'recaptcha_theme', 'string' ), ), 'timetrap' => array( 'enabled' => array( 'timetrap_enabled', 'bool' ), ), ), ); $skip_enabled = array( 'access_controls-user_identification', 'access_controls-timerange', 'actions-email_notifications', 'actions-redirection', 'protectors-honeypot', 'protectors-linkcount', 'protectors-recaptcha', 'protectors-timetrap', ); foreach ( $mappings as $module => $module_mappings ) { $metadata = get_post_meta( $form_id, $prefix . 'module_' . $module, true ); if ( ! is_array( $metadata ) ) { $metadata = array(); } foreach ( $module_mappings as $submodule => $submodule_mappings ) { $submodule_data_found = false; $form_option_prefix = ! empty( $submodule ) ? $submodule . '__' : ''; foreach ( $submodule_mappings as $form_option => $mapping_data ) { if ( 'PARTICIPANTS' === $mapping_data ) { if ( get_option( $prefix . 'legacy_participants_table_installed' ) === 'true' ) { $user_ids = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT user_id FROM $participants WHERE form_id = %d", $form_id ) ); if ( ! empty( $user_ids ) ) { $submodule_data_found = true; // New values already set take precedence. if ( ! isset( $metadata[ $form_option_prefix . $form_option ] ) ) { $metadata[ $form_option_prefix . $form_option ] = $user_ids; } } } continue; } if ( 'EMAIL_NOTIFICATIONS' === $mapping_data ) { if ( get_option( $prefix . 'legacy_email_notifications_table_installed' ) === 'true' ) { $notifications = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $email_notifications WHERE form_id = %d", $form_id ) ); if ( ! empty( $notifications ) ) { $submodule_data_found = true; // New values already set take precedence. if ( ! isset( $metadata[ $form_option_prefix . $form_option ] ) ) { $metadata[ $form_option_prefix . $form_option ] = array(); foreach ( $notifications as $notification ) { $metadata[ $form_option_prefix . $form_option ][] = array( 'from_name' => $notification->from_name, 'from_email' => $notification->from_email, 'reply_email' => $notification->reply_email, 'to_email' => $notification->to_email, 'subject' => $notification->subject, 'message' => wpautop( $notification->message ), ); } } } } continue; } if ( ! isset( $mapping_data[0] ) ) { $new = array(); foreach ( $mapping_data as $group_value => $old_form_option ) { $old = get_post_meta( $form_id, $old_form_option, true ); if ( ! empty( $old ) && 'no' !== strtolower( $old ) ) { $new[] = $group_value; } } $metadata[ $form_option_prefix . $form_option ] = $new; continue; } $old = array(); if ( is_array( $mapping_data[0] ) ) { foreach ( $mapping_data[0] as $old_form_option ) { $old = get_post_meta( $form_id, $old_form_option ); if ( ! empty( $old ) ) { break; } } } else { $old = get_post_meta( $form_id, $mapping_data[0] ); } if ( empty( $old ) ) { continue; } $submodule_data_found = true; // New values already set take precedence. if ( isset( $metadata[ $form_option_prefix . $form_option ] ) ) { continue; } $old = $old[0]; switch ( $mapping_data[1] ) { case 'bool': $new = ! empty( $old ) && 'no' !== strtolower( $old ) ? true : false; break; case 'datetime': if ( ! is_numeric( $old ) ) { $old = strtotime( $old ); } $new = date( 'Y-m-d H:i:s', $old ); break; case 'string': default: $new = $old; } $metadata[ $form_option_prefix . $form_option ] = $new; } if ( ! empty( $form_option_prefix ) && ! in_array( $module . '-' . $submodule, $skip_enabled, true ) && $submodule_data_found ) { $metadata[ $form_option_prefix . 'enabled' ] = true; } } if ( ! empty( $metadata ) ) { update_post_meta( $form_id, $prefix . 'module_' . $module, $metadata ); } } } /** * Upgrades legacy form metadata to new schema if necessary. * * @since 1.0.0 * * @param int $form_id ID of the form for which to migrate data. * @return bool True if form metadata was migrated, false if it had already been * migrated before. */ public function maybe_upgrade_legacy_form_meta( $form_id ) { if ( get_post_meta( $form_id, $this->get_prefix() . 'legacy_needs_migration', true ) !== 'true' ) { return false; } $this->upgrade_legacy_form_meta( $form_id ); delete_post_meta( $form_id, $this->get_prefix() . 'legacy_needs_migration' ); return true; } /** * Upgrades legacy form attachment statuses to new attachment taxonomy term if necessary. * * This method will migrate a maximum of 50 attachments at a time, so it may not necessarily * perform the full migration. It will only delete the flag once the last attachment has been * migrated. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. * * @return bool True if form attachments were migrated, false if they had already been * migrated before. */ public function maybe_upgrade_legacy_form_attachment_statuses() { global $wpdb; if ( get_option( $this->get_prefix() . 'legacy_attachments_need_migration' ) !== 'true' ) { return false; } $general = get_option( $this->get_prefix() . 'general_settings', array() ); // If no term is set, migration is not possible. if ( empty( $general['attachment_taxonomy_term_id'] ) ) { return true; } $taxonomy_slug = torro()->taxonomies()->get_attachment_taxonomy_slug(); // If no taxonomy is available, migration is not possible. if ( empty( $taxonomy_slug ) ) { return true; } $form_attachment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s AND post_status = %s LIMIT 50", 'attachment', 'torro-forms-upload' ) ); foreach ( $form_attachment_ids as $form_attachment_id ) { $result = wp_set_post_terms( $form_attachment_id, array( $general['attachment_taxonomy_term_id'] ), $taxonomy_slug, true ); if ( is_array( $result ) ) { wp_update_post( array( 'ID' => $form_attachment_id, 'post_status' => 'inherit', ) ); } } $form_attachment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s AND post_status = %s LIMIT 1", 'attachment', 'torro-forms-upload' ) ); if ( empty( $form_attachment_ids ) ) { delete_option( $this->get_prefix() . 'legacy_attachments_need_migration' ); } return true; } /** * Runs the upgrade from a legacy version. * * @since 1.0.0 * * @param string $legacy_db_version The legacy version number. * * @codeCoverageIgnore */ public function upgrade( $legacy_db_version ) { $last_legacy_db_version = '1.0.10'; if ( $legacy_db_version === $last_legacy_db_version ) { return; } require_once ABSPATH . 'wp-admin/includes/upgrade.php'; if ( version_compare( $legacy_db_version, '1.0.3', '<' ) ) { $this->upgrade_to_1_0_3(); $this->update_db_version( '1.0.3' ); } if ( version_compare( $legacy_db_version, '1.0.4', '<' ) ) { $this->upgrade_to_1_0_4(); $this->update_db_version( '1.0.4' ); } if ( version_compare( $legacy_db_version, '1.0.5', '<' ) ) { $this->upgrade_to_1_0_5(); $this->update_db_version( '1.0.5' ); } if ( version_compare( $legacy_db_version, '1.0.6', '<' ) ) { $this->upgrade_to_1_0_6(); $this->update_db_version( '1.0.6' ); } if ( version_compare( $legacy_db_version, '1.0.7', '<' ) ) { $this->upgrade_to_1_0_7(); $this->update_db_version( '1.0.7' ); } if ( version_compare( $legacy_db_version, '1.0.8', '<' ) ) { $this->upgrade_to_1_0_8(); $this->update_db_version( '1.0.8' ); } if ( version_compare( $legacy_db_version, '1.0.9', '<' ) ) { $this->upgrade_to_1_0_9(); $this->update_db_version( '1.0.9' ); } if ( version_compare( $legacy_db_version, '1.0.10', '<' ) ) { $this->upgrade_to_1_0_10(); $this->update_db_version( '1.0.10' ); } } /** * Upgrades to legacy version 1.0.3. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. * * @codeCoverageIgnore */ protected function upgrade_to_1_0_3() { global $wpdb; $elements = $this->get_full_table_name( 'elements' ); $wpdb->query( "UPDATE $elements SET type='textfield' WHERE type='Text'" ); } /** * Upgrades to legacy version 1.0.4. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. * * @codeCoverageIgnore */ protected function upgrade_to_1_0_4() { global $wpdb; $containers = $this->get_full_table_name( 'containers' ); $elements = $this->get_full_table_name( 'elements' ); $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE $containers ( id int(11) NOT NULL AUTO_INCREMENT, form_id int(11) NOT NULL, label text NOT NULL, sort int(11) NOT NULL, UNIQUE KEY id (id) ) ENGINE = INNODB " . $charset_collate . ";"; dbDelta( $sql ); $wpdb->query( "ALTER TABLE $elements ADD container_id INT(11) NOT NULL AFTER form_id" ); } /** * Upgrades to legacy version 1.0.5. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. * * @codeCoverageIgnore */ protected function upgrade_to_1_0_5() { global $wpdb; $element_settings = $this->get_full_table_name( 'element_settings' ); $settings = $this->get_full_table_name( 'settings' ); $wpdb->query( "ALTER TABLE $settings RENAME TO $element_settings" ); } /** * Upgrades to legacy version 1.0.6. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. * * @codeCoverageIgnore */ protected function upgrade_to_1_0_6() { global $wpdb; $wpdb->update( $wpdb->posts, array( 'post_type' => $this->get_prefix() . 'form', ), array( 'post_type' => 'torro-forms', ), array( '%s' ), array( '%s' ) ); $wpdb->update( $wpdb->term_taxonomy, array( 'taxonomy' => $this->get_prefix() . 'form_category', ), array( 'taxonomy' => 'torro-forms-categories', ), array( '%s' ), array( '%s' ) ); } /** * Upgrades to legacy version 1.0.7. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. * * @codeCoverageIgnore */ protected function upgrade_to_1_0_7() { global $wpdb; $elements = $this->get_full_table_name( 'elements' ); $wpdb->query( "ALTER TABLE $elements DROP form_id" ); } /** * Upgrades to legacy version 1.0.8. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. * * @codeCoverageIgnore */ protected function upgrade_to_1_0_8() { global $wpdb; $email_notifications = $this->get_full_table_name( 'email_notifications' ); $wpdb->query( "ALTER TABLE $email_notifications ADD reply_email TEXT NOT NULL AFTER from_email" ); } /** * Upgrades to legacy version 1.0.9. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. * * @codeCoverageIgnore */ protected function upgrade_to_1_0_9() { global $wpdb; $elements = $this->get_full_table_name( 'elements' ); $wpdb->update( $elements, array( 'label' => '<hr />', 'type' => 'content' ), array( 'type' => 'separator' ) ); } /** * Upgrades to legacy version 1.0.10. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. */ protected function upgrade_to_1_0_10() { global $wpdb; $containers = $this->get_full_table_name( 'containers' ); $elements = $this->get_full_table_name( 'elements' ); $element_answers = $this->get_full_table_name( 'element_answers' ); $element_choices = $this->get_full_table_name( 'element_choices' ); $element_settings = $this->get_full_table_name( 'element_settings' ); $results = $this->get_full_table_name( 'results' ); $submissions = $this->get_full_table_name( 'submissions' ); $result_values = $this->get_full_table_name( 'result_values' ); $submission_values = $this->get_full_table_name( 'submission_values' ); $participants = $this->get_full_table_name( 'participants' ); $email_notifications = $this->get_full_table_name( 'email_notifications' ); $wpdb->query( "ALTER TABLE $containers CHANGE sort sort int(11) unsigned NOT NULL default '0'" ); $wpdb->query( "ALTER TABLE $containers ADD KEY form_id (form_id)" ); $wpdb->query( "ALTER TABLE $elements CHANGE sort sort int(11) unsigned NOT NULL default '0'" ); $wpdb->query( "ALTER TABLE $elements ADD KEY container_id (container_id)" ); $wpdb->query( "ALTER TABLE $elements ADD KEY type (type)" ); $wpdb->query( "ALTER TABLE $elements ADD KEY type_container_id (type,container_id)" ); $wpdb->query( "ALTER TABLE $element_answers RENAME TO $element_choices" ); $wpdb->query( "ALTER TABLE $element_choices CHANGE answer value text NOT NULL" ); $wpdb->query( "ALTER TABLE $element_choices CHANGE sort sort int(11) unsigned NOT NULL default '0'" ); $wpdb->query( "ALTER TABLE $element_choices ADD field char(100) NOT NULL default '' AFTER element_id" ); $wpdb->query( "ALTER TABLE $element_choices ADD KEY element_id (element_id)" ); $wpdb->query( "ALTER TABLE $element_settings ADD KEY element_id (element_id)" ); $wpdb->query( "ALTER TABLE $results RENAME TO $submissions" ); $wpdb->query( "ALTER TABLE $submissions CHANGE remote_addr remote_addr char(50) NOT NULL" ); $wpdb->query( "ALTER TABLE $submissions CHANGE cookie_key user_key char(50) NOT NULL" ); $wpdb->query( "ALTER TABLE $submissions ADD status char(50) NOT NULL default 'completed' AFTER user_key" ); $wpdb->query( "ALTER TABLE $submissions ADD KEY form_id (form_id)" ); $wpdb->query( "ALTER TABLE $submissions ADD KEY user_id (user_id)" ); $wpdb->query( "ALTER TABLE $submissions ADD KEY status (status)" ); $wpdb->query( "ALTER TABLE $submissions ADD KEY status_form_id (status,form_id)" ); $wpdb->query( "ALTER TABLE $result_values RENAME TO $submission_values" ); $wpdb->query( "ALTER TABLE $submission_values CHANGE result_id submission_id int(11) unsigned NOT NULL" ); $wpdb->query( "ALTER TABLE $submission_values ADD field char(100) NOT NULL default '' AFTER element_id" ); $wpdb->query( "ALTER TABLE $submission_values ADD KEY submission_id (submission_id)" ); $wpdb->query( "ALTER TABLE $submission_values ADD KEY element_id (element_id)" ); $this->upgrade_legacy_settings(); $form_attachment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s AND post_status = %s LIMIT 1", 'attachment', 'torro-forms-upload' ) ); if ( ! empty( $form_attachment_ids ) ) { // Set a flag to indicate that some form attachments need to have their old status migrated to a taxonomy term. update_option( $this->get_prefix() . 'legacy_attachments_need_migration', 'true' ); } // Set a flag that the old participants table still exists. update_option( $this->get_prefix() . 'legacy_participants_table_installed', 'true' ); // Set a flag that the old email notifications table still exists. update_option( $this->get_prefix() . 'legacy_email_notifications_table_installed', 'true' ); // If forms exist, their data needs to be migrated on-the-fly later. $form_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s", $this->get_prefix() . 'form' ) ); if ( empty( $form_ids ) ) { return; } // Set flags to indicate that form meta still need to be migrated. $insert_flags = array(); foreach ( $form_ids as $form_id ) { $insert_flags[] = $wpdb->prepare( "( %d, %s, %s)", (int) $form_id, $this->get_prefix() . 'legacy_needs_migration', 'true' ); } $wpdb->query( "INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value ) VALUES " . implode( ', ', $insert_flags ) ); foreach ( $form_ids as $form_id ) { wp_cache_delete( (int) $form_id, 'post_meta' ); } } /** * Updates the legacy version number. * * @since 1.0.0 * * @param string $legacy_db_version The legacy version number to set. */ protected function update_db_version( $legacy_db_version ) { update_option( $this->get_prefix() . 'db_version', $legacy_db_version ); } /** * Creates a full database table name for an unprefixed table name. * * @since 1.0.0 * * @global \wpdb $wpdb WordPress database abstraction object. * * @param string $table_name Unprefixed table name. * @return string Full table name. */ protected function get_full_table_name( $table_name ) { global $wpdb; return $wpdb->prefix . $this->get_prefix() . $table_name; } }
Changelog
Version | Description |
---|---|
1.0.0 | Introduced. |
Methods
- __construct — Constructor.
- get_full_table_name — Creates a full database table name for an unprefixed table name.
- maybe_upgrade_legacy_form_attachment_statuses — Upgrades legacy form attachment statuses to new attachment taxonomy term if necessary.
- maybe_upgrade_legacy_form_meta — Upgrades legacy form metadata to new schema if necessary.
- update_db_version — Updates the legacy version number.
- upgrade — Runs the upgrade from a legacy version.
- upgrade_legacy_form_meta — Upgrades legacy form metadata to new schema.
- upgrade_legacy_settings — Upgrades legacy settings to new schema.
- upgrade_to_1_0_10 — Upgrades to legacy version 1.0.10.
- upgrade_to_1_0_3 — Upgrades to legacy version 1.0.3.
- upgrade_to_1_0_4 — Upgrades to legacy version 1.0.4.
- upgrade_to_1_0_5 — Upgrades to legacy version 1.0.5.
- upgrade_to_1_0_6 — Upgrades to legacy version 1.0.6.
- upgrade_to_1_0_7 — Upgrades to legacy version 1.0.7.
- upgrade_to_1_0_8 — Upgrades to legacy version 1.0.8.
- upgrade_to_1_0_9 — Upgrades to legacy version 1.0.9.