PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.7
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.7
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.7, at classes/models/FrmMigrate.php

655 lines 18.7 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 );
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( 'frm_welcome_redirect' );
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( 'frm_activation_redirect' );
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 * Clear frmpro_css transient.
331 *
332 * @since 4.10.02
333 */
334 private function migrate_to_98() {
335 delete_transient( 'frmpro_css' );
336 }
337
338 /**
339 * Move default_blank and clear_on_focus to placeholder.
340 *
341 * @since 4.0
342 */
343 private function migrate_to_97() {
344 $this->migrate_to_placeholder( 'clear_on_focus' );
345 $this->migrate_to_placeholder( 'default_blank' );
346 }
347
348 /**
349 * Move clear_on_focus or default_blank to placeholder.
350 *
351 * @since 4.0
352 */
353 private function migrate_to_placeholder( $type = 'clear_on_focus' ) {
354 $query = array(
355 'field_options like' => '"' . $type . '";s:1:"1";',
356 );
357
358 $fields = FrmDb::get_results( $this->fields, $query, 'id, default_value, field_options, options' );
359
360 foreach ( $fields as $field ) {
361 FrmAppHelper::unserialize_or_decode( $field->field_options );
362 FrmAppHelper::unserialize_or_decode( $field->options );
363 $update_values = FrmXMLHelper::migrate_field_placeholder( $field, $type );
364 if ( empty( $update_values ) ) {
365 continue;
366 }
367
368 FrmField::update( $field->id, $update_values );
369 unset( $field );
370 }
371 }
372
373 /**
374 * Delete uneeded default templates
375 *
376 * @since 3.06
377 */
378 private function migrate_to_90() {
379 $form = FrmForm::getOne( 'contact' );
380 if ( $form && $form->default_template == 1 ) {
381 FrmForm::destroy( 'contact' );
382 }
383 }
384
385 /**
386 * Reverse migration 17 -- Divide by 9
387 *
388 * @since 3.0.05
389 */
390 private function migrate_to_86() {
391
392 $fields = $this->get_fields_with_size();
393
394 foreach ( (array) $fields as $f ) {
395 FrmAppHelper::unserialize_or_decode( $f->field_options );
396 $size = $f->field_options['size'];
397 $this->maybe_convert_migrated_size( $size );
398
399 if ( $size === $f->field_options['size'] ) {
400 continue;
401 }
402
403 $f->field_options['size'] = $size;
404 FrmField::update( $f->id, array( 'field_options' => $f->field_options ) );
405 unset( $f );
406 }
407
408 // reverse the extra size changes in widgets
409 $widgets = get_option( 'widget_frm_show_form' );
410 if ( empty( $widgets ) ) {
411 return;
412 }
413
414 $this->revert_widget_field_size();
415 }
416
417 private function get_fields_with_size() {
418 $field_types = array(
419 'textarea',
420 'text',
421 'number',
422 'email',
423 'url',
424 'rte',
425 'date',
426 'phone',
427 'password',
428 'image',
429 'tag',
430 'file',
431 );
432
433 $query = array(
434 'type' => $field_types,
435 'field_options like' => 's:4:"size";',
436 'field_options not like' => 's:4:"size";s:0:',
437 );
438
439 return FrmDb::get_results( $this->fields, $query, 'id, field_options' );
440 }
441
442 /**
443 * Reverse the extra size changes in widgets
444 *
445 * @since 3.0.05
446 */
447 private function revert_widget_field_size() {
448 $widgets = get_option( 'widget_frm_show_form' );
449 if ( empty( $widgets ) ) {
450 return;
451 }
452
453 FrmAppHelper::unserialize_or_decode( $widgets );
454 foreach ( $widgets as $k => $widget ) {
455 if ( ! is_array( $widget ) || ! isset( $widget['size'] ) ) {
456 continue;
457 }
458
459 $this->maybe_convert_migrated_size( $widgets[ $k ]['size'] );
460 }
461 update_option( 'widget_frm_show_form', $widgets );
462 }
463
464 /**
465 * Divide by 9 to reverse the multiplication
466 *
467 * @since 3.0.05
468 */
469 private function maybe_convert_migrated_size( &$size ) {
470 $has_px_size = ! empty( $size ) && strpos( $size, 'px' );
471 if ( ! $has_px_size ) {
472 return;
473 }
474
475 $int_size = str_replace( 'px', '', $size );
476 if ( ! is_numeric( $int_size ) || (int) $int_size < 900 ) {
477 return;
478 }
479
480 $pixel_conversion = 9;
481
482 $size = round( (int) $int_size / $pixel_conversion );
483 }
484
485 /**
486 * Migrate old styling settings. If sites are using the old
487 * default 400px field width, switch it to 100%
488 *
489 * @since 2.0.4
490 */
491 private function migrate_to_25() {
492 // get the style that was created with the style migration
493 $frm_style = new FrmStyle();
494 $styles = $frm_style->get_all( 'post_date', 'ASC', 1 );
495 if ( empty( $styles ) ) {
496 return;
497 }
498
499 foreach ( $styles as $style ) {
500 if ( $style->post_content['field_width'] == '400px' ) {
501 $style->post_content['field_width'] = '100%';
502 $frm_style->save( (array) $style );
503
504 return;
505 }
506 }
507 }
508
509 /**
510 * Check if the parent_form_id columns exists.
511 * If not, try and add it again
512 *
513 * @since 2.0.2
514 */
515 private function migrate_to_23() {
516 global $wpdb;
517 $exists = $wpdb->get_row( 'SHOW COLUMNS FROM ' . $this->forms . ' LIKE "parent_form_id"' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
518 if ( empty( $exists ) ) {
519 $wpdb->query( 'ALTER TABLE ' . $this->forms . ' ADD parent_form_id int(11) default 0' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
520 }
521 }
522
523 /**
524 * Change field size from character to pixel -- Multiply by 9
525 */
526 private function migrate_to_17() {
527 $fields = $this->get_fields_with_size();
528
529 foreach ( $fields as $f ) {
530 FrmAppHelper::unserialize_or_decode( $f->field_options );
531 if ( empty( $f->field_options['size'] ) || ! is_numeric( $f->field_options['size'] ) ) {
532 continue;
533 }
534
535 $this->convert_character_to_px( $f->field_options['size'] );
536
537 FrmField::update( $f->id, array( 'field_options' => $f->field_options ) );
538 unset( $f );
539 }
540
541 $this->adjust_widget_size();
542 }
543
544 /**
545 * Change the characters in widgets to pixels
546 */
547 private function adjust_widget_size() {
548 $widgets = get_option( 'widget_frm_show_form' );
549 if ( empty( $widgets ) ) {
550 return;
551 }
552
553 FrmAppHelper::unserialize_or_decode( $widgets );
554 foreach ( $widgets as $k => $widget ) {
555 if ( ! is_array( $widget ) || ! isset( $widget['size'] ) ) {
556 continue;
557 }
558 $this->convert_character_to_px( $widgets[ $k ]['size'] );
559 }
560 update_option( 'widget_frm_show_form', $widgets );
561 }
562
563 private function convert_character_to_px( &$size ) {
564 $pixel_conversion = 9;
565
566 $size = round( $pixel_conversion * (int) $size );
567 $size .= 'px';
568 }
569
570 /**
571 * Migrate post and email notification settings into actions
572 */
573 private function migrate_to_16() {
574 $forms = FrmDb::get_results( $this->forms, array(), 'id, options, is_template, default_template' );
575
576 /**
577 * Old email settings format:
578 * email_to: Email or field id
579 * also_email_to: array of fields ids
580 * reply_to: Email, field id, 'custom'
581 * cust_reply_to: string
582 * reply_to_name: field id, 'custom'
583 * cust_reply_to_name: string
584 * plain_text: 0|1
585 * email_message: string or ''
586 * email_subject: string or ''
587 * inc_user_info: 0|1
588 * update_email: 0, 1, 2
589 *
590 * Old autoresponder settings format:
591 * auto_responder: 0|1
592 * ar_email_message: string or ''
593 * ar_email_to: field id
594 * ar_plain_text: 0|1
595 * ar_reply_to_name: string
596 * ar_reply_to: string
597 * ar_email_subject: string
598 * ar_update_email: 0, 1, 2
599 *
600 * New email settings:
601 * post_content: json settings
602 * post_title: form id
603 * post_excerpt: message
604 */
605 foreach ( $forms as $form ) {
606 if ( $form->is_template && $form->default_template ) {
607 // don't migrate the default templates since the email will be added anyway
608 continue;
609 }
610
611 // Format form options
612 $form_options = $form->options;
613 FrmAppHelper::unserialize_or_decode( $form_options );
614
615 // Migrate settings to actions
616 FrmXMLHelper::migrate_form_settings_to_actions( $form_options, $form->id );
617 }
618 }
619
620 private function migrate_to_11() {
621 global $wpdb;
622
623 $forms = FrmDb::get_results( $this->forms, array(), 'id, options' );
624
625 $sending = __( 'Sending', 'formidable' );
626 $img = FrmAppHelper::plugin_url() . '/images/ajax_loader.gif';
627 $old_default_html = <<<DEFAULT_HTML
628 <div class="frm_submit">
629 [if back_button]<input type="submit" value="[back_label]" name="frm_prev_page" formnovalidate="formnovalidate" [back_hook] />[/if back_button]
630 <input type="submit" value="[button_label]" [button_action] />
631 <img class="frm_ajax_loading" src="$img" alt="$sending" style="visibility:hidden;" />
632 </div>
633 DEFAULT_HTML;
634 unset( $sending, $img );
635
636 $new_default_html = FrmFormsHelper::get_default_html( 'submit' );
637 $draft_link = FrmFormsHelper::get_draft_link();
638 foreach ( $forms as $form ) {
639 FrmAppHelper::unserialize_or_decode( $form->options );
640 if ( ! isset( $form->options['submit_html'] ) || empty( $form->options['submit_html'] ) ) {
641 continue;
642 }
643
644 if ( $form->options['submit_html'] != $new_default_html && $form->options['submit_html'] == $old_default_html ) {
645 $form->options['submit_html'] = $new_default_html;
646 $wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) );
647 } elseif ( ! strpos( $form->options['submit_html'], 'save_draft' ) ) {
648 $form->options['submit_html'] = preg_replace( '~\<\/div\>(?!.*\<\/div\>)~', $draft_link . "\r\n</div>", $form->options['submit_html'] );
649 $wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) );
650 }
651 unset( $form );
652 }
653 }
654 }
655