Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
forbidals
/
wp-content
/
plugins
/
formidable
/
classes
/
models
:
FrmMigrate.php
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php if ( ! defined( 'ABSPATH' ) ) { die( 'You are not allowed to call this page directly.' ); } class FrmMigrate { /** * @var string */ public $fields; /** * @var string */ public $forms; /** * @var string */ public $entries; /** * @var string */ public $entry_metas; public function __construct() { global $wpdb; $this->fields = $wpdb->prefix . 'frm_fields'; $this->forms = $wpdb->prefix . 'frm_forms'; $this->entries = $wpdb->prefix . 'frm_items'; $this->entry_metas = $wpdb->prefix . 'frm_item_metas'; } /** * @return void */ public function upgrade() { do_action( 'frm_before_install' ); global $wpdb, $frm_vars; $frm_vars['doing_upgrade'] = true; $needs_upgrade = FrmAppController::compare_for_update( array( 'option' => 'frm_db_version', 'new_db_version' => FrmAppHelper::$db_version, 'new_plugin_version' => FrmAppHelper::plugin_version(), ) ); if ( $needs_upgrade ) { $this->maybe_delete_htaccess_file(); // update rewrite rules for views and other custom post types flush_rewrite_rules(); require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $old_db_version = get_option( 'frm_db_version' ); $this->create_tables(); $this->migrate_data( $old_db_version ); $this->check_that_tables_exist(); // SAVE DB VERSION. update_option( 'frm_db_version', FrmAppHelper::plugin_version() . '-' . FrmAppHelper::$db_version ); if ( ! $old_db_version ) { $this->maybe_create_contact_form(); if ( false === get_option( 'frm_first_activation' ) ) { update_option( 'frm_first_activation', time(), false ); } $this->update_settings_for_new_install(); } }//end if do_action( 'frm_after_install' ); $frm_vars['doing_upgrade'] = false; FrmAppHelper::save_combined_js(); // update the styling settings if ( function_exists( 'get_filesystem_method' ) ) { $frm_style = new FrmStyle(); $frm_style->update( 'default' ); } } /** * Check if the .htaccess file should be deleted based on server response. * If a server has AllowOverride FileInfo but not AllowOverride AuthConfig, JS and CSS files * will result in a 500 error. * * @since 6.27 * * @return void */ private function maybe_delete_htaccess_file() { $css_file_request = wp_remote_get( FrmAppHelper::plugin_url() . '/css/frm_fonts.css' ); if ( 200 === wp_remote_retrieve_response_code( $css_file_request ) ) { return; } $htaccess_path = FrmAppHelper::plugin_path() . '/.htaccess'; if ( file_exists( $htaccess_path ) ) { wp_delete_file( $htaccess_path ); } } /** * Updates some settings for new installs. * * @since 6.23 * * @return void */ private function update_settings_for_new_install() { $settings = FrmAppHelper::get_settings(); $settings->denylist_check = 1; $settings->installed_after_welcome_tour_update = 1; $settings->store(); } /** * If we fail to create the database tables, add an inbox notice. * This informs the user that they need to correct the issue and try again. * * @since 6.19 * * @return void */ private function check_that_tables_exist() { // Check the DB that the table $this->forms exists. global $wpdb; $exists = $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $this->forms ) ); if ( $exists ) { $inbox = new FrmInbox(); $inbox->dismiss( 'failed-to-create-tables' ); return; } $message = array( 'key' => 'failed-to-create-tables', 'subject' => 'Something went wrong setting up the database', 'message' => 'For steps to continue, see our <a href="https://formidableforms.com/knowledgebase/install-formidable-forms/#kb-missing-database-tables">documentation</a>. If you need assistance, we recommend that you reach out to your hosting provider. Then <a href="' . esc_url( admin_url( 'admin.php?page=formidable&frm_add_tables=1' ) ) . '">click here</a> to try again.', // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong 'cta' => '<a href="https://formidableforms.com/knowledgebase/install-formidable-forms/#kb-missing-database-tables">Learn More</a>', 'type' => 'error', ); $inbox = new FrmInbox(); $inbox->add_message( $message ); } /** * @return string */ public function collation() { global $wpdb; return $wpdb->has_cap( 'collation' ) ? $wpdb->get_charset_collate() : ''; } /** * @return void */ private function create_tables() { $charset_collate = $this->collation(); $sql = array(); /* Create/Upgrade Fields Table */ $sql[] = 'CREATE TABLE ' . $this->fields . ' ( id BIGINT(20) NOT NULL auto_increment, field_key varchar(100) default NULL, name text default NULL, description longtext default NULL, type text default NULL, default_value longtext default NULL, options longtext default NULL, field_order int(11) default 0, required int(1) default NULL, field_options longtext default NULL, form_id int(11) default NULL, created_at datetime NOT NULL, PRIMARY KEY (id), KEY form_id (form_id), UNIQUE KEY field_key (field_key) )'; /* Create/Upgrade Forms Table */ $sql[] = 'CREATE TABLE ' . $this->forms . ' ( id int(11) NOT NULL auto_increment, form_key varchar(100) default NULL, name varchar(255) default NULL, description text default NULL, parent_form_id int(11) default 0, logged_in tinyint(1) default NULL, editable tinyint(1) default NULL, is_template tinyint(1) default 0, default_template tinyint(1) default 0, status varchar(255) default NULL, options longtext default NULL, created_at datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY form_key (form_key) )'; /* Create/Upgrade Items Table */ $sql[] = 'CREATE TABLE ' . $this->entries . ' ( id BIGINT(20) NOT NULL auto_increment, item_key varchar(100) default NULL, name varchar(255) default NULL, description text default NULL, ip text default NULL, form_id BIGINT(20) default NULL, post_id BIGINT(20) default NULL, user_id BIGINT(20) default NULL, parent_item_id BIGINT(20) default 0, is_draft tinyint(1) default 0, updated_by BIGINT(20) default NULL, created_at datetime NOT NULL, updated_at datetime NOT NULL, PRIMARY KEY (id), KEY form_id (form_id), KEY post_id (post_id), KEY user_id (user_id), KEY parent_item_id (parent_item_id), UNIQUE KEY item_key (item_key) )'; /* Create/Upgrade Meta Table */ $sql[] = 'CREATE TABLE ' . $this->entry_metas . ' ( id BIGINT(20) NOT NULL auto_increment, meta_value longtext default NULL, field_id BIGINT(20) NOT NULL, item_id BIGINT(20) NOT NULL, created_at datetime NOT NULL, PRIMARY KEY (id), KEY field_id (field_id), KEY item_id (item_id) )'; foreach ( $sql as $q ) { if ( function_exists( 'dbDelta' ) ) { dbDelta( $q . $charset_collate . ';' ); } else { global $wpdb; $wpdb->query( $q . $charset_collate ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } unset( $q ); } $this->add_composite_indexes_for_entries(); } /** * These indexes help optimize database queries for entries. * * @since 6.6 * @since 6.16.3 idx_form_id_is_draft was also added to frm_items. * @since 6.17 idx_form_id_type was also added to frm_fields. * * @return void */ private function add_composite_indexes_for_entries() { global $wpdb; $table_name = "{$wpdb->prefix}frm_items"; $index_name = 'idx_is_draft_created_at'; if ( ! self::index_exists( $table_name, $index_name ) ) { $wpdb->query( "CREATE INDEX idx_is_draft_created_at ON `{$wpdb->prefix}frm_items` (is_draft, created_at)" ); } $table_name = "{$wpdb->prefix}frm_item_metas"; $index_name = 'idx_field_id_item_id'; if ( ! self::index_exists( $table_name, $index_name ) ) { $wpdb->query( "CREATE INDEX idx_field_id_item_id ON `{$wpdb->prefix}frm_item_metas` (field_id, item_id)" ); } $table_name = "{$wpdb->prefix}frm_items"; $index_name = 'idx_form_id_is_draft'; if ( ! self::index_exists( $table_name, $index_name ) ) { $wpdb->query( "CREATE INDEX idx_form_id_is_draft ON `{$wpdb->prefix}frm_items` (form_id, is_draft)" ); } $table_name = "{$wpdb->prefix}frm_fields"; $index_name = 'idx_form_id_type'; if ( ! self::index_exists( $table_name, $index_name ) ) { $wpdb->query( "CREATE INDEX idx_form_id_type ON `{$wpdb->prefix}frm_fields` (form_id, type(30))" ); } } /** * Check that an index exists in a database table before trying to add it (which results in an error). * * @since 6.6 * * @param string $table_name * @param string $index_name * * @return bool */ private static function index_exists( $table_name, $index_name ) { global $wpdb; $row = $wpdb->get_row( $wpdb->prepare( 'SELECT 1 FROM information_schema.statistics WHERE table_schema = database() AND table_name = %s AND index_name = %s LIMIT 1', array( $table_name, $index_name ) ) ); return (bool) $row; } /** * @return void */ private function maybe_create_contact_form() { $form_exists = FrmForm::get_id_by_key( 'contact-form' ); if ( ! $form_exists ) { $this->add_default_template(); } } /** * Create the default contact form * * @since 3.06 * * @return void */ private function add_default_template() { if ( FrmXMLHelper::check_if_libxml_disable_entity_loader_exists() ) { // XML import is not enabled on your server. return; } $set_err = libxml_use_internal_errors( true ); $loader = FrmXMLHelper::maybe_libxml_disable_entity_loader( true ); $file = FrmAppHelper::plugin_path() . '/classes/views/xml/default-templates.xml'; FrmXMLHelper::import_xml( $file ); libxml_use_internal_errors( $set_err ); FrmXMLHelper::maybe_libxml_disable_entity_loader( $loader ); } /** * @param int|string $old_db_version * * @return void */ private function migrate_data( $old_db_version ) { if ( ! $old_db_version ) { $old_db_version = get_option( 'frm_db_version' ); } if ( str_contains( $old_db_version, '-' ) ) { $last_upgrade = explode( '-', $old_db_version ); $old_db_version = (int) $last_upgrade[1]; } if ( ! is_numeric( $old_db_version ) ) { // bail if we don't know the previous version return; } $migrations = array( 16, 11, 16, 17, 23, 25, 86, 90, 97, 98, 101, 104 ); foreach ( $migrations as $migration ) { if ( FrmAppHelper::$db_version >= $migration && $old_db_version < $migration ) { $function_name = 'migrate_to_' . $migration; $this->$function_name(); } } } public function uninstall() { if ( ! current_user_can( 'administrator' ) ) { $frm_settings = FrmAppHelper::get_settings(); wp_die( esc_html( $frm_settings->admin_permission ) ); } global $wpdb, $wp_roles; $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->fields ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->forms ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->entries ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->entry_metas ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared delete_option( 'frm_options' ); delete_option( 'frm_db_version' ); delete_option( 'frm_install_running' ); delete_option( 'frm_lite_settings_upgrade' ); delete_option( 'frm-usage-uuid' ); delete_option( 'frm_inbox' ); delete_option( 'frmpro_css' ); delete_option( FrmOnboardingWizardController::REDIRECT_STATUS_OPTION ); delete_option( FrmEmailSummaryHelper::$option_name ); // Delete roles. $frm_roles = FrmAppHelper::frm_capabilities(); $roles = get_editable_roles(); foreach ( $frm_roles as $frm_role => $frm_role_description ) { foreach ( $roles as $role => $details ) { $wp_roles->remove_cap( $role, $frm_role ); unset( $role, $details ); } unset( $frm_role, $frm_role_description ); } unset( $roles, $frm_roles ); // delete actions, views, and styles // prevent the post deletion from triggering entries to be deleted remove_action( 'before_delete_post', 'FrmProDisplaysController::before_delete_post' ); remove_action( 'deleted_post', 'FrmProEntriesController::delete_entry' ); $post_ids = $wpdb->get_col( $wpdb->prepare( 'SELECT ID FROM ' . $wpdb->posts . ' WHERE post_type in (%s, %s, %s)', FrmFormActionsController::$action_post_type, FrmStylesController::$post_type, 'frm_display' ) ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong foreach ( $post_ids as $post_id ) { // Delete's each post. wp_delete_post( $post_id, true ); } unset( $post_ids ); // delete transients delete_transient( 'frmpro_css' ); delete_transient( 'frm_options' ); delete_transient( 'frmpro_options' ); delete_transient( FrmOnboardingWizardController::TRANSIENT_NAME ); $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE %s OR option_name LIKE %s', '_transient_timeout_frm_form_fields_%', '_transient_frm_form_fields_%' ) ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong do_action( 'frm_after_uninstall' ); return true; } /** * In older versions of Lite, it's possible we've saved the wrong location ID. * So force it to get valid values again. * * @since 6.25 * * @return void */ private function migrate_to_104() { if ( FrmSquareLiteConnectHelper::get_merchant_id( 'test' ) ) { FrmSquareLiteConnectHelper::get_location_id( true, 'test' ); } if ( FrmSquareLiteConnectHelper::get_merchant_id( 'live' ) ) { FrmSquareLiteConnectHelper::get_location_id( true, 'live' ); } } /** * Disables summary email for multisite (not the main site) if recipient setting isn't changed. * * @since 6.8 * * @return void */ private function migrate_to_101() { if ( ! is_multisite() || get_main_site_id() === get_current_blog_id() ) { return; } $frm_settings = FrmAppHelper::get_settings(); if ( empty( $frm_settings->summary_emails ) || '[admin_email]' !== $frm_settings->summary_emails_recipients ) { // User changed it. return; } $frm_settings->summary_emails = 0; $frm_settings->store(); } /** * Clear frmpro_css transient. * * @since 4.10.02 * * @return void */ private function migrate_to_98() { delete_transient( 'frmpro_css' ); } /** * Move default_blank and clear_on_focus to placeholder. * * @since 4.0 * * @return void */ private function migrate_to_97() { $this->migrate_to_placeholder( 'clear_on_focus' ); $this->migrate_to_placeholder( 'default_blank' ); } /** * Move clear_on_focus or default_blank to placeholder. * * @since 4.0 * * @param string $type Field option key to migrate. * * @return void */ private function migrate_to_placeholder( $type = 'clear_on_focus' ) { $query = array( 'field_options like' => '"' . $type . '";s:1:"1";', ); $fields = FrmDb::get_results( $this->fields, $query, 'id, default_value, field_options, options' ); foreach ( $fields as $field ) { FrmAppHelper::unserialize_or_decode( $field->field_options ); FrmAppHelper::unserialize_or_decode( $field->options ); $update_values = FrmXMLHelper::migrate_field_placeholder( $field, $type ); if ( ! $update_values ) { continue; } FrmField::update( $field->id, $update_values ); unset( $field ); } } /** * Delete unneeded default templates * * @since 3.06 * * @return void */ private function migrate_to_90() { $form = FrmForm::getOne( 'contact' ); // phpcs:ignore Universal.Operators.StrictComparisons if ( $form && $form->default_template == 1 ) { FrmForm::destroy( 'contact' ); } } /** * Reverse migration 17 -- Divide by 9 * * @since 3.0.05 * * @return void */ private function migrate_to_86() { $fields = $this->get_fields_with_size(); foreach ( $fields as $f ) { FrmAppHelper::unserialize_or_decode( $f->field_options ); $size = $f->field_options['size']; $this->maybe_convert_migrated_size( $size ); if ( $size === $f->field_options['size'] ) { continue; } $f->field_options['size'] = $size; FrmField::update( $f->id, array( 'field_options' => $f->field_options ) ); unset( $f ); } // reverse the extra size changes in widgets $widgets = get_option( 'widget_frm_show_form' ); if ( ! $widgets ) { return; } $this->revert_widget_field_size(); } /** * @return array */ private function get_fields_with_size() { $field_types = array( 'textarea', 'text', 'number', 'email', 'url', 'rte', 'date', 'phone', 'password', 'image', 'tag', 'file', ); $query = array( 'type' => $field_types, 'field_options like' => 's:4:"size";', 'field_options not like' => 's:4:"size";s:0:', ); return FrmDb::get_results( $this->fields, $query, 'id, field_options' ); } /** * Reverse the extra size changes in widgets * * @since 3.0.05 * * @return void */ private function revert_widget_field_size() { $widgets = get_option( 'widget_frm_show_form' ); if ( ! $widgets ) { return; } FrmAppHelper::unserialize_or_decode( $widgets ); foreach ( $widgets as $k => $widget ) { if ( ! is_array( $widget ) || ! isset( $widget['size'] ) ) { continue; } $this->maybe_convert_migrated_size( $widgets[ $k ]['size'] ); } update_option( 'widget_frm_show_form', $widgets ); } /** * Divide by 9 to reverse the multiplication * * @since 3.0.05 * * @param string $size Size string to maybe convert, passed by reference. * * @return void */ private function maybe_convert_migrated_size( &$size ) { $has_px_size = ! empty( $size ) && str_contains( $size, 'px' ); if ( ! $has_px_size ) { return; } $int_size = str_replace( 'px', '', $size ); if ( ! is_numeric( $int_size ) || (int) $int_size < 900 ) { return; } $pixel_conversion = 9; $size = round( (int) $int_size / $pixel_conversion ); } /** * Migrate old styling settings. If sites are using the old * default 400px field width, switch it to 100% * * @since 2.0.4 * * @return void */ private function migrate_to_25() { // get the style that was created with the style migration $frm_style = new FrmStyle(); $styles = $frm_style->get_all( 'post_date', 'ASC', 1 ); if ( ! $styles ) { return; } foreach ( $styles as $style ) { if ( $style->post_content['field_width'] === '400px' ) { $style->post_content['field_width'] = '100%'; $frm_style->save( (array) $style ); return; } } } /** * Check if the parent_form_id columns exists. * If not, try and add it again * * @since 2.0.2 * * @return void */ private function migrate_to_23() { global $wpdb; $exists = $wpdb->get_row( 'SHOW COLUMNS FROM ' . $this->forms . ' LIKE "parent_form_id"' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared if ( ! $exists ) { $wpdb->query( 'ALTER TABLE ' . $this->forms . ' ADD parent_form_id int(11) default 0' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } } /** * Change field size from character to pixel -- Multiply by 9 * * @return void */ private function migrate_to_17() { $fields = $this->get_fields_with_size(); foreach ( $fields as $f ) { FrmAppHelper::unserialize_or_decode( $f->field_options ); if ( empty( $f->field_options['size'] ) || ! is_numeric( $f->field_options['size'] ) ) { continue; } $this->convert_character_to_px( $f->field_options['size'] ); FrmField::update( $f->id, array( 'field_options' => $f->field_options ) ); unset( $f ); } $this->adjust_widget_size(); } /** * Change the characters in widgets to pixels * * @return void */ private function adjust_widget_size() { $widgets = get_option( 'widget_frm_show_form' ); if ( ! $widgets ) { return; } FrmAppHelper::unserialize_or_decode( $widgets ); foreach ( $widgets as $k => $widget ) { if ( ! is_array( $widget ) || ! isset( $widget['size'] ) ) { continue; } $this->convert_character_to_px( $widgets[ $k ]['size'] ); } update_option( 'widget_frm_show_form', $widgets ); } /** * @param string $size * * @return void */ private function convert_character_to_px( &$size ) { $pixel_conversion = 9; $size = round( $pixel_conversion * (int) $size ); $size .= 'px'; } /** * Migrate post and email notification settings into actions */ private function migrate_to_16() { $forms = FrmDb::get_results( $this->forms, array(), 'id, options, is_template, default_template' ); /** * Old email settings format: * email_to: Email or field id * also_email_to: array of fields ids * reply_to: Email, field id, 'custom' * cust_reply_to: string * reply_to_name: field id, 'custom' * cust_reply_to_name: string * plain_text: 0|1 * email_message: string or '' * email_subject: string or '' * inc_user_info: 0|1 * update_email: 0, 1, 2 * * Old autoresponder settings format: * auto_responder: 0|1 * ar_email_message: string or '' * ar_email_to: field id * ar_plain_text: 0|1 * ar_reply_to_name: string * ar_reply_to: string * ar_email_subject: string * ar_update_email: 0, 1, 2 * * New email settings: * post_content: json settings * post_title: form id * post_excerpt: message */ foreach ( $forms as $form ) { if ( $form->is_template && $form->default_template ) { // don't migrate the default templates since the email will be added anyway continue; } // Format form options $form_options = $form->options; FrmAppHelper::unserialize_or_decode( $form_options ); // Migrate settings to actions FrmXMLHelper::migrate_form_settings_to_actions( $form_options, $form->id ); } } private function migrate_to_11() { global $wpdb; $forms = FrmDb::get_results( $this->forms, array(), 'id, options' ); $sending = __( 'Sending', 'formidable' ); $img = FrmAppHelper::plugin_url() . '/images/ajax_loader.gif'; $old_default_html = <<<DEFAULT_HTML <div class="frm_submit"> [if back_button]<input type="submit" value="[back_label]" name="frm_prev_page" formnovalidate="formnovalidate" [back_hook] />[/if back_button] <input type="submit" value="[button_label]" [button_action] /> <img class="frm_ajax_loading" src="$img" alt="$sending" style="visibility:hidden;" /> </div> DEFAULT_HTML; unset( $sending, $img ); $new_default_html = FrmFormsHelper::get_default_html( 'submit' ); $draft_link = FrmFormsHelper::get_draft_link(); foreach ( $forms as $form ) { FrmAppHelper::unserialize_or_decode( $form->options ); if ( empty( $form->options['submit_html'] ) ) { continue; } // phpcs:ignore Universal.Operators.StrictComparisons if ( $form->options['submit_html'] != $new_default_html && $form->options['submit_html'] == $old_default_html ) { $form->options['submit_html'] = $new_default_html; $wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) ); } elseif ( ! str_contains( $form->options['submit_html'], 'save_draft' ) ) { $form->options['submit_html'] = preg_replace( '~\<\/div\>(?!.*\<\/div\>)~', $draft_link . "\r\n</div>", $form->options['submit_html'] ); $wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) ); } unset( $form ); } } }