PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.15
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.15
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / models / FrmMigrate.php

FrmMigrate.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.15, at classes/models/FrmMigrate.php

675 lines 19.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class FrmMigrate {
7 public $fields;
8 public $forms;
9 public $entries;
10 public $entry_metas;
11
12 public function __construct() {
13 global $wpdb;
14 $this->fields = $wpdb->prefix . 'frm_fields';
15 $this->forms = $wpdb->prefix . 'frm_forms';
16 $this->entries = $wpdb->prefix . 'frm_items';
17 $this->entry_metas = $wpdb->prefix . 'frm_item_metas';
18 }
19
20 public function upgrade() {
21 do_action( 'frm_before_install' );
22
23 global $wpdb, $frm_vars;
24
25 $frm_vars['doing_upgrade'] = true;
26
27 $needs_upgrade = FrmAppController::compare_for_update(
28 array(
29 'option' => 'frm_db_version',
30 'new_db_version' => FrmAppHelper::$db_version,
31 'new_plugin_version' => FrmAppHelper::plugin_version(),
32 )
33 );
34
35 if ( $needs_upgrade ) {
36 // update rewrite rules for views and other custom post types
37 flush_rewrite_rules();
38
39 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
40
41 $old_db_version = get_option( 'frm_db_version' );
42
43 $this->create_tables();
44 $this->migrate_data( $old_db_version );
45
46 // SAVE DB VERSION.
47 update_option( 'frm_db_version', FrmAppHelper::plugin_version() . '-' . FrmAppHelper::$db_version );
48
49 if ( ! $old_db_version ) {
50 $this->maybe_create_contact_form();
51 }
52 }
53
54 do_action( 'frm_after_install' );
55
56 $frm_vars['doing_upgrade'] = false;
57
58 FrmAppHelper::save_combined_js();
59
60 // update the styling settings
61 if ( function_exists( 'get_filesystem_method' ) ) {
62 $frm_style = new FrmStyle();
63 $frm_style->update( 'default' );
64 }
65 }
66
67 public function collation() {
68 global $wpdb;
69 if ( ! $wpdb->has_cap( 'collation' ) ) {
70 return '';
71 }
72
73 return $wpdb->get_charset_collate();
74 }
75
76 private function create_tables() {
77 $charset_collate = $this->collation();
78 $sql = array();
79
80 /* Create/Upgrade Fields Table */
81 $sql[] = 'CREATE TABLE ' . $this->fields . ' (
82 id BIGINT(20) NOT NULL auto_increment,
83 field_key varchar(100) default NULL,
84 name text default NULL,
85 description longtext default NULL,
86 type text default NULL,
87 default_value longtext default NULL,
88 options longtext default NULL,
89 field_order int(11) default 0,
90 required int(1) default NULL,
91 field_options longtext default NULL,
92 form_id int(11) default NULL,
93 created_at datetime NOT NULL,
94 PRIMARY KEY (id),
95 KEY form_id (form_id),
96 UNIQUE KEY field_key (field_key)
97 )';
98
99 /* Create/Upgrade Forms Table */
100 $sql[] = 'CREATE TABLE ' . $this->forms . ' (
101 id int(11) NOT NULL auto_increment,
102 form_key varchar(100) default NULL,
103 name varchar(255) default NULL,
104 description text default NULL,
105 parent_form_id int(11) default 0,
106 logged_in tinyint(1) default NULL,
107 editable tinyint(1) default NULL,
108 is_template tinyint(1) default 0,
109 default_template tinyint(1) default 0,
110 status varchar(255) default NULL,
111 options longtext default NULL,
112 created_at datetime NOT NULL,
113 PRIMARY KEY (id),
114 UNIQUE KEY form_key (form_key)
115 )';
116
117 /* Create/Upgrade Items Table */
118 $sql[] = 'CREATE TABLE ' . $this->entries . ' (
119 id BIGINT(20) NOT NULL auto_increment,
120 item_key varchar(100) default NULL,
121 name varchar(255) default NULL,
122 description text default NULL,
123 ip text default NULL,
124 form_id BIGINT(20) default NULL,
125 post_id BIGINT(20) default NULL,
126 user_id BIGINT(20) default NULL,
127 parent_item_id BIGINT(20) default 0,
128 is_draft tinyint(1) default 0,
129 updated_by BIGINT(20) default NULL,
130 created_at datetime NOT NULL,
131 updated_at datetime NOT NULL,
132 PRIMARY KEY (id),
133 KEY form_id (form_id),
134 KEY post_id (post_id),
135 KEY user_id (user_id),
136 KEY parent_item_id (parent_item_id),
137 UNIQUE KEY item_key (item_key)
138 )';
139
140 /* Create/Upgrade Meta Table */
141 $sql[] = 'CREATE TABLE ' . $this->entry_metas . ' (
142 id BIGINT(20) NOT NULL auto_increment,
143 meta_value longtext default NULL,
144 field_id BIGINT(20) NOT NULL,
145 item_id BIGINT(20) NOT NULL,
146 created_at datetime NOT NULL,
147 PRIMARY KEY (id),
148 KEY field_id (field_id),
149 KEY item_id (item_id)
150 )';
151
152 foreach ( $sql as $q ) {
153 if ( function_exists( 'dbDelta' ) ) {
154 dbDelta( $q . $charset_collate . ';' );
155 } else {
156 global $wpdb;
157 $wpdb->query( $q . $charset_collate ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
158 }
159 unset( $q );
160 }
161
162 $this->add_composite_indexes_for_entries();
163 }
164
165 /**
166 * These indexes help optimize database queries for entries.
167 *
168 * @since 6.6
169 *
170 * @return void
171 */
172 private function add_composite_indexes_for_entries() {
173 global $wpdb;
174
175 $table_name = "{$wpdb->prefix}frm_items";
176 $index_name = 'idx_is_draft_created_at';
177
178 if ( ! self::index_exists( $table_name, $index_name ) ) {
179 $wpdb->query( "CREATE INDEX idx_is_draft_created_at ON `{$wpdb->prefix}frm_items` (is_draft, created_at)" );
180 }
181
182 $table_name = "{$wpdb->prefix}frm_item_metas";
183 $index_name = 'idx_field_id_item_id';
184
185 if ( ! self::index_exists( $table_name, $index_name ) ) {
186 $wpdb->query( "CREATE INDEX idx_field_id_item_id ON `{$wpdb->prefix}frm_item_metas` (field_id, item_id)" );
187 }
188 }
189
190 /**
191 * Check that an index exists in a database table before trying to add it (which results in an error).
192 *
193 * @since 6.6
194 *
195 * @param string $table_name
196 * @param string $index_name
197 * @return bool
198 */
199 private static function index_exists( $table_name, $index_name ) {
200 global $wpdb;
201 $row = $wpdb->get_row(
202 $wpdb->prepare(
203 'SELECT 1 FROM information_schema.statistics
204 WHERE table_schema = database()
205 AND table_name = %s
206 AND index_name = %s
207 LIMIT 1',
208 array( $table_name, $index_name )
209 )
210 );
211 return (bool) $row;
212 }
213
214 private function maybe_create_contact_form() {
215 $form_exists = FrmForm::get_id_by_key( 'contact-form' );
216 if ( ! $form_exists ) {
217 $this->add_default_template();
218 }
219 }
220
221 /**
222 * Create the default contact form
223 *
224 * @since 3.06
225 */
226 private function add_default_template() {
227 if ( FrmXMLHelper::check_if_libxml_disable_entity_loader_exists() ) {
228 // XML import is not enabled on your server.
229 return;
230 }
231
232 $set_err = libxml_use_internal_errors( true );
233 $loader = FrmXMLHelper::maybe_libxml_disable_entity_loader( true );
234
235 $file = FrmAppHelper::plugin_path() . '/classes/views/xml/default-templates.xml';
236 FrmXMLHelper::import_xml( $file );
237
238 libxml_use_internal_errors( $set_err );
239 FrmXMLHelper::maybe_libxml_disable_entity_loader( $loader );
240 }
241
242 /**
243 * @param int|string $old_db_version
244 */
245 private function migrate_data( $old_db_version ) {
246 if ( ! $old_db_version ) {
247 $old_db_version = get_option( 'frm_db_version' );
248 }
249 if ( strpos( $old_db_version, '-' ) ) {
250 $last_upgrade = explode( '-', $old_db_version );
251 $old_db_version = (int) $last_upgrade[1];
252 }
253
254 if ( ! is_numeric( $old_db_version ) ) {
255 // bail if we don't know the previous version
256 return;
257 }
258
259 $migrations = array( 16, 11, 16, 17, 23, 25, 86, 90, 97, 98, 101 );
260 foreach ( $migrations as $migration ) {
261 if ( FrmAppHelper::$db_version >= $migration && $old_db_version < $migration ) {
262 $function_name = 'migrate_to_' . $migration;
263 $this->$function_name();
264 }
265 }
266 }
267
268 public function uninstall() {
269 if ( ! current_user_can( 'administrator' ) ) {
270 $frm_settings = FrmAppHelper::get_settings();
271 wp_die( esc_html( $frm_settings->admin_permission ) );
272 }
273
274 global $wpdb, $wp_roles;
275
276 $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->fields ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
277 $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->forms ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
278 $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->entries ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
279 $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->entry_metas ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
280
281 delete_option( 'frm_options' );
282 delete_option( 'frm_db_version' );
283 delete_option( 'frm_install_running' );
284 delete_option( 'frm_lite_settings_upgrade' );
285 delete_option( 'frm-usage-uuid' );
286 delete_option( 'frm_inbox' );
287 delete_option( 'frmpro_css' );
288 delete_option( FrmOnboardingWizardController::REDIRECT_STATUS_OPTION );
289 delete_option( FrmEmailSummaryHelper::$option_name );
290
291 // Delete roles.
292 $frm_roles = FrmAppHelper::frm_capabilities();
293 $roles = get_editable_roles();
294 foreach ( $frm_roles as $frm_role => $frm_role_description ) {
295 foreach ( $roles as $role => $details ) {
296 $wp_roles->remove_cap( $role, $frm_role );
297 unset( $role, $details );
298 }
299 unset( $frm_role, $frm_role_description );
300 }
301 unset( $roles, $frm_roles );
302
303 // delete actions, views, and styles
304
305 // prevent the post deletion from triggering entries to be deleted
306 remove_action( 'before_delete_post', 'FrmProDisplaysController::before_delete_post' );
307 remove_action( 'deleted_post', 'FrmProEntriesController::delete_entry' );
308
309 $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' ) );
310 foreach ( $post_ids as $post_id ) {
311 // Delete's each post.
312 wp_delete_post( $post_id, true );
313 }
314 unset( $post_ids );
315
316 // delete transients
317 delete_transient( 'frmpro_css' );
318 delete_transient( 'frm_options' );
319 delete_transient( 'frmpro_options' );
320 delete_transient( FrmOnboardingWizardController::TRANSIENT_NAME );
321
322 $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_%' ) );
323
324 do_action( 'frm_after_uninstall' );
325
326 return true;
327 }
328
329 /**
330 * Disables summary email for multisite (not the main site) if recipient setting isn't changed.
331 *
332 * @since 6.8
333 */
334 private function migrate_to_101() {
335 if ( ! is_multisite() || get_main_site_id() === get_current_blog_id() ) {
336 return;
337 }
338
339 $frm_settings = FrmAppHelper::get_settings();
340 if ( empty( $frm_settings->summary_emails ) || '[admin_email]' !== $frm_settings->summary_emails_recipients ) {
341 // User changed it.
342 return;
343 }
344
345 $frm_settings->summary_emails = 0;
346 $frm_settings->store();
347 }
348
349 /**
350 * Clear frmpro_css transient.
351 *
352 * @since 4.10.02
353 */
354 private function migrate_to_98() {
355 delete_transient( 'frmpro_css' );
356 }
357
358 /**
359 * Move default_blank and clear_on_focus to placeholder.
360 *
361 * @since 4.0
362 */
363 private function migrate_to_97() {
364 $this->migrate_to_placeholder( 'clear_on_focus' );
365 $this->migrate_to_placeholder( 'default_blank' );
366 }
367
368 /**
369 * Move clear_on_focus or default_blank to placeholder.
370 *
371 * @since 4.0
372 */
373 private function migrate_to_placeholder( $type = 'clear_on_focus' ) {
374 $query = array(
375 'field_options like' => '"' . $type . '";s:1:"1";',
376 );
377
378 $fields = FrmDb::get_results( $this->fields, $query, 'id, default_value, field_options, options' );
379
380 foreach ( $fields as $field ) {
381 FrmAppHelper::unserialize_or_decode( $field->field_options );
382 FrmAppHelper::unserialize_or_decode( $field->options );
383 $update_values = FrmXMLHelper::migrate_field_placeholder( $field, $type );
384 if ( empty( $update_values ) ) {
385 continue;
386 }
387
388 FrmField::update( $field->id, $update_values );
389 unset( $field );
390 }
391 }
392
393 /**
394 * Delete unneeded default templates
395 *
396 * @since 3.06
397 */
398 private function migrate_to_90() {
399 $form = FrmForm::getOne( 'contact' );
400 if ( $form && $form->default_template == 1 ) {
401 FrmForm::destroy( 'contact' );
402 }
403 }
404
405 /**
406 * Reverse migration 17 -- Divide by 9
407 *
408 * @since 3.0.05
409 */
410 private function migrate_to_86() {
411
412 $fields = $this->get_fields_with_size();
413
414 foreach ( (array) $fields as $f ) {
415 FrmAppHelper::unserialize_or_decode( $f->field_options );
416 $size = $f->field_options['size'];
417 $this->maybe_convert_migrated_size( $size );
418
419 if ( $size === $f->field_options['size'] ) {
420 continue;
421 }
422
423 $f->field_options['size'] = $size;
424 FrmField::update( $f->id, array( 'field_options' => $f->field_options ) );
425 unset( $f );
426 }
427
428 // reverse the extra size changes in widgets
429 $widgets = get_option( 'widget_frm_show_form' );
430 if ( empty( $widgets ) ) {
431 return;
432 }
433
434 $this->revert_widget_field_size();
435 }
436
437 private function get_fields_with_size() {
438 $field_types = array(
439 'textarea',
440 'text',
441 'number',
442 'email',
443 'url',
444 'rte',
445 'date',
446 'phone',
447 'password',
448 'image',
449 'tag',
450 'file',
451 );
452
453 $query = array(
454 'type' => $field_types,
455 'field_options like' => 's:4:"size";',
456 'field_options not like' => 's:4:"size";s:0:',
457 );
458
459 return FrmDb::get_results( $this->fields, $query, 'id, field_options' );
460 }
461
462 /**
463 * Reverse the extra size changes in widgets
464 *
465 * @since 3.0.05
466 */
467 private function revert_widget_field_size() {
468 $widgets = get_option( 'widget_frm_show_form' );
469 if ( empty( $widgets ) ) {
470 return;
471 }
472
473 FrmAppHelper::unserialize_or_decode( $widgets );
474 foreach ( $widgets as $k => $widget ) {
475 if ( ! is_array( $widget ) || ! isset( $widget['size'] ) ) {
476 continue;
477 }
478
479 $this->maybe_convert_migrated_size( $widgets[ $k ]['size'] );
480 }
481 update_option( 'widget_frm_show_form', $widgets );
482 }
483
484 /**
485 * Divide by 9 to reverse the multiplication
486 *
487 * @since 3.0.05
488 */
489 private function maybe_convert_migrated_size( &$size ) {
490 $has_px_size = ! empty( $size ) && strpos( $size, 'px' );
491 if ( ! $has_px_size ) {
492 return;
493 }
494
495 $int_size = str_replace( 'px', '', $size );
496 if ( ! is_numeric( $int_size ) || (int) $int_size < 900 ) {
497 return;
498 }
499
500 $pixel_conversion = 9;
501
502 $size = round( (int) $int_size / $pixel_conversion );
503 }
504
505 /**
506 * Migrate old styling settings. If sites are using the old
507 * default 400px field width, switch it to 100%
508 *
509 * @since 2.0.4
510 */
511 private function migrate_to_25() {
512 // get the style that was created with the style migration
513 $frm_style = new FrmStyle();
514 $styles = $frm_style->get_all( 'post_date', 'ASC', 1 );
515 if ( empty( $styles ) ) {
516 return;
517 }
518
519 foreach ( $styles as $style ) {
520 if ( $style->post_content['field_width'] === '400px' ) {
521 $style->post_content['field_width'] = '100%';
522 $frm_style->save( (array) $style );
523
524 return;
525 }
526 }
527 }
528
529 /**
530 * Check if the parent_form_id columns exists.
531 * If not, try and add it again
532 *
533 * @since 2.0.2
534 */
535 private function migrate_to_23() {
536 global $wpdb;
537 $exists = $wpdb->get_row( 'SHOW COLUMNS FROM ' . $this->forms . ' LIKE "parent_form_id"' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
538 if ( empty( $exists ) ) {
539 $wpdb->query( 'ALTER TABLE ' . $this->forms . ' ADD parent_form_id int(11) default 0' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
540 }
541 }
542
543 /**
544 * Change field size from character to pixel -- Multiply by 9
545 */
546 private function migrate_to_17() {
547 $fields = $this->get_fields_with_size();
548
549 foreach ( $fields as $f ) {
550 FrmAppHelper::unserialize_or_decode( $f->field_options );
551 if ( empty( $f->field_options['size'] ) || ! is_numeric( $f->field_options['size'] ) ) {
552 continue;
553 }
554
555 $this->convert_character_to_px( $f->field_options['size'] );
556
557 FrmField::update( $f->id, array( 'field_options' => $f->field_options ) );
558 unset( $f );
559 }
560
561 $this->adjust_widget_size();
562 }
563
564 /**
565 * Change the characters in widgets to pixels
566 */
567 private function adjust_widget_size() {
568 $widgets = get_option( 'widget_frm_show_form' );
569 if ( empty( $widgets ) ) {
570 return;
571 }
572
573 FrmAppHelper::unserialize_or_decode( $widgets );
574 foreach ( $widgets as $k => $widget ) {
575 if ( ! is_array( $widget ) || ! isset( $widget['size'] ) ) {
576 continue;
577 }
578 $this->convert_character_to_px( $widgets[ $k ]['size'] );
579 }
580 update_option( 'widget_frm_show_form', $widgets );
581 }
582
583 private function convert_character_to_px( &$size ) {
584 $pixel_conversion = 9;
585
586 $size = round( $pixel_conversion * (int) $size );
587 $size .= 'px';
588 }
589
590 /**
591 * Migrate post and email notification settings into actions
592 */
593 private function migrate_to_16() {
594 $forms = FrmDb::get_results( $this->forms, array(), 'id, options, is_template, default_template' );
595
596 /**
597 * Old email settings format:
598 * email_to: Email or field id
599 * also_email_to: array of fields ids
600 * reply_to: Email, field id, 'custom'
601 * cust_reply_to: string
602 * reply_to_name: field id, 'custom'
603 * cust_reply_to_name: string
604 * plain_text: 0|1
605 * email_message: string or ''
606 * email_subject: string or ''
607 * inc_user_info: 0|1
608 * update_email: 0, 1, 2
609 *
610 * Old autoresponder settings format:
611 * auto_responder: 0|1
612 * ar_email_message: string or ''
613 * ar_email_to: field id
614 * ar_plain_text: 0|1
615 * ar_reply_to_name: string
616 * ar_reply_to: string
617 * ar_email_subject: string
618 * ar_update_email: 0, 1, 2
619 *
620 * New email settings:
621 * post_content: json settings
622 * post_title: form id
623 * post_excerpt: message
624 */
625 foreach ( $forms as $form ) {
626 if ( $form->is_template && $form->default_template ) {
627 // don't migrate the default templates since the email will be added anyway
628 continue;
629 }
630
631 // Format form options
632 $form_options = $form->options;
633 FrmAppHelper::unserialize_or_decode( $form_options );
634
635 // Migrate settings to actions
636 FrmXMLHelper::migrate_form_settings_to_actions( $form_options, $form->id );
637 }
638 }
639
640 private function migrate_to_11() {
641 global $wpdb;
642
643 $forms = FrmDb::get_results( $this->forms, array(), 'id, options' );
644
645 $sending = __( 'Sending', 'formidable' );
646 $img = FrmAppHelper::plugin_url() . '/images/ajax_loader.gif';
647 $old_default_html = <<<DEFAULT_HTML
648 <div class="frm_submit">
649 [if back_button]<input type="submit" value="[back_label]" name="frm_prev_page" formnovalidate="formnovalidate" [back_hook] />[/if back_button]
650 <input type="submit" value="[button_label]" [button_action] />
651 <img class="frm_ajax_loading" src="$img" alt="$sending" style="visibility:hidden;" />
652 </div>
653 DEFAULT_HTML;
654 unset( $sending, $img );
655
656 $new_default_html = FrmFormsHelper::get_default_html( 'submit' );
657 $draft_link = FrmFormsHelper::get_draft_link();
658 foreach ( $forms as $form ) {
659 FrmAppHelper::unserialize_or_decode( $form->options );
660 if ( empty( $form->options['submit_html'] ) ) {
661 continue;
662 }
663
664 if ( $form->options['submit_html'] != $new_default_html && $form->options['submit_html'] == $old_default_html ) {
665 $form->options['submit_html'] = $new_default_html;
666 $wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) );
667 } elseif ( ! strpos( $form->options['submit_html'], 'save_draft' ) ) {
668 $form->options['submit_html'] = preg_replace( '~\<\/div\>(?!.*\<\/div\>)~', $draft_link . "\r\n</div>", $form->options['submit_html'] );
669 $wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) );
670 }
671 unset( $form );
672 }
673 }
674 }
675