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

877 lines 23.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
8 /**
9 * @var string
10 */
11 public $fields;
12
13 /**
14 * @var string
15 */
16 public $forms;
17
18 /**
19 * @var string
20 */
21 public $entries;
22
23 /**
24 * @var string
25 */
26 public $entry_metas;
27
28 public function __construct() {
29 global $wpdb;
30 $this->fields = $wpdb->prefix . 'frm_fields';
31 $this->forms = $wpdb->prefix . 'frm_forms';
32 $this->entries = $wpdb->prefix . 'frm_items';
33 $this->entry_metas = $wpdb->prefix . 'frm_item_metas';
34 }
35
36 /**
37 * @return void
38 */
39 public function upgrade() {
40 do_action( 'frm_before_install' );
41
42 global $wpdb, $frm_vars;
43
44 $frm_vars['doing_upgrade'] = true;
45
46 $needs_upgrade = FrmAppController::compare_for_update(
47 array(
48 'option' => 'frm_db_version',
49 'new_db_version' => FrmAppHelper::$db_version,
50 'new_plugin_version' => FrmAppHelper::plugin_version(),
51 )
52 );
53
54 if ( $needs_upgrade ) {
55 $this->maybe_delete_htaccess_file();
56
57 // Update rewrite rules for views and other custom post types
58 flush_rewrite_rules();
59
60 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
61
62 $old_db_version = get_option( 'frm_db_version' );
63
64 $this->create_tables();
65 $this->migrate_data( $old_db_version );
66 $this->check_that_tables_exist();
67
68 // SAVE DB VERSION.
69 update_option( 'frm_db_version', FrmAppHelper::plugin_version() . '-' . FrmAppHelper::$db_version );
70
71 if ( ! $old_db_version ) {
72 $this->maybe_create_contact_form();
73
74 if ( false === get_option( 'frm_first_activation' ) ) {
75 update_option( 'frm_first_activation', time(), false );
76 }
77
78 $this->update_settings_for_new_install();
79 }
80 }//end if
81
82 do_action( 'frm_after_install' );
83
84 $frm_vars['doing_upgrade'] = false;
85
86 FrmAppHelper::save_combined_js();
87
88 // Update the styling settings
89 if ( ! function_exists( 'get_filesystem_method' ) ) {
90 return;
91 }
92
93 $frm_style = new FrmStyle();
94 $frm_style->update( 'default' );
95 }
96
97 /**
98 * Check if the .htaccess file should be deleted based on server response.
99 * If a server has AllowOverride FileInfo but not AllowOverride AuthConfig, JS and CSS files
100 * will result in a 500 error.
101 *
102 * @since 6.27
103 *
104 * @return void
105 */
106 private function maybe_delete_htaccess_file() {
107 $css_file_request = wp_remote_get( FrmAppHelper::plugin_url() . '/css/frm_fonts.css' );
108
109 if ( 200 === wp_remote_retrieve_response_code( $css_file_request ) ) {
110 return;
111 }
112
113 $htaccess_path = FrmAppHelper::plugin_path() . '/.htaccess';
114
115 if ( file_exists( $htaccess_path ) ) {
116 wp_delete_file( $htaccess_path );
117 }
118 }
119
120 /**
121 * Updates some settings for new installs.
122 *
123 * @since 6.23
124 *
125 * @return void
126 */
127 private function update_settings_for_new_install() {
128 $settings = FrmAppHelper::get_settings();
129
130 $settings->denylist_check = 1;
131 $settings->installed_after_welcome_tour_update = 1;
132 $settings->store();
133 }
134
135 /**
136 * If we fail to create the database tables, add an inbox notice.
137 * This informs the user that they need to correct the issue and try again.
138 *
139 * @since 6.19
140 *
141 * @return void
142 */
143 private function check_that_tables_exist() {
144 // Check the DB that the table $this->forms exists.
145 global $wpdb;
146 $exists = $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $this->forms ) );
147
148 if ( $exists ) {
149 $inbox = new FrmInbox();
150 $inbox->dismiss( 'failed-to-create-tables' );
151 return;
152 }
153
154 $message = array(
155 'key' => 'failed-to-create-tables',
156 'subject' => 'Something went wrong setting up the database',
157 '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
158 'cta' => '<a href="https://formidableforms.com/knowledgebase/install-formidable-forms/#kb-missing-database-tables">Learn More</a>',
159 'type' => 'error',
160 );
161
162 $inbox = new FrmInbox();
163 $inbox->add_message( $message );
164 }
165
166 /**
167 * @return string
168 */
169 public function collation() {
170 global $wpdb;
171 return $wpdb->has_cap( 'collation' ) ? $wpdb->get_charset_collate() : '';
172 }
173
174 /**
175 * @return void
176 */
177 private function create_tables() {
178 $charset_collate = $this->collation();
179 $sql = array();
180
181 /* Create/Upgrade Fields Table */
182 $sql[] = 'CREATE TABLE ' . $this->fields . ' (
183 id BIGINT(20) NOT NULL auto_increment,
184 field_key varchar(100) default NULL,
185 name text default NULL,
186 description longtext default NULL,
187 type text default NULL,
188 default_value longtext default NULL,
189 options longtext default NULL,
190 field_order int(11) default 0,
191 required int(1) default NULL,
192 field_options longtext default NULL,
193 form_id int(11) default NULL,
194 created_at datetime NOT NULL,
195 PRIMARY KEY (id),
196 KEY form_id (form_id),
197 UNIQUE KEY field_key (field_key)
198 )';
199
200 /* Create/Upgrade Forms Table */
201 $sql[] = 'CREATE TABLE ' . $this->forms . ' (
202 id int(11) NOT NULL auto_increment,
203 form_key varchar(100) default NULL,
204 name varchar(255) default NULL,
205 description text default NULL,
206 parent_form_id int(11) default 0,
207 logged_in tinyint(1) default NULL,
208 editable tinyint(1) default NULL,
209 is_template tinyint(1) default 0,
210 default_template tinyint(1) default 0,
211 status varchar(255) default NULL,
212 options longtext default NULL,
213 created_at datetime NOT NULL,
214 PRIMARY KEY (id),
215 UNIQUE KEY form_key (form_key)
216 )';
217
218 /* Create/Upgrade Items Table */
219 $sql[] = 'CREATE TABLE ' . $this->entries . ' (
220 id BIGINT(20) NOT NULL auto_increment,
221 item_key varchar(100) default NULL,
222 name varchar(255) default NULL,
223 description text default NULL,
224 ip text default NULL,
225 form_id BIGINT(20) default NULL,
226 post_id BIGINT(20) default NULL,
227 user_id BIGINT(20) default NULL,
228 parent_item_id BIGINT(20) default 0,
229 is_draft tinyint(1) default 0,
230 updated_by BIGINT(20) default NULL,
231 created_at datetime NOT NULL,
232 updated_at datetime NOT NULL,
233 PRIMARY KEY (id),
234 KEY form_id (form_id),
235 KEY post_id (post_id),
236 KEY user_id (user_id),
237 KEY parent_item_id (parent_item_id),
238 UNIQUE KEY item_key (item_key)
239 )';
240
241 /* Create/Upgrade Meta Table */
242 $sql[] = 'CREATE TABLE ' . $this->entry_metas . ' (
243 id BIGINT(20) NOT NULL auto_increment,
244 meta_value longtext default NULL,
245 field_id BIGINT(20) NOT NULL,
246 item_id BIGINT(20) NOT NULL,
247 created_at datetime NOT NULL,
248 PRIMARY KEY (id),
249 KEY field_id (field_id),
250 KEY item_id (item_id)
251 )';
252
253 foreach ( $sql as $q ) {
254 if ( function_exists( 'dbDelta' ) ) {
255 dbDelta( $q . $charset_collate . ';' );
256 } else {
257 global $wpdb;
258 $wpdb->query( $q . $charset_collate ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
259 }
260 unset( $q );
261 }
262
263 $this->add_composite_indexes_for_entries();
264 }
265
266 /**
267 * These indexes help optimize database queries for entries.
268 *
269 * @since 6.6
270 * @since 6.16.3 idx_form_id_is_draft was also added to frm_items.
271 * @since 6.17 idx_form_id_type was also added to frm_fields.
272 *
273 * @return void
274 */
275 private function add_composite_indexes_for_entries() {
276 global $wpdb;
277
278 $table_name = "{$wpdb->prefix}frm_items";
279 $index_name = 'idx_is_draft_created_at';
280
281 if ( ! self::index_exists( $table_name, $index_name ) ) {
282 $wpdb->query( "CREATE INDEX idx_is_draft_created_at ON `{$wpdb->prefix}frm_items` (is_draft, created_at)" );
283 }
284
285 $table_name = "{$wpdb->prefix}frm_item_metas";
286 $index_name = 'idx_field_id_item_id';
287
288 if ( ! self::index_exists( $table_name, $index_name ) ) {
289 $wpdb->query( "CREATE INDEX idx_field_id_item_id ON `{$wpdb->prefix}frm_item_metas` (field_id, item_id)" );
290 }
291
292 $table_name = "{$wpdb->prefix}frm_items";
293 $index_name = 'idx_form_id_is_draft';
294
295 if ( ! self::index_exists( $table_name, $index_name ) ) {
296 $wpdb->query( "CREATE INDEX idx_form_id_is_draft ON `{$wpdb->prefix}frm_items` (form_id, is_draft)" );
297 }
298
299 $table_name = "{$wpdb->prefix}frm_fields";
300 $index_name = 'idx_form_id_type';
301
302 if ( ! self::index_exists( $table_name, $index_name ) ) {
303 $wpdb->query( "CREATE INDEX idx_form_id_type ON `{$wpdb->prefix}frm_fields` (form_id, type(30))" );
304 }
305 }
306
307 /**
308 * Check that an index exists in a database table before trying to add it (which results in an error).
309 *
310 * @since 6.6
311 *
312 * @param string $table_name
313 * @param string $index_name
314 *
315 * @return bool
316 */
317 private static function index_exists( $table_name, $index_name ) {
318 global $wpdb;
319 $row = $wpdb->get_row(
320 $wpdb->prepare(
321 'SELECT 1 FROM information_schema.statistics
322 WHERE table_schema = database()
323 AND table_name = %s
324 AND index_name = %s
325 LIMIT 1',
326 array( $table_name, $index_name )
327 )
328 );
329 return (bool) $row;
330 }
331
332 /**
333 * @return void
334 */
335 private function maybe_create_contact_form() {
336 $form_exists = FrmForm::get_id_by_key( 'contact-form' );
337
338 if ( ! $form_exists ) {
339 $this->add_default_template();
340 }
341 }
342
343 /**
344 * Create the default contact form
345 *
346 * @since 3.06
347 *
348 * @return void
349 */
350 private function add_default_template() {
351 if ( FrmXMLHelper::check_if_libxml_disable_entity_loader_exists() ) {
352 // XML import is not enabled on your server.
353 return;
354 }
355
356 $set_err = libxml_use_internal_errors( true );
357 $loader = FrmXMLHelper::maybe_libxml_disable_entity_loader( true );
358 $file = FrmAppHelper::plugin_path() . '/classes/views/xml/default-templates.xml';
359 FrmXMLHelper::import_xml( $file );
360
361 libxml_use_internal_errors( $set_err );
362 FrmXMLHelper::maybe_libxml_disable_entity_loader( $loader );
363 }
364
365 /**
366 * @param int|string $old_db_version
367 *
368 * @return void
369 */
370 private function migrate_data( $old_db_version ) {
371 if ( ! $old_db_version ) {
372 $old_db_version = get_option( 'frm_db_version' );
373 }
374
375 if ( str_contains( $old_db_version, '-' ) ) {
376 $last_upgrade = explode( '-', $old_db_version );
377 $old_db_version = (int) $last_upgrade[1];
378 }
379
380 if ( ! is_numeric( $old_db_version ) ) {
381 // Bail if we don't know the previous version
382 return;
383 }
384
385 $migrations = array( 16, 11, 16, 17, 23, 25, 86, 90, 97, 98, 101, 104 );
386
387 foreach ( $migrations as $migration ) {
388 if ( FrmAppHelper::$db_version >= $migration && $old_db_version < $migration ) {
389 $function_name = 'migrate_to_' . $migration;
390 $this->$function_name();
391 }
392 }
393 }
394
395 /**
396 * @return bool
397 */
398 public function uninstall() {
399 if ( ! current_user_can( 'administrator' ) ) {
400 $frm_settings = FrmAppHelper::get_settings();
401 wp_die( esc_html( $frm_settings->admin_permission ) );
402 }
403
404 global $wpdb, $wp_roles;
405
406 $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->fields ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
407 $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->forms ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
408 $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->entries ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
409 $wpdb->query( 'DROP TABLE IF EXISTS ' . $this->entry_metas ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
410
411 delete_option( 'frm_options' );
412 delete_option( 'frm_db_version' );
413 delete_option( 'frm_install_running' );
414 delete_option( 'frm_lite_settings_upgrade' );
415 delete_option( 'frm-usage-uuid' );
416 delete_option( 'frm_inbox' );
417 delete_option( 'frmpro_css' );
418 delete_option( FrmOnboardingWizardController::REDIRECT_STATUS_OPTION );
419 delete_option( FrmEmailSummaryHelper::$option_name );
420
421 // Delete roles.
422 $frm_roles = FrmAppHelper::frm_capabilities();
423 $roles = get_editable_roles();
424
425 foreach ( $frm_roles as $frm_role => $frm_role_description ) {
426 foreach ( $roles as $role => $details ) {
427 $wp_roles->remove_cap( $role, $frm_role );
428 unset( $role, $details );
429 }
430 unset( $frm_role, $frm_role_description );
431 }
432 unset( $roles, $frm_roles );
433
434 // Delete actions, views, and styles
435
436 // Prevent the post deletion from triggering entries to be deleted
437 remove_action( 'before_delete_post', 'FrmProDisplaysController::before_delete_post' );
438 remove_action( 'deleted_post', 'FrmProEntriesController::delete_entry' );
439
440 $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
441
442 foreach ( $post_ids as $post_id ) {
443 // Delete's each post.
444 wp_delete_post( $post_id, true );
445 }
446 unset( $post_ids );
447
448 // Delete transients
449 delete_transient( 'frmpro_css' );
450 delete_transient( 'frm_options' );
451 delete_transient( 'frmpro_options' );
452 delete_transient( FrmOnboardingWizardController::TRANSIENT_NAME );
453
454 $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
455
456 do_action( 'frm_after_uninstall' );
457
458 return true;
459 }
460
461 /**
462 * In older versions of Lite, it's possible we've saved the wrong location ID.
463 * So force it to get valid values again.
464 *
465 * @since 6.25
466 *
467 * @return void
468 */
469 private function migrate_to_104() {
470 if ( FrmSquareLiteConnectHelper::get_merchant_id( 'test' ) ) {
471 FrmSquareLiteConnectHelper::get_location_id( true, 'test' );
472 }
473
474 if ( FrmSquareLiteConnectHelper::get_merchant_id( 'live' ) ) {
475 FrmSquareLiteConnectHelper::get_location_id( true, 'live' );
476 }
477 }
478
479 /**
480 * Disables summary email for multisite (not the main site) if recipient setting isn't changed.
481 *
482 * @since 6.8
483 *
484 * @return void
485 */
486 private function migrate_to_101() {
487 if ( ! is_multisite() || get_main_site_id() === get_current_blog_id() ) {
488 return;
489 }
490
491 $frm_settings = FrmAppHelper::get_settings();
492
493 if ( empty( $frm_settings->summary_emails ) || '[admin_email]' !== $frm_settings->summary_emails_recipients ) {
494 // User changed it.
495 return;
496 }
497
498 $frm_settings->summary_emails = 0;
499 $frm_settings->store();
500 }
501
502 /**
503 * Clear frmpro_css transient.
504 *
505 * @since 4.10.02
506 *
507 * @return void
508 */
509 private function migrate_to_98() {
510 delete_transient( 'frmpro_css' );
511 }
512
513 /**
514 * Move default_blank and clear_on_focus to placeholder.
515 *
516 * @since 4.0
517 *
518 * @return void
519 */
520 private function migrate_to_97() {
521 $this->migrate_to_placeholder( 'clear_on_focus' );
522 $this->migrate_to_placeholder( 'default_blank' );
523 }
524
525 /**
526 * Move clear_on_focus or default_blank to placeholder.
527 *
528 * @since 4.0
529 *
530 * @param string $type Field option key to migrate.
531 *
532 * @return void
533 */
534 private function migrate_to_placeholder( $type = 'clear_on_focus' ) {
535 $query = array(
536 'field_options like' => '"' . $type . '";s:1:"1";',
537 );
538
539 $fields = FrmDb::get_results( $this->fields, $query, 'id, default_value, field_options, options' );
540
541 foreach ( $fields as $field ) {
542 FrmAppHelper::unserialize_or_decode( $field->field_options );
543 FrmAppHelper::unserialize_or_decode( $field->options );
544 $update_values = FrmXMLHelper::migrate_field_placeholder( $field, $type );
545
546 if ( ! $update_values ) {
547 continue;
548 }
549
550 FrmField::update( $field->id, $update_values );
551 unset( $field );
552 }
553 }
554
555 /**
556 * Delete unneeded default templates
557 *
558 * @since 3.06
559 *
560 * @return void
561 */
562 private function migrate_to_90() {
563 $form = FrmForm::getOne( 'contact' );
564
565 // phpcs:ignore Universal.Operators.StrictComparisons
566 if ( $form && $form->default_template == 1 ) {
567 FrmForm::destroy( 'contact' );
568 }
569 }
570
571 /**
572 * Reverse migration 17 -- Divide by 9
573 *
574 * @since 3.0.05
575 *
576 * @return void
577 */
578 private function migrate_to_86() {
579 $fields = $this->get_fields_with_size();
580
581 foreach ( $fields as $f ) {
582 FrmAppHelper::unserialize_or_decode( $f->field_options );
583 $size = $f->field_options['size'];
584 $this->maybe_convert_migrated_size( $size );
585
586 if ( $size === $f->field_options['size'] ) {
587 continue;
588 }
589
590 $f->field_options['size'] = $size;
591 FrmField::update( $f->id, array( 'field_options' => $f->field_options ) );
592 unset( $f );
593 }
594
595 // Reverse the extra size changes in widgets
596 $widgets = get_option( 'widget_frm_show_form' );
597
598 if ( ! $widgets ) {
599 return;
600 }
601
602 $this->revert_widget_field_size();
603 }
604
605 /**
606 * @return array
607 */
608 private function get_fields_with_size() {
609 $field_types = array(
610 'textarea',
611 'text',
612 'number',
613 'email',
614 'url',
615 'rte',
616 'date',
617 'phone',
618 'password',
619 'image',
620 'tag',
621 'file',
622 );
623
624 $query = array(
625 'type' => $field_types,
626 'field_options like' => 's:4:"size";',
627 'field_options not like' => 's:4:"size";s:0:',
628 );
629
630 return FrmDb::get_results( $this->fields, $query, 'id, field_options' );
631 }
632
633 /**
634 * Reverse the extra size changes in widgets
635 *
636 * @since 3.0.05
637 *
638 * @return void
639 */
640 private function revert_widget_field_size() {
641 $widgets = get_option( 'widget_frm_show_form' );
642
643 if ( ! $widgets ) {
644 return;
645 }
646
647 FrmAppHelper::unserialize_or_decode( $widgets );
648
649 foreach ( $widgets as $k => $widget ) {
650 if ( ! is_array( $widget ) || ! isset( $widget['size'] ) ) {
651 continue;
652 }
653
654 $this->maybe_convert_migrated_size( $widgets[ $k ]['size'] );
655 }
656
657 update_option( 'widget_frm_show_form', $widgets );
658 }
659
660 /**
661 * Divide by 9 to reverse the multiplication
662 *
663 * @since 3.0.05
664 *
665 * @param string $size Size string to maybe convert, passed by reference.
666 *
667 * @return void
668 */
669 private function maybe_convert_migrated_size( &$size ) {
670 $has_px_size = $size && str_contains( $size, 'px' );
671
672 if ( ! $has_px_size ) {
673 return;
674 }
675
676 $int_size = str_replace( 'px', '', $size );
677
678 if ( ! is_numeric( $int_size ) || (int) $int_size < 900 ) {
679 return;
680 }
681
682 $pixel_conversion = 9;
683 $size = round( (int) $int_size / $pixel_conversion );
684 }
685
686 /**
687 * Migrate old styling settings. If sites are using the old
688 * default 400px field width, switch it to 100%
689 *
690 * @since 2.0.4
691 *
692 * @return void
693 */
694 private function migrate_to_25() {
695 // Get the style that was created with the style migration
696 $frm_style = new FrmStyle();
697 $styles = $frm_style->get_all( 'post_date', 'ASC', 1 );
698
699 if ( ! $styles ) {
700 return;
701 }
702
703 foreach ( $styles as $style ) {
704 if ( $style->post_content['field_width'] === '400px' ) {
705 $style->post_content['field_width'] = '100%';
706 $frm_style->save( (array) $style );
707
708 return;
709 }
710 }
711 }
712
713 /**
714 * Check if the parent_form_id columns exists.
715 * If not, try and add it again
716 *
717 * @since 2.0.2
718 *
719 * @return void
720 */
721 private function migrate_to_23() {
722 global $wpdb;
723 $exists = $wpdb->get_row( 'SHOW COLUMNS FROM ' . $this->forms . ' LIKE "parent_form_id"' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
724
725 if ( ! $exists ) {
726 $wpdb->query( 'ALTER TABLE ' . $this->forms . ' ADD parent_form_id int(11) default 0' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
727 }
728 }
729
730 /**
731 * Change field size from character to pixel -- Multiply by 9
732 *
733 * @return void
734 */
735 private function migrate_to_17() {
736 $fields = $this->get_fields_with_size();
737
738 foreach ( $fields as $f ) {
739 FrmAppHelper::unserialize_or_decode( $f->field_options );
740
741 if ( empty( $f->field_options['size'] ) || ! is_numeric( $f->field_options['size'] ) ) {
742 continue;
743 }
744
745 $this->convert_character_to_px( $f->field_options['size'] );
746
747 FrmField::update( $f->id, array( 'field_options' => $f->field_options ) );
748 unset( $f );
749 }
750
751 $this->adjust_widget_size();
752 }
753
754 /**
755 * Change the characters in widgets to pixels
756 *
757 * @return void
758 */
759 private function adjust_widget_size() {
760 $widgets = get_option( 'widget_frm_show_form' );
761
762 if ( ! $widgets ) {
763 return;
764 }
765
766 FrmAppHelper::unserialize_or_decode( $widgets );
767
768 foreach ( $widgets as $k => $widget ) {
769 if ( ! is_array( $widget ) || ! isset( $widget['size'] ) ) {
770 continue;
771 }
772 $this->convert_character_to_px( $widgets[ $k ]['size'] );
773 }
774
775 update_option( 'widget_frm_show_form', $widgets );
776 }
777
778 /**
779 * @param string $size
780 *
781 * @return void
782 */
783 private function convert_character_to_px( &$size ) {
784 $pixel_conversion = 9;
785
786 $size = round( $pixel_conversion * (int) $size );
787 $size .= 'px';
788 }
789
790 /**
791 * Migrate post and email notification settings into actions
792 */
793 private function migrate_to_16() {
794 $forms = FrmDb::get_results( $this->forms, array(), 'id, options, is_template, default_template' );
795
796 /**
797 * Old email settings format:
798 * email_to: Email or field id
799 * also_email_to: array of fields ids
800 * reply_to: Email, field id, 'custom'
801 * cust_reply_to: string
802 * reply_to_name: field id, 'custom'
803 * cust_reply_to_name: string
804 * plain_text: 0|1
805 * email_message: string or ''
806 * email_subject: string or ''
807 * inc_user_info: 0|1
808 * update_email: 0, 1, 2
809 *
810 * Old autoresponder settings format:
811 * auto_responder: 0|1
812 * ar_email_message: string or ''
813 * ar_email_to: field id
814 * ar_plain_text: 0|1
815 * ar_reply_to_name: string
816 * ar_reply_to: string
817 * ar_email_subject: string
818 * ar_update_email: 0, 1, 2
819 *
820 * New email settings:
821 * post_content: json settings
822 * post_title: form id
823 * post_excerpt: message
824 */
825 foreach ( $forms as $form ) {
826 if ( $form->is_template && $form->default_template ) {
827 // Don't migrate the default templates since the email will be added anyway
828 continue;
829 }
830
831 // Format form options
832 $form_options = $form->options;
833 FrmAppHelper::unserialize_or_decode( $form_options );
834
835 // Migrate settings to actions
836 FrmXMLHelper::migrate_form_settings_to_actions( $form_options, $form->id );
837 }
838 }
839
840 private function migrate_to_11() {
841 global $wpdb;
842
843 $forms = FrmDb::get_results( $this->forms, array(), 'id, options' );
844 $sending = __( 'Sending', 'formidable' );
845 $img = FrmAppHelper::plugin_url() . '/images/ajax_loader.gif';
846 $old_default_html = <<<DEFAULT_HTML
847 <div class="frm_submit">
848 [if back_button]<input type="submit" value="[back_label]" name="frm_prev_page" formnovalidate="formnovalidate" [back_hook] />[/if back_button]
849 <input type="submit" value="[button_label]" [button_action] />
850 <img class="frm_ajax_loading" src="$img" alt="$sending" style="visibility:hidden;" />
851 </div>
852 DEFAULT_HTML;
853 unset( $sending, $img );
854
855 $new_default_html = FrmFormsHelper::get_default_html( 'submit' );
856 $draft_link = FrmFormsHelper::get_draft_link();
857
858 foreach ( $forms as $form ) {
859 FrmAppHelper::unserialize_or_decode( $form->options );
860
861 if ( empty( $form->options['submit_html'] ) ) {
862 continue;
863 }
864
865 // phpcs:ignore Universal.Operators.StrictComparisons
866 if ( $form->options['submit_html'] != $new_default_html && $form->options['submit_html'] == $old_default_html ) {
867 $form->options['submit_html'] = $new_default_html;
868 $wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) );
869 } elseif ( ! str_contains( $form->options['submit_html'], 'save_draft' ) ) {
870 $form->options['submit_html'] = preg_replace( '~\<\/div\>(?!.*\<\/div\>)~', $draft_link . "\r\n</div>", $form->options['submit_html'] );
871 $wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) );
872 }
873 unset( $form );
874 }
875 }
876 }
877