Completed
Push — master ( feb49b...2e7061 )
by Stephanie
06:17 queued 03:03
created

FrmXMLHelper   F

Complexity

Total Complexity 295

Size/Duplication

Total Lines 1580
Duplicated Lines 0.76 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
dl 12
loc 1580
rs 0.8
c 0
b 0
f 0
wmc 295
lcom 1
cbo 10

57 Methods

Rating   Name   Duplication   Size   Complexity  
A get_xml_values() 0 16 5
B import_xml() 0 29 6
A import_xml_now() 0 14 3
A pre_import_data() 0 18 1
B import_xml_terms() 0 28 6
A get_term_parent_id() 0 13 3
B import_xml_forms() 0 56 5
A fill_form() 0 19 2
A maybe_get_form() 0 14 2
A update_form() 0 11 2
A get_form_fields() 0 12 2
A delete_removed_fields() 0 10 4
A put_child_forms_first() 0 16 4
A track_imported_child_forms() 0 5 2
A maybe_update_child_form_parent_id() 0 11 4
B import_xml_fields() 0 62 9
A fill_field() 0 15 1
A maybe_update_in_section_variable() 0 16 4
B maybe_update_form_select() 6 14 7
A maybe_update_get_values_form_setting() 6 12 4
A run_field_migrations() 0 4 1
A migrate_placeholders() 0 11 3
C migrate_field_placeholder() 0 38 12
A create_imported_field() 0 10 2
A update_custom_style_setting_on_import() 0 30 4
A update_custom_style_setting_after_import() 0 14 5
C import_xml_views() 0 87 11
B populate_post() 0 24 6
D populate_postmeta() 0 57 21
B populate_taxonomies() 0 27 6
A maybe_editing_post() 0 20 4
A update_postmeta() 0 15 5
A maybe_update_custom_css() 0 10 2
B maybe_update_stylesheet() 0 13 8
B parse_message() 0 47 10
A item_count_message() 0 26 3
A add_form_link_to_message() 0 14 4
A prepare_form_options_for_export() 0 23 4
A remove_default_form_options() 0 7 2
A prepare_field_for_export() 0 3 1
A remove_default_field_options() 0 23 3
A default_field_options() 0 7 2
A remove_defaults() 0 11 3
A remove_default_html() 0 19 5
A cdata() 0 19 4
A remove_invalid_characters_from_xml() 0 4 1
A migrate_form_settings_to_actions() 0 15 2
B migrate_post_settings_to_action() 0 70 7
B switch_action_field_ids() 0 30 8
B migrate_email_settings_to_action() 0 55 8
A remove_deprecated_notification_settings() 0 9 3
B migrate_notifications_to_action() 0 36 10
B format_email_data() 0 29 10
B format_email_to_data() 0 29 7
B setup_new_notification() 0 31 8
A switch_email_contition_field_ids() 0 11 5
F migrate_autoresponder_to_action() 0 43 19

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like FrmXMLHelper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FrmXMLHelper, and based on these observations, apply Extract Interface, too.

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 ) );
0 ignored issues
show
introduced by
file_get_contents is highly discouraged, please use wpcom_vip_file_get_contents() instead.
Loading history...
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 View Code Duplication
			if ( FrmField::is_option_true( $f['field_options'], 'form_select' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
		if ( FrmField::is_option_true_in_array( $f['field_options'], 'get_values_form' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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'];
0 ignored issues
show
introduced by
Detected usage of meta_key, possible slow query.
Loading history...
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 ) );
0 ignored issues
show
introduced by
The use of function print_r() is discouraged
Loading history...
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_contition_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_contition_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