PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 4.05.02
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v4.05.02
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 / helpers / FrmXMLHelper.php

FrmXMLHelper.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 4.05.02, at classes/helpers/FrmXMLHelper.php

1,604 lines 48.1 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 FrmXMLHelper {
7
8 public static function get_xml_values( $opt, $padding ) {
9 if ( is_array( $opt ) ) {
10 foreach ( $opt as $ok => $ov ) {
11 echo "\n" . esc_html( $padding );
12 $tag = ( is_numeric( $ok ) ? 'key:' : '' ) . $ok;
13 echo '<' . esc_html( $tag ) . '>';
14 self::get_xml_values( $ov, $padding . ' ' );
15 if ( is_array( $ov ) ) {
16 echo "\n" . esc_html( $padding );
17 }
18 echo '</' . esc_html( $tag ) . '>';
19 }
20 } else {
21 echo self::cdata( $opt ); // WPCS: XSS ok.
22 }
23 }
24
25 public static function import_xml( $file ) {
26 if ( ! defined( 'WP_IMPORTING' ) ) {
27 define( 'WP_IMPORTING', true );
28 }
29
30 if ( ! class_exists( 'DOMDocument' ) ) {
31 return new WP_Error( 'SimpleXML_parse_error', __( 'Your server does not have XML enabled', 'formidable' ), libxml_get_errors() );
32 }
33
34 $dom = new DOMDocument();
35 $success = $dom->loadXML( file_get_contents( $file ) );
36 if ( ! $success ) {
37 return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this XML file', 'formidable' ), libxml_get_errors() );
38 }
39
40 if ( ! function_exists( 'simplexml_import_dom' ) ) {
41 return new WP_Error( 'SimpleXML_parse_error', __( 'Your server is missing the simplexml_import_dom function', 'formidable' ), libxml_get_errors() );
42 }
43
44 $xml = simplexml_import_dom( $dom );
45 unset( $dom );
46
47 // halt if loading produces an error
48 if ( ! $xml ) {
49 return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this XML file', 'formidable' ), libxml_get_errors() );
50 }
51
52 return self::import_xml_now( $xml );
53 }
54
55 /**
56 * Add terms, forms (form and field ids), posts (post ids), and entries to db, in that order
57 *
58 * @since 3.06
59 * @return array The number of items imported
60 */
61 public static function import_xml_now( $xml ) {
62 $imported = self::pre_import_data();
63
64 foreach ( array( 'term', 'form', 'view' ) as $item_type ) {
65 // Grab cats, tags, and terms, or forms or posts.
66 if ( isset( $xml->{$item_type} ) ) {
67 $function_name = 'import_xml_' . $item_type . 's';
68 $imported = self::$function_name( $xml->{$item_type}, $imported );
69 unset( $function_name, $xml->{$item_type} );
70 }
71 }
72
73 return apply_filters( 'frm_importing_xml', $imported, $xml );
74 }
75
76 /**
77 * @since 3.06
78 * @return array
79 */
80 private static function pre_import_data() {
81 $defaults = array(
82 'forms' => 0,
83 'fields' => 0,
84 'terms' => 0,
85 'posts' => 0,
86 'views' => 0,
87 'actions' => 0,
88 'styles' => 0,
89 );
90
91 return array(
92 'imported' => $defaults,
93 'updated' => $defaults,
94 'forms' => array(),
95 'terms' => array(),
96 );
97 }
98
99 public static function import_xml_terms( $terms, $imported ) {
100 foreach ( $terms as $t ) {
101 if ( term_exists( (string) $t->term_slug, (string) $t->term_taxonomy ) ) {
102 continue;
103 }
104
105 $parent = self::get_term_parent_id( $t );
106
107 $term = wp_insert_term(
108 (string) $t->term_name,
109 (string) $t->term_taxonomy,
110 array(
111 'slug' => (string) $t->term_slug,
112 'description' => (string) $t->term_description,
113 'parent' => empty( $parent ) ? 0 : $parent,
114 )
115 );
116
117 if ( $term && is_array( $term ) ) {
118 $imported['imported']['terms'] ++;
119 $imported['terms'][ (int) $t->term_id ] = $term['term_id'];
120 }
121
122 unset( $term, $t );
123 }
124
125 return $imported;
126 }
127
128 /**
129 * @since 2.0.8
130 */
131 private static function get_term_parent_id( $t ) {
132 $parent = (string) $t->term_parent;
133 if ( ! empty( $parent ) ) {
134 $parent = term_exists( (string) $t->term_parent, (string) $t->term_taxonomy );
135 if ( $parent ) {
136 $parent = $parent['term_id'];
137 } else {
138 $parent = 0;
139 }
140 }
141
142 return $parent;
143 }
144
145 public static function import_xml_forms( $forms, $imported ) {
146 $child_forms = array();
147
148 // Import child forms first
149 self::put_child_forms_first( $forms );
150
151 foreach ( $forms as $item ) {
152 $form = self::fill_form( $item );
153
154 self::update_custom_style_setting_on_import( $form );
155
156 $this_form = self::maybe_get_form( $form );
157
158 $old_id = false;
159 $form_fields = false;
160 if ( ! empty( $this_form ) ) {
161 $form_id = $this_form->id;
162 $old_id = $this_form->id;
163 self::update_form( $this_form, $form, $imported );
164
165 $form_fields = self::get_form_fields( $form_id );
166 } else {
167 $form_id = FrmForm::create( $form );
168 if ( $form_id ) {
169 if ( empty( $form['parent_form_id'] ) ) {
170 // Don't include the repeater form in the imported count.
171 $imported['imported']['forms'] ++;
172 }
173
174 // Keep track of whether this specific form was updated or not.
175 $imported['form_status'][ $form_id ] = 'imported';
176 self::track_imported_child_forms( (int) $form_id, $form['parent_form_id'], $child_forms );
177 }
178 }
179
180 self::import_xml_fields( $item->field, $form_id, $this_form, $form_fields, $imported );
181
182 self::delete_removed_fields( $form_fields );
183
184 // Update field ids/keys to new ones.
185 do_action( 'frm_after_duplicate_form', $form_id, $form, array( 'old_id' => $old_id ) );
186
187 $imported['forms'][ (int) $item->id ] = $form_id;
188
189 // Send pre 2.0 form options through function that creates actions.
190 self::migrate_form_settings_to_actions( $form['options'], $form_id, $imported, true );
191
192 do_action( 'frm_after_import_form', $form_id, $form );
193
194 unset( $form, $item );
195 }
196
197 self::maybe_update_child_form_parent_id( $imported['forms'], $child_forms );
198
199 return $imported;
200 }
201
202 private static function fill_form( $item ) {
203 $form = array(
204 'id' => (int) $item->id,
205 'form_key' => (string) $item->form_key,
206 'name' => (string) $item->name,
207 'description' => (string) $item->description,
208 'options' => (string) $item->options,
209 'logged_in' => (int) $item->logged_in,
210 'is_template' => (int) $item->is_template,
211 'editable' => (int) $item->editable,
212 'status' => (string) $item->status,
213 'parent_form_id' => isset( $item->parent_form_id ) ? (int) $item->parent_form_id : 0,
214 'created_at' => gmdate( 'Y-m-d H:i:s', strtotime( (string) $item->created_at ) ),
215 );
216
217 if ( empty( $item->created_at ) ) {
218 $form['created_at'] = current_time( 'mysql', 1 );
219 }
220
221 $form['options'] = FrmAppHelper::maybe_json_decode( $form['options'] );
222
223 return $form;
224 }
225
226 private static function maybe_get_form( $form ) {
227 // if template, allow to edit if form keys match, otherwise, creation date must also match
228 $edit_query = array(
229 'form_key' => $form['form_key'],
230 'is_template' => $form['is_template'],
231 );
232 if ( ! $form['is_template'] ) {
233 $edit_query['created_at'] = $form['created_at'];
234 }
235
236 $edit_query = apply_filters( 'frm_match_xml_form', $edit_query, $form );
237
238 return FrmForm::getAll( $edit_query, '', 1 );
239 }
240
241 private static function update_form( $this_form, $form, &$imported ) {
242 $form_id = $this_form->id;
243 FrmForm::update( $form_id, $form );
244 if ( empty( $form['parent_form_id'] ) ) {
245 // Don't include the repeater form in the updated count.
246 $imported['updated']['forms'] ++;
247 }
248
249 // Keep track of whether this specific form was updated or not
250 $imported['form_status'][ $form_id ] = 'updated';
251 }
252
253 private static function get_form_fields( $form_id ) {
254 $form_fields = FrmField::get_all_for_form( $form_id, '', 'exclude', 'exclude' );
255 $old_fields = array();
256 foreach ( $form_fields as $f ) {
257 $old_fields[ $f->id ] = $f;
258 $old_fields[ $f->field_key ] = $f->id;
259 unset( $f );
260 }
261 $form_fields = $old_fields;
262
263 return $form_fields;
264 }
265
266 /**
267 * Delete any fields attached to this form that were not included in the template
268 */
269 private static function delete_removed_fields( $form_fields ) {
270 if ( ! empty( $form_fields ) ) {
271 foreach ( $form_fields as $field ) {
272 if ( is_object( $field ) ) {
273 FrmField::destroy( $field->id );
274 }
275 unset( $field );
276 }
277 }
278 }
279
280 /**
281 * Put child forms first so they will be imported before parents
282 *
283 * @since 2.0.16
284 *
285 * @param array $forms
286 */
287 private static function put_child_forms_first( &$forms ) {
288 $child_forms = array();
289 $regular_forms = array();
290
291 foreach ( $forms as $form ) {
292 $parent_form_id = isset( $form->parent_form_id ) ? (int) $form->parent_form_id : 0;
293
294 if ( $parent_form_id ) {
295 $child_forms[] = $form;
296 } else {
297 $regular_forms[] = $form;
298 }
299 }
300
301 $forms = array_merge( $child_forms, $regular_forms );
302 }
303
304 /**
305 * Keep track of all imported child forms
306 *
307 * @since 2.0.16
308 *
309 * @param int $form_id
310 * @param int $parent_form_id
311 * @param array $child_forms
312 */
313 private static function track_imported_child_forms( $form_id, $parent_form_id, &$child_forms ) {
314 if ( $parent_form_id ) {
315 $child_forms[ $form_id ] = $parent_form_id;
316 }
317 }
318
319 /**
320 * Update the parent_form_id on imported child forms
321 * Child forms are imported first so their parent_form_id will need to be updated after the parent is imported
322 *
323 * @since 2.0.6
324 *
325 * @param array $imported_forms
326 * @param array $child_forms
327 */
328 private static function maybe_update_child_form_parent_id( $imported_forms, $child_forms ) {
329 foreach ( $child_forms as $child_form_id => $old_parent_form_id ) {
330
331 if ( isset( $imported_forms[ $old_parent_form_id ] ) && $imported_forms[ $old_parent_form_id ] != $old_parent_form_id ) {
332 // Update all children with this old parent_form_id
333 $new_parent_form_id = (int) $imported_forms[ $old_parent_form_id ];
334
335 FrmForm::update( $child_form_id, array( 'parent_form_id' => $new_parent_form_id ) );
336 }
337 }
338 }
339
340 /**
341 * Import all fields for a form
342 *
343 * @since 2.0.13
344 *
345 * TODO: Cut down on params
346 */
347 private static function import_xml_fields( $xml_fields, $form_id, $this_form, &$form_fields, &$imported ) {
348 $in_section = 0;
349
350 foreach ( $xml_fields as $field ) {
351 $f = self::fill_field( $field, $form_id );
352
353 $has_default = array(
354 'text',
355 'email',
356 'url',
357 'textarea',
358 'number',
359 'phone',
360 'date',
361 'hidden',
362 'password',
363 'tag',
364 );
365 if ( is_array( $f['default_value'] ) && in_array( $f['type'], $has_default, true ) ) {
366 if ( count( $f['default_value'] ) === 1 ) {
367 $f['default_value'] = '[' . reset( $f['default_value'] ) . ']';
368 } else {
369 $f['default_value'] = reset( $f['default_value'] );
370 }
371 }
372
373 self::maybe_add_required( $f );
374 self::maybe_update_in_section_variable( $in_section, $f );
375 self::maybe_update_form_select( $f, $imported );
376 self::maybe_update_get_values_form_setting( $imported, $f );
377 self::migrate_placeholders( $f );
378
379 if ( ! empty( $this_form ) ) {
380 // check for field to edit by field id
381 if ( isset( $form_fields[ $f['id'] ] ) ) {
382 FrmField::update( $f['id'], $f );
383 $imported['updated']['fields'] ++;
384
385 unset( $form_fields[ $f['id'] ] );
386
387 //unset old field key
388 if ( isset( $form_fields[ $f['field_key'] ] ) ) {
389 unset( $form_fields[ $f['field_key'] ] );
390 }
391 } elseif ( isset( $form_fields[ $f['field_key'] ] ) ) {
392 // check for field to edit by field key
393 unset( $f['id'] );
394
395 FrmField::update( $form_fields[ $f['field_key'] ], $f );
396 $imported['updated']['fields'] ++;
397
398 unset( $form_fields[ $form_fields[ $f['field_key'] ] ] ); //unset old field id
399 unset( $form_fields[ $f['field_key'] ] ); //unset old field key
400 } else {
401 // if no matching field id or key in this form, create the field
402 self::create_imported_field( $f, $imported );
403 }
404 } else {
405
406 self::create_imported_field( $f, $imported );
407 }
408 }
409 }
410
411 private static function fill_field( $field, $form_id ) {
412 return array(
413 'id' => (int) $field->id,
414 'field_key' => (string) $field->field_key,
415 'name' => (string) $field->name,
416 'description' => (string) $field->description,
417 'type' => (string) $field->type,
418 'default_value' => FrmAppHelper::maybe_json_decode( (string) $field->default_value ),
419 'field_order' => (int) $field->field_order,
420 'form_id' => (int) $form_id,
421 'required' => (int) $field->required,
422 'options' => FrmAppHelper::maybe_json_decode( (string) $field->options ),
423 'field_options' => FrmAppHelper::maybe_json_decode( (string) $field->field_options ),
424 );
425 }
426
427 /**
428 * Make sure the required indicator is set.
429 *
430 * @since 4.05
431 */
432 private static function maybe_add_required( &$f ) {
433 if ( $f['required'] && ! isset( $f['field_options']['required_indicator'] ) ) {
434 $f['field_options']['required_indicator'] = '*';
435 }
436 }
437
438 /**
439 * Update the current in_section value
440 *
441 * @since 2.0.25
442 *
443 * @param int $in_section
444 * @param array $f
445 */
446 private static function maybe_update_in_section_variable( &$in_section, &$f ) {
447 // If we're at the end of a section, switch $in_section is 0
448 if ( in_array( $f['type'], array( 'end_divider', 'break', 'form' ) ) ) {
449 $in_section = 0;
450 }
451
452 // Update the current field's in_section value
453 if ( ! isset( $f['field_options']['in_section'] ) ) {
454 $f['field_options']['in_section'] = $in_section;
455 }
456
457 // If we're starting a new section, switch $in_section to ID of divider
458 if ( $f['type'] == 'divider' ) {
459 $in_section = $f['id'];
460 }
461 }
462
463 /**
464 * Switch the form_select on a repeating field or embedded form if it needs to be switched
465 *
466 * @since 2.0.16
467 *
468 * @param array $f
469 * @param array $imported
470 */
471 private static function maybe_update_form_select( &$f, $imported ) {
472 if ( ! isset( $imported['forms'] ) ) {
473 return;
474 }
475
476 if ( $f['type'] == 'form' || ( $f['type'] == 'divider' && FrmField::is_option_true( $f['field_options'], 'repeat' ) ) ) {
477 if ( FrmField::is_option_true( $f['field_options'], 'form_select' ) ) {
478 $form_select = (int) $f['field_options']['form_select'];
479 if ( isset( $imported['forms'][ $form_select ] ) ) {
480 $f['field_options']['form_select'] = $imported['forms'][ $form_select ];
481 }
482 }
483 }
484 }
485
486 /**
487 * Update the get_values_form setting if the form was imported
488 *
489 * @since 2.01.0
490 *
491 * @param array $imported
492 * @param array $f
493 */
494 private static function maybe_update_get_values_form_setting( $imported, &$f ) {
495 if ( ! isset( $imported['forms'] ) ) {
496 return;
497 }
498
499 if ( FrmField::is_option_true_in_array( $f['field_options'], 'get_values_form' ) ) {
500 $old_form = $f['field_options']['get_values_form'];
501 if ( isset( $imported['forms'][ $old_form ] ) ) {
502 $f['field_options']['get_values_form'] = $imported['forms'][ $old_form ];
503 }
504 }
505 }
506
507 /**
508 * If field settings have been migrated, update the values during import.
509 *
510 * @since 4.0
511 */
512 private static function run_field_migrations( &$f ) {
513 self::migrate_placeholders( $f );
514 $f = apply_filters( 'frm_import_xml_field', $f );
515 }
516
517 /**
518 * @since 4.0
519 */
520 private static function migrate_placeholders( &$f ) {
521 $update_values = self::migrate_field_placeholder( $f, 'clear_on_focus' );
522 foreach ( $update_values as $k => $v ) {
523 $f[ $k ] = $v;
524 }
525
526 $update_values = self::migrate_field_placeholder( $f, 'default_blank' );
527 foreach ( $update_values as $k => $v ) {
528 $f[ $k ] = $v;
529 }
530 }
531
532 /**
533 * Move clear_on_focus or default_blank to placeholder.
534 * Also called during database migration in FrmMigrate.
535 *
536 * @since 4.0
537 * @return array
538 */
539 public static function migrate_field_placeholder( $field, $type ) {
540 $field = (array) $field;
541 $field_options = $field['field_options'];
542 if ( empty( $field_options[ $type ] ) || empty( $field['default_value'] ) ) {
543 return array();
544 }
545
546 $field_options['placeholder'] = is_array( $field['default_value'] ) ? reset( $field['default_value'] ) : $field['default_value'];
547 unset( $field_options['default_blank'], $field_options['clear_on_focus'] );
548
549 $changes = array(
550 'field_options' => $field_options,
551 'default_value' => '',
552 );
553
554 // If a dropdown placeholder was used, remove the option so it won't be included twice.
555 $options = $field['options'];
556 if ( $type === 'default_blank' && is_array( $options ) ) {
557 $default_value = $field['default_value'];
558 if ( is_array( $default_value ) ) {
559 $default_value = reset( $default_value );
560 }
561
562 foreach ( $options as $opt_key => $opt ) {
563 if ( is_array( $opt ) ) {
564 $opt = isset( $opt['value'] ) ? $opt['value'] : ( isset( $opt['label'] ) ? $opt['label'] : reset( $opt ) );
565 }
566
567 if ( $opt == $default_value ) {
568 unset( $options[ $opt_key ] );
569 break;
570 }
571 }
572 $changes['options'] = $options;
573 }
574
575 return $changes;
576 }
577
578 /**
579 * Create an imported field
580 *
581 * @since 2.0.25
582 *
583 * @param array $f
584 * @param array $imported
585 */
586 private static function create_imported_field( $f, &$imported ) {
587 $defaults = self::default_field_options( $f['type'] );
588 $f['field_options'] = array_merge( $defaults, $f['field_options'] );
589
590 $new_id = FrmField::create( $f );
591 if ( $new_id != false ) {
592 $imported['imported']['fields'] ++;
593 do_action( 'frm_after_field_is_imported', $f, $new_id );
594 }
595 }
596
597 /**
598 * Updates the custom style setting on import
599 * Convert the post slug to an ID
600 *
601 * @since 2.0.19
602 *
603 * @param array $form
604 */
605 private static function update_custom_style_setting_on_import( &$form ) {
606 if ( ! isset( $form['options']['custom_style'] ) ) {
607 return;
608 }
609
610 if ( is_numeric( $form['options']['custom_style'] ) ) {
611 // Set to default
612 $form['options']['custom_style'] = 1;
613 } else {
614 // Replace the style name with the style ID on import
615 global $wpdb;
616 $table = $wpdb->prefix . 'posts';
617 $where = array(
618 'post_name' => $form['options']['custom_style'],
619 'post_type' => 'frm_styles',
620 );
621 $select = 'ID';
622 $style_id = FrmDb::get_var( $table, $where, $select );
623
624 if ( $style_id ) {
625 $form['options']['custom_style'] = $style_id;
626 } else {
627 // save the old style to maybe update after styles import
628 $form['options']['old_style'] = $form['options']['custom_style'];
629
630 // Set to default
631 $form['options']['custom_style'] = 1;
632 }
633 }
634 }
635
636 /**
637 * After styles are imported, check for any forms that were linked
638 * and link them back up.
639 *
640 * @since 2.2.7
641 */
642 private static function update_custom_style_setting_after_import( $form_id ) {
643 $form = FrmForm::getOne( $form_id );
644
645 if ( $form && isset( $form->options['old_style'] ) ) {
646 $form = (array) $form;
647 $saved_style = $form['options']['custom_style'];
648 $form['options']['custom_style'] = $form['options']['old_style'];
649 self::update_custom_style_setting_on_import( $form );
650 $has_changed = ( $form['options']['custom_style'] != $saved_style && $form['options']['custom_style'] != $form['options']['old_style'] );
651 if ( $has_changed ) {
652 FrmForm::update( $form['id'], $form );
653 }
654 }
655 }
656
657 public static function import_xml_views( $views, $imported ) {
658 $imported['posts'] = array();
659 $form_action_type = FrmFormActionsController::$action_post_type;
660
661 $post_types = array(
662 'frm_display' => 'views',
663 $form_action_type => 'actions',
664 'frm_styles' => 'styles',
665 );
666
667 foreach ( $views as $item ) {
668 $post = array(
669 'post_title' => (string) $item->title,
670 'post_name' => (string) $item->post_name,
671 'post_type' => (string) $item->post_type,
672 'post_password' => (string) $item->post_password,
673 'guid' => (string) $item->guid,
674 'post_status' => (string) $item->status,
675 'post_author' => FrmAppHelper::get_user_id_param( (string) $item->post_author ),
676 'post_id' => (int) $item->post_id,
677 'post_parent' => (int) $item->post_parent,
678 'menu_order' => (int) $item->menu_order,
679 'post_content' => FrmFieldsHelper::switch_field_ids( (string) $item->content ),
680 'post_excerpt' => FrmFieldsHelper::switch_field_ids( (string) $item->excerpt ),
681 'is_sticky' => (string) $item->is_sticky,
682 'comment_status' => (string) $item->comment_status,
683 'post_date' => (string) $item->post_date,
684 'post_date_gmt' => (string) $item->post_date_gmt,
685 'ping_status' => (string) $item->ping_status,
686 'postmeta' => array(),
687 'tax_input' => array(),
688 );
689
690 $old_id = $post['post_id'];
691 self::populate_post( $post, $item, $imported );
692
693 unset( $item );
694
695 $post_id = false;
696 if ( $post['post_type'] == $form_action_type ) {
697 $action_control = FrmFormActionsController::get_form_actions( $post['post_excerpt'] );
698 if ( $action_control && is_object( $action_control ) ) {
699 $post_id = $action_control->maybe_create_action( $post, $imported['form_status'] );
700 }
701 unset( $action_control );
702 } elseif ( $post['post_type'] == 'frm_styles' ) {
703 // Properly encode post content before inserting the post
704 $post['post_content'] = FrmAppHelper::maybe_json_decode( $post['post_content'] );
705 $custom_css = isset( $post['post_content']['custom_css'] ) ? $post['post_content']['custom_css'] : '';
706 $post['post_content'] = FrmAppHelper::prepare_and_encode( $post['post_content'] );
707
708 // Create/update post now
709 $post_id = wp_insert_post( $post );
710 self::maybe_update_custom_css( $custom_css );
711 } else {
712 // Create/update post now
713 $post_id = wp_insert_post( $post );
714 }
715
716 if ( ! is_numeric( $post_id ) ) {
717 continue;
718 }
719
720 self::update_postmeta( $post, $post_id );
721
722 $this_type = 'posts';
723 if ( isset( $post_types[ $post['post_type'] ] ) ) {
724 $this_type = $post_types[ $post['post_type'] ];
725 }
726
727 if ( isset( $post['ID'] ) && $post_id == $post['ID'] ) {
728 $imported['updated'][ $this_type ] ++;
729 } else {
730 $imported['imported'][ $this_type ] ++;
731 }
732
733 $imported['posts'][ (int) $old_id ] = $post_id;
734
735 do_action( 'frm_after_import_view', $post_id, $post );
736
737 unset( $post );
738 }
739
740 self::maybe_update_stylesheet( $imported );
741
742 return $imported;
743 }
744
745 private static function populate_post( &$post, $item, $imported ) {
746 if ( isset( $item->attachment_url ) ) {
747 $post['attachment_url'] = (string) $item->attachment_url;
748 }
749
750 if ( $post['post_type'] == FrmFormActionsController::$action_post_type && isset( $imported['forms'][ (int) $post['menu_order'] ] ) ) {
751 // update to new form id
752 $post['menu_order'] = $imported['forms'][ (int) $post['menu_order'] ];
753 }
754
755 // Don't allow default styles to take over a site's default style
756 if ( 'frm_styles' == $post['post_type'] ) {
757 $post['menu_order'] = 0;
758 }
759
760 foreach ( $item->postmeta as $meta ) {
761 self::populate_postmeta( $post, $meta, $imported );
762 unset( $meta );
763 }
764
765 self::populate_taxonomies( $post, $item );
766
767 self::maybe_editing_post( $post );
768 }
769
770 private static function populate_postmeta( &$post, $meta, $imported ) {
771 global $frm_duplicate_ids;
772
773 $m = array(
774 'key' => (string) $meta->meta_key,
775 'value' => (string) $meta->meta_value,
776 );
777
778 //switch old form and field ids to new ones
779 if ( $m['key'] == 'frm_form_id' && isset( $imported['forms'][ (int) $m['value'] ] ) ) {
780 $m['value'] = $imported['forms'][ (int) $m['value'] ];
781 } else {
782 $m['value'] = FrmAppHelper::maybe_json_decode( $m['value'] );
783
784 if ( ! empty( $frm_duplicate_ids ) ) {
785
786 if ( $m['key'] == 'frm_dyncontent' ) {
787 $m['value'] = FrmFieldsHelper::switch_field_ids( $m['value'] );
788 } elseif ( $m['key'] == 'frm_options' ) {
789
790 foreach ( array( 'date_field_id', 'edate_field_id' ) as $setting_name ) {
791 if ( isset( $m['value'][ $setting_name ] ) && is_numeric( $m['value'][ $setting_name ] ) && isset( $frm_duplicate_ids[ $m['value'][ $setting_name ] ] ) ) {
792 $m['value'][ $setting_name ] = $frm_duplicate_ids[ $m['value'][ $setting_name ] ];
793 }
794 }
795
796 $check_dup_array = array();
797 if ( isset( $m['value']['order_by'] ) && ! empty( $m['value']['order_by'] ) ) {
798 if ( is_numeric( $m['value']['order_by'] ) && isset( $frm_duplicate_ids[ $m['value']['order_by'] ] ) ) {
799 $m['value']['order_by'] = $frm_duplicate_ids[ $m['value']['order_by'] ];
800 } elseif ( is_array( $m['value']['order_by'] ) ) {
801 $check_dup_array[] = 'order_by';
802 }
803 }
804
805 if ( isset( $m['value']['where'] ) && ! empty( $m['value']['where'] ) ) {
806 $check_dup_array[] = 'where';
807 }
808
809 foreach ( $check_dup_array as $check_k ) {
810 foreach ( (array) $m['value'][ $check_k ] as $mk => $mv ) {
811 if ( isset( $frm_duplicate_ids[ $mv ] ) ) {
812 $m['value'][ $check_k ][ $mk ] = $frm_duplicate_ids[ $mv ];
813 }
814 unset( $mk, $mv );
815 }
816 }
817 }
818 }
819 }
820
821 if ( ! is_array( $m['value'] ) ) {
822 $m['value'] = FrmAppHelper::maybe_json_decode( $m['value'] );
823 }
824
825 $post['postmeta'][ (string) $meta->meta_key ] = $m['value'];
826 }
827
828 /**
829 * Add terms to post
830 *
831 * @param array $post by reference
832 * @param object $item The XML object data
833 */
834 private static function populate_taxonomies( &$post, $item ) {
835 foreach ( $item->category as $c ) {
836 $att = $c->attributes();
837 if ( ! isset( $att['nicename'] ) ) {
838 continue;
839 }
840
841 $taxonomy = (string) $att['domain'];
842 if ( is_taxonomy_hierarchical( $taxonomy ) ) {
843 $name = (string) $att['nicename'];
844 $h_term = get_term_by( 'slug', $name, $taxonomy );
845 if ( $h_term ) {
846 $name = $h_term->term_id;
847 }
848 unset( $h_term );
849 } else {
850 $name = (string) $c;
851 }
852
853 if ( ! isset( $post['tax_input'][ $taxonomy ] ) ) {
854 $post['tax_input'][ $taxonomy ] = array();
855 }
856
857 $post['tax_input'][ $taxonomy ][] = $name;
858 unset( $name );
859 }
860 }
861
862 /**
863 * Edit post if the key and created time match
864 */
865 private static function maybe_editing_post( &$post ) {
866 $match_by = array(
867 'post_type' => $post['post_type'],
868 'name' => $post['post_name'],
869 'post_status' => $post['post_status'],
870 'posts_per_page' => 1,
871 );
872
873 if ( in_array( $post['post_status'], array( 'trash', 'draft' ) ) ) {
874 $match_by['include'] = $post['post_id'];
875 unset( $match_by['name'] );
876 }
877
878 $editing = get_posts( $match_by );
879
880 if ( ! empty( $editing ) && current( $editing )->post_date == $post['post_date'] ) {
881 // set the id of the post to edit
882 $post['ID'] = current( $editing )->ID;
883 }
884 }
885
886 private static function update_postmeta( &$post, $post_id ) {
887 foreach ( $post['postmeta'] as $k => $v ) {
888 if ( '_edit_last' == $k ) {
889 $v = FrmAppHelper::get_user_id_param( $v );
890 } elseif ( '_thumbnail_id' == $k && FrmAppHelper::pro_is_installed() ) {
891 // Change the attachment ID.
892 $field_obj = FrmFieldFactory::get_field_type( 'file' );
893 $v = $field_obj->get_file_id( $v );
894 }
895
896 update_post_meta( $post_id, $k, $v );
897
898 unset( $k, $v );
899 }
900 }
901
902 /**
903 * If a template includes custom css, let's include it.
904 * The custom css is included on the default style.
905 *
906 * @since 2.03
907 */
908 private static function maybe_update_custom_css( $custom_css ) {
909 if ( empty( $custom_css ) ) {
910 return;
911 }
912
913 $frm_style = new FrmStyle();
914 $default_style = $frm_style->get_default_style();
915 $default_style->post_content['custom_css'] .= "\r\n\r\n" . $custom_css;
916 $frm_style->save( $default_style );
917 }
918
919 private static function maybe_update_stylesheet( $imported ) {
920 $new_styles = isset( $imported['imported']['styles'] ) && ! empty( $imported['imported']['styles'] );
921 $updated_styles = isset( $imported['updated']['styles'] ) && ! empty( $imported['updated']['styles'] );
922 if ( $new_styles || $updated_styles ) {
923 if ( is_admin() && function_exists( 'get_filesystem_method' ) ) {
924 $frm_style = new FrmStyle();
925 $frm_style->update( 'default' );
926 }
927 foreach ( $imported['forms'] as $form_id ) {
928 self::update_custom_style_setting_after_import( $form_id );
929 }
930 }
931 }
932
933 /**
934 * @param string $message
935 */
936 public static function parse_message( $result, &$message, &$errors ) {
937 if ( is_wp_error( $result ) ) {
938 $errors[] = $result->get_error_message();
939 } elseif ( ! $result ) {
940 return;
941 }
942
943 if ( ! is_array( $result ) ) {
944 $message = is_string( $result ) ? $result : htmlentities( print_r( $result, 1 ) );
945
946 return;
947 }
948
949 $t_strings = array(
950 'imported' => __( 'Imported', 'formidable' ),
951 'updated' => __( 'Updated', 'formidable' ),
952 );
953
954 $message = '<ul>';
955 foreach ( $result as $type => $results ) {
956 if ( ! isset( $t_strings[ $type ] ) ) {
957 // only print imported and updated
958 continue;
959 }
960
961 $s_message = array();
962 foreach ( $results as $k => $m ) {
963 self::item_count_message( $m, $k, $s_message );
964 unset( $k, $m );
965 }
966
967 if ( ! empty( $s_message ) ) {
968 $message .= '<li><strong>' . $t_strings[ $type ] . ':</strong> ';
969 $message .= implode( ', ', $s_message );
970 $message .= '</li>';
971 }
972 }
973
974 if ( $message == '<ul>' ) {
975 $message = '';
976 $errors[] = __( 'Nothing was imported or updated', 'formidable' );
977 } else {
978 self::add_form_link_to_message( $result, $message );
979
980 $message .= '</ul>';
981 }
982 }
983
984 public static function item_count_message( $m, $type, &$s_message ) {
985 if ( ! $m ) {
986 return;
987 }
988
989 $strings = array(
990 /* translators: %1$s: Number of items */
991 'forms' => sprintf( _n( '%1$s Form', '%1$s Forms', $m, 'formidable' ), $m ),
992 /* translators: %1$s: Number of items */
993 'fields' => sprintf( _n( '%1$s Field', '%1$s Fields', $m, 'formidable' ), $m ),
994 /* translators: %1$s: Number of items */
995 'items' => sprintf( _n( '%1$s Entry', '%1$s Entries', $m, 'formidable' ), $m ),
996 /* translators: %1$s: Number of items */
997 'views' => sprintf( _n( '%1$s View', '%1$s Views', $m, 'formidable' ), $m ),
998 /* translators: %1$s: Number of items */
999 'posts' => sprintf( _n( '%1$s Post', '%1$s Posts', $m, 'formidable' ), $m ),
1000 /* translators: %1$s: Number of items */
1001 'styles' => sprintf( _n( '%1$s Style', '%1$s Styles', $m, 'formidable' ), $m ),
1002 /* translators: %1$s: Number of items */
1003 'terms' => sprintf( _n( '%1$s Term', '%1$s Terms', $m, 'formidable' ), $m ),
1004 /* translators: %1$s: Number of items */
1005 'actions' => sprintf( _n( '%1$s Form Action', '%1$s Form Actions', $m, 'formidable' ), $m ),
1006 );
1007
1008 $s_message[] = isset( $strings[ $type ] ) ? $strings[ $type ] : ' ' . $m . ' ' . ucfirst( $type );
1009 }
1010
1011 /**
1012 * If a single form was imported, include a link in the success message.
1013 *
1014 * @since 4.0
1015 * @param array $result The response from the XML import.
1016 * @param string $message The response shown on the page after import.
1017 */
1018 private static function add_form_link_to_message( $result, &$message ) {
1019 $total_forms = $result['imported']['forms'] + $result['updated']['forms'];
1020 if ( $total_forms > 1 ) {
1021 return;
1022 }
1023
1024 $primary_form = reset( $result['forms'] );
1025 if ( ! empty( $primary_form ) ) {
1026 $primary_form = FrmForm::getOne( $primary_form );
1027 $form_id = empty( $primary_form->parent_form_id ) ? $primary_form->id : $primary_form->parent_form_id;
1028
1029 $message .= '<li><a href="' . esc_url( FrmForm::get_edit_link( $form_id ) ) . '">' . esc_html__( 'Go to imported form', 'formidable' ) . '</a></li>';
1030 }
1031 }
1032
1033 /**
1034 * Prepare the form options for export
1035 *
1036 * @since 2.0.19
1037 *
1038 * @param string $options
1039 *
1040 * @return string
1041 */
1042 public static function prepare_form_options_for_export( $options ) {
1043 FrmAppHelper::unserialize_or_decode( $options );
1044 // Change custom_style to the post_name instead of ID (1 may be a string)
1045 $not_default = isset( $options['custom_style'] ) && 1 != $options['custom_style'];
1046 if ( $not_default ) {
1047 global $wpdb;
1048 $table = $wpdb->prefix . 'posts';
1049 $where = array( 'ID' => $options['custom_style'] );
1050 $select = 'post_name';
1051
1052 $style_name = FrmDb::get_var( $table, $where, $select );
1053
1054 if ( $style_name ) {
1055 $options['custom_style'] = $style_name;
1056 } else {
1057 $options['custom_style'] = 1;
1058 }
1059 }
1060 self::remove_default_form_options( $options );
1061 $options = serialize( $options );
1062
1063 return self::cdata( $options );
1064 }
1065
1066 /**
1067 * If the saved value is the same as the default, remove it from the export
1068 * This keeps file size down and prevents overriding global settings after import
1069 *
1070 * @since 3.06
1071 */
1072 private static function remove_default_form_options( &$options ) {
1073 $defaults = FrmFormsHelper::get_default_opts();
1074 if ( is_callable( 'FrmProFormsHelper::get_default_opts' ) ) {
1075 $defaults += FrmProFormsHelper::get_default_opts();
1076 }
1077 self::remove_defaults( $defaults, $options );
1078 }
1079
1080 /**
1081 * Remove extra settings from field to keep file size down
1082 *
1083 * @since 3.06
1084 */
1085 public static function prepare_field_for_export( &$field ) {
1086 self::remove_default_field_options( $field );
1087 }
1088
1089 /**
1090 * Remove defaults from field options too
1091 *
1092 * @since 3.06
1093 */
1094 private static function remove_default_field_options( &$field ) {
1095 $defaults = self::default_field_options( $field->type );
1096 if ( empty( $defaults['blank'] ) ) {
1097 $global_settings = new FrmSettings();
1098 $global_defaults = $global_settings->default_options();
1099 $defaults['blank'] = $global_defaults['blank_msg'];
1100 }
1101
1102 $options = $field->field_options;
1103 FrmAppHelper::unserialize_or_decode( $options );
1104 self::remove_defaults( $defaults, $options );
1105 self::remove_default_html( 'custom_html', $defaults, $options );
1106
1107 // Get variations on the defaults.
1108 if ( isset( $options['invalid'] ) ) {
1109 $defaults = array(
1110 /* translators: %s: Field name */
1111 'invalid' => sprintf( __( '%s is invalid', 'formidable' ), $field->name ),
1112 );
1113 self::remove_defaults( $defaults, $options );
1114 }
1115
1116 $field->field_options = serialize( $options );
1117 }
1118
1119 /**
1120 * @since 3.06.03
1121 */
1122 private static function default_field_options( $type ) {
1123 $defaults = FrmFieldsHelper::get_default_field_options( $type );
1124 if ( empty( $defaults['custom_html'] ) ) {
1125 $defaults['custom_html'] = FrmFieldsHelper::get_default_html( $type );
1126 }
1127 return $defaults;
1128 }
1129
1130 /**
1131 * Compare the default array to the saved values and
1132 * remove if they are the same
1133 *
1134 * @since 3.06
1135 */
1136 private static function remove_defaults( $defaults, &$saved ) {
1137 $array_defaults = array_filter( $defaults, 'is_array' );
1138 foreach ( $array_defaults as $d => $default ) {
1139 // compare array defaults
1140 if ( $default == $saved[ $d ] ) {
1141 unset( $saved[ $d ] );
1142 }
1143 unset( $defaults[ $d ] );
1144 }
1145 $saved = array_diff_assoc( (array) $saved, $defaults );
1146 }
1147
1148 /**
1149 * The line endings may prevent html from being equal when it should
1150 *
1151 * @since 3.06
1152 */
1153 private static function remove_default_html( $html_name, $defaults, &$options ) {
1154 if ( ! isset( $options[ $html_name ] ) || ! isset( $defaults[ $html_name ] ) ) {
1155 return;
1156 }
1157
1158 $old_html = str_replace( "\r\n", "\n", $options[ $html_name ] );
1159 $default_html = $defaults[ $html_name ];
1160 if ( $old_html == $default_html ) {
1161 unset( $options[ $html_name ] );
1162
1163 return;
1164 }
1165
1166 // Account for some of the older field default HTML.
1167 $default_html = str_replace( ' id="frm_desc_field_[key]"', '', $default_html );
1168 if ( $old_html == $default_html ) {
1169 unset( $options[ $html_name ] );
1170 }
1171 }
1172
1173 public static function cdata( $str ) {
1174 FrmAppHelper::unserialize_or_decode( $str );
1175 if ( is_array( $str ) ) {
1176 $str = json_encode( $str );
1177 } elseif ( seems_utf8( $str ) == false ) {
1178 $str = utf8_encode( $str );
1179 }
1180
1181 if ( is_numeric( $str ) ) {
1182 return $str;
1183 }
1184
1185 self::remove_invalid_characters_from_xml( $str );
1186
1187 // $str = ent2ncr(esc_html( $str));
1188 $str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str ) . ']]>';
1189
1190 return $str;
1191 }
1192
1193 /**
1194 * Remove <US> character (unit separator) from exported strings
1195 *
1196 * @since 2.0.22
1197 *
1198 * @param string $str
1199 */
1200 private static function remove_invalid_characters_from_xml( &$str ) {
1201 // Remove <US> character
1202 $str = str_replace( '\x1F', '', $str );
1203 }
1204
1205 public static function migrate_form_settings_to_actions( $form_options, $form_id, &$imported = array(), $switch = false ) {
1206 // Get post type
1207 $post_type = FrmFormActionsController::$action_post_type;
1208
1209 // Set up imported index, if not set up yet
1210 if ( ! isset( $imported['imported']['actions'] ) ) {
1211 $imported['imported']['actions'] = 0;
1212 }
1213
1214 // Migrate post settings to action
1215 self::migrate_post_settings_to_action( $form_options, $form_id, $post_type, $imported, $switch );
1216
1217 // Migrate email settings to action
1218 self::migrate_email_settings_to_action( $form_options, $form_id, $post_type, $imported, $switch );
1219 }
1220
1221 /**
1222 * Migrate post settings to form action
1223 *
1224 * @param string $post_type
1225 */
1226 private static function migrate_post_settings_to_action( $form_options, $form_id, $post_type, &$imported, $switch ) {
1227 if ( ! isset( $form_options['create_post'] ) || ! $form_options['create_post'] ) {
1228 return;
1229 }
1230
1231 $new_action = array(
1232 'post_type' => $post_type,
1233 'post_excerpt' => 'wppost',
1234 'post_title' => __( 'Create Posts', 'formidable' ),
1235 'menu_order' => $form_id,
1236 'post_status' => 'publish',
1237 'post_content' => array(),
1238 'post_name' => $form_id . '_wppost_1',
1239 );
1240
1241 $post_settings = array(
1242 'post_type',
1243 'post_category',
1244 'post_content',
1245 'post_excerpt',
1246 'post_title',
1247 'post_name',
1248 'post_date',
1249 'post_status',
1250 'post_custom_fields',
1251 'post_password',
1252 );
1253
1254 foreach ( $post_settings as $post_setting ) {
1255 if ( isset( $form_options[ $post_setting ] ) ) {
1256 $new_action['post_content'][ $post_setting ] = $form_options[ $post_setting ];
1257 }
1258 unset( $post_setting );
1259 }
1260
1261 $new_action['event'] = array( 'create', 'update' );
1262
1263 if ( $switch ) {
1264 // Fields with string or int saved.
1265 $basic_fields = array(
1266 'post_title',
1267 'post_content',
1268 'post_excerpt',
1269 'post_password',
1270 'post_date',
1271 'post_status',
1272 );
1273
1274 // Fields with arrays saved.
1275 $array_fields = array( 'post_category', 'post_custom_fields' );
1276
1277 $new_action['post_content'] = self::switch_action_field_ids( $new_action['post_content'], $basic_fields, $array_fields );
1278 }
1279 $new_action['post_content'] = json_encode( $new_action['post_content'] );
1280
1281 $exists = get_posts(
1282 array(
1283 'name' => $new_action['post_name'],
1284 'post_type' => $new_action['post_type'],
1285 'post_status' => $new_action['post_status'],
1286 'numberposts' => 1,
1287 )
1288 );
1289
1290 if ( ! $exists ) {
1291 // this isn't an email, but we need to use a class that will always be included
1292 FrmDb::save_json_post( $new_action );
1293 $imported['imported']['actions'] ++;
1294 }
1295 }
1296
1297 /**
1298 * Switch old field IDs for new field IDs in emails and post
1299 *
1300 * @since 2.0
1301 *
1302 * @param array $post_content - check for old field IDs
1303 * @param array $basic_fields - fields with string or int saved
1304 * @param array $array_fields - fields with arrays saved
1305 *
1306 * @return string $post_content - new field IDs
1307 */
1308 private static function switch_action_field_ids( $post_content, $basic_fields, $array_fields = array() ) {
1309 global $frm_duplicate_ids;
1310
1311 // If there aren't IDs that were switched, end now
1312 if ( ! $frm_duplicate_ids ) {
1313 return;
1314 }
1315
1316 // Get old IDs
1317 $old = array_keys( $frm_duplicate_ids );
1318
1319 // Get new IDs
1320 $new = array_values( $frm_duplicate_ids );
1321
1322 // Do a str_replace with each item to set the new IDs
1323 foreach ( $post_content as $key => $setting ) {
1324 if ( ! is_array( $setting ) && in_array( $key, $basic_fields ) ) {
1325 // Replace old IDs with new IDs
1326 $post_content[ $key ] = str_replace( $old, $new, $setting );
1327 } elseif ( is_array( $setting ) && in_array( $key, $array_fields ) ) {
1328 foreach ( $setting as $k => $val ) {
1329 // Replace old IDs with new IDs
1330 $post_content[ $key ][ $k ] = str_replace( $old, $new, $val );
1331 }
1332 }
1333 unset( $key, $setting );
1334 }
1335
1336 return $post_content;
1337 }
1338
1339 private static function migrate_email_settings_to_action( $form_options, $form_id, $post_type, &$imported, $switch ) {
1340 // No old notifications or autoresponders to carry over
1341 if ( ! isset( $form_options['auto_responder'] ) && ! isset( $form_options['notification'] ) && ! isset( $form_options['email_to'] ) ) {
1342 return;
1343 }
1344
1345 // Initialize notifications array
1346 $notifications = array();
1347
1348 // Migrate regular notifications
1349 self::migrate_notifications_to_action( $form_options, $form_id, $notifications );
1350
1351 // Migrate autoresponders
1352 self::migrate_autoresponder_to_action( $form_options, $form_id, $notifications );
1353
1354 if ( empty( $notifications ) ) {
1355 return;
1356 }
1357
1358 foreach ( $notifications as $new_notification ) {
1359 $new_notification['post_type'] = $post_type;
1360 $new_notification['post_excerpt'] = 'email';
1361 $new_notification['post_title'] = __( 'Email Notification', 'formidable' );
1362 $new_notification['menu_order'] = $form_id;
1363 $new_notification['post_status'] = 'publish';
1364
1365 // Switch field IDs and keys, if needed
1366 if ( $switch ) {
1367
1368 // Switch field IDs in email conditional logic
1369 self::switch_email_condition_field_ids( $new_notification['post_content'] );
1370
1371 // Switch all other field IDs in email
1372 $new_notification['post_content'] = FrmFieldsHelper::switch_field_ids( $new_notification['post_content'] );
1373 }
1374 $new_notification['post_content'] = FrmAppHelper::prepare_and_encode( $new_notification['post_content'] );
1375
1376 $exists = get_posts(
1377 array(
1378 'name' => $new_notification['post_name'],
1379 'post_type' => $new_notification['post_type'],
1380 'post_status' => $new_notification['post_status'],
1381 'numberposts' => 1,
1382 )
1383 );
1384
1385 if ( empty( $exists ) ) {
1386 FrmDb::save_json_post( $new_notification );
1387 $imported['imported']['actions'] ++;
1388 }
1389 unset( $new_notification );
1390 }
1391
1392 self::remove_deprecated_notification_settings( $form_id, $form_options );
1393 }
1394
1395 /**
1396 * Remove deprecated notification settings after migration
1397 *
1398 * @since 2.05
1399 *
1400 * @param int|string $form_id
1401 * @param array $form_options
1402 */
1403 private static function remove_deprecated_notification_settings( $form_id, $form_options ) {
1404 $delete_settings = array( 'notification', 'autoresponder', 'email_to' );
1405 foreach ( $delete_settings as $index ) {
1406 if ( isset( $form_options[ $index ] ) ) {
1407 unset( $form_options[ $index ] );
1408 }
1409 }
1410 FrmForm::update( $form_id, array( 'options' => $form_options ) );
1411 }
1412
1413 private static function migrate_notifications_to_action( $form_options, $form_id, &$notifications ) {
1414 if ( ! isset( $form_options['notification'] ) && isset( $form_options['email_to'] ) && ! empty( $form_options['email_to'] ) ) {
1415 // add old settings into notification array
1416 $form_options['notification'] = array( 0 => $form_options );
1417 } elseif ( isset( $form_options['notification']['email_to'] ) ) {
1418 // make sure it's in the correct format
1419 $form_options['notification'] = array( 0 => $form_options['notification'] );
1420 }
1421
1422 if ( isset( $form_options['notification'] ) && is_array( $form_options['notification'] ) ) {
1423 foreach ( $form_options['notification'] as $email_key => $notification ) {
1424
1425 $atts = array(
1426 'email_to' => '',
1427 'reply_to' => '',
1428 'reply_to_name' => '',
1429 'event' => '',
1430 'form_id' => $form_id,
1431 'email_key' => $email_key,
1432 );
1433
1434 // Format the email data
1435 self::format_email_data( $atts, $notification );
1436
1437 if ( isset( $notification['twilio'] ) && $notification['twilio'] ) {
1438 do_action( 'frm_create_twilio_action', $atts, $notification );
1439 }
1440
1441 // Setup the new notification
1442 $new_notification = array();
1443 self::setup_new_notification( $new_notification, $notification, $atts );
1444
1445 $notifications[] = $new_notification;
1446 }
1447 }
1448 }
1449
1450 private static function format_email_data( &$atts, $notification ) {
1451 // Format email_to
1452 self::format_email_to_data( $atts, $notification );
1453
1454 // Format the reply to email and name
1455 $reply_fields = array(
1456 'reply_to' => '',
1457 'reply_to_name' => '',
1458 );
1459 foreach ( $reply_fields as $f => $val ) {
1460 if ( isset( $notification[ $f ] ) ) {
1461 $atts[ $f ] = $notification[ $f ];
1462 if ( 'custom' == $notification[ $f ] ) {
1463 $atts[ $f ] = $notification[ 'cust_' . $f ];
1464 } elseif ( is_numeric( $atts[ $f ] ) && ! empty( $atts[ $f ] ) ) {
1465 $atts[ $f ] = '[' . $atts[ $f ] . ']';
1466 }
1467 }
1468 unset( $f, $val );
1469 }
1470
1471 // Format event
1472 $atts['event'] = array( 'create' );
1473 if ( isset( $notification['update_email'] ) && 1 == $notification['update_email'] ) {
1474 $atts['event'][] = 'update';
1475 } elseif ( isset( $notification['update_email'] ) && 2 == $notification['update_email'] ) {
1476 $atts['event'] = array( 'update' );
1477 }
1478 }
1479
1480 private static function format_email_to_data( &$atts, $notification ) {
1481 if ( isset( $notification['email_to'] ) ) {
1482 $atts['email_to'] = preg_split( '/ (,|;) /', $notification['email_to'] );
1483 } else {
1484 $atts['email_to'] = array();
1485 }
1486
1487 if ( isset( $notification['also_email_to'] ) ) {
1488 $email_fields = (array) $notification['also_email_to'];
1489 $atts['email_to'] = array_merge( $email_fields, $atts['email_to'] );
1490 unset( $email_fields );
1491 }
1492
1493 foreach ( $atts['email_to'] as $key => $email_field ) {
1494
1495 if ( is_numeric( $email_field ) ) {
1496 $atts['email_to'][ $key ] = '[' . $email_field . ']';
1497 }
1498
1499 if ( strpos( $email_field, '|' ) ) {
1500 $email_opt = explode( '|', $email_field );
1501 if ( isset( $email_opt[0] ) ) {
1502 $atts['email_to'][ $key ] = '[' . $email_opt[0] . ' show=' . $email_opt[1] . ']';
1503 }
1504 unset( $email_opt );
1505 }
1506 }
1507 $atts['email_to'] = implode( ', ', $atts['email_to'] );
1508 }
1509
1510 private static function setup_new_notification( &$new_notification, $notification, $atts ) {
1511 // Set up new notification
1512 $new_notification = array(
1513 'post_content' => array(
1514 'email_to' => $atts['email_to'],
1515 'event' => $atts['event'],
1516 ),
1517 'post_name' => $atts['form_id'] . '_email_' . $atts['email_key'],
1518 );
1519
1520 // Add more fields to the new notification
1521 $add_fields = array( 'email_message', 'email_subject', 'plain_text', 'inc_user_info', 'conditions' );
1522 foreach ( $add_fields as $add_field ) {
1523 if ( isset( $notification[ $add_field ] ) ) {
1524 $new_notification['post_content'][ $add_field ] = $notification[ $add_field ];
1525 } elseif ( in_array( $add_field, array( 'plain_text', 'inc_user_info' ) ) ) {
1526 $new_notification['post_content'][ $add_field ] = 0;
1527 } else {
1528 $new_notification['post_content'][ $add_field ] = '';
1529 }
1530 unset( $add_field );
1531 }
1532
1533 // Set reply to
1534 $new_notification['post_content']['reply_to'] = $atts['reply_to'];
1535
1536 // Set from
1537 if ( ! empty( $atts['reply_to'] ) || ! empty( $atts['reply_to_name'] ) ) {
1538 $new_notification['post_content']['from'] = ( empty( $atts['reply_to_name'] ) ? '[sitename]' : $atts['reply_to_name'] ) . ' <' . ( empty( $atts['reply_to'] ) ? '[admin_email]' : $atts['reply_to'] ) . '>';
1539 }
1540 }
1541
1542 /**
1543 * Switch field IDs in pre-2.0 email conditional logic
1544 *
1545 * @param $post_content array, pass by reference
1546 */
1547 private static function switch_email_condition_field_ids( &$post_content ) {
1548 // Switch field IDs in conditional logic
1549 if ( isset( $post_content['conditions'] ) && is_array( $post_content['conditions'] ) ) {
1550 foreach ( $post_content['conditions'] as $email_key => $val ) {
1551 if ( is_numeric( $email_key ) ) {
1552 $post_content['conditions'][ $email_key ] = self::switch_action_field_ids( $val, array( 'hide_field' ) );
1553 }
1554 unset( $email_key, $val );
1555 }
1556 }
1557 }
1558
1559 private static function migrate_autoresponder_to_action( $form_options, $form_id, &$notifications ) {
1560 if ( isset( $form_options['auto_responder'] ) && $form_options['auto_responder'] && isset( $form_options['ar_email_message'] ) && $form_options['ar_email_message'] ) {
1561 // migrate autoresponder
1562
1563 $email_field = isset( $form_options['ar_email_to'] ) ? $form_options['ar_email_to'] : 0;
1564 if ( strpos( $email_field, '|' ) ) {
1565 // data from entries field
1566 $email_field = explode( '|', $email_field );
1567 if ( isset( $email_field[1] ) ) {
1568 $email_field = $email_field[1];
1569 }
1570 }
1571 if ( is_numeric( $email_field ) && ! empty( $email_field ) ) {
1572 $email_field = '[' . $email_field . ']';
1573 }
1574
1575 $notification = $form_options;
1576 $new_notification2 = array(
1577 'post_content' => array(
1578 'email_message' => $notification['ar_email_message'],
1579 'email_subject' => isset( $notification['ar_email_subject'] ) ? $notification['ar_email_subject'] : '',
1580 'email_to' => $email_field,
1581 'plain_text' => isset( $notification['ar_plain_text'] ) ? $notification['ar_plain_text'] : 0,
1582 'inc_user_info' => 0,
1583 ),
1584 'post_name' => $form_id . '_email_' . count( $notifications ),
1585 );
1586
1587 $reply_to = isset( $notification['ar_reply_to'] ) ? $notification['ar_reply_to'] : '';
1588 $reply_to_name = isset( $notification['ar_reply_to_name'] ) ? $notification['ar_reply_to_name'] : '';
1589
1590 if ( ! empty( $reply_to ) ) {
1591 $new_notification2['post_content']['reply_to'] = $reply_to;
1592 }
1593
1594 if ( ! empty( $reply_to ) || ! empty( $reply_to_name ) ) {
1595 $new_notification2['post_content']['from'] = ( empty( $reply_to_name ) ? '[sitename]' : $reply_to_name ) . ' <' . ( empty( $reply_to ) ? '[admin_email]' : $reply_to ) . '>';
1596 }
1597
1598 $notifications[] = $new_notification2;
1599 unset( $new_notification2 );
1600 }
1601 }
1602 }
1603
1604