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

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