Completed
Push — master ( e99028...923363 )
by Stephanie
02:53 queued 10s
created

FrmFormsHelper::add_html_attr()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) {
3
	die( 'You are not allowed to call this page directly.' );
4
}
5
6
class FrmFormsHelper {
7
8
	/**
9
	 * @since 2.2.10
10
	 */
11
	public static function form_error_class() {
12
		return apply_filters( 'frm_form_error_class', 'frm_error_style' );
13
	}
14
15
	public static function get_direct_link( $key, $form = false ) {
16
		$target_url = esc_url( admin_url( 'admin-ajax.php?action=frm_forms_preview&form=' . $key ) );
17
		$target_url = apply_filters( 'frm_direct_link', $target_url, $key, $form );
18
19
		return $target_url;
20
	}
21
22
	public static function forms_dropdown( $field_name, $field_value = '', $args = array() ) {
23
		$defaults = array(
24
			'blank'        => true,
25
			'field_id'     => false,
26
			'onchange'     => false,
27
			'exclude'      => false,
28
			'class'        => '',
29
			'inc_children' => 'exclude',
30
		);
31
		$args     = wp_parse_args( $args, $defaults );
32
33
		if ( ! $args['field_id'] ) {
34
			$args['field_id'] = $field_name;
35
		}
36
37
		$query = array();
38
		if ( $args['exclude'] ) {
39
			$query['id !'] = $args['exclude'];
40
		}
41
42
		$where    = apply_filters( 'frm_forms_dropdown', $query, $field_name );
43
		$forms    = FrmForm::get_published_forms( $where, 999, $args['inc_children'] );
44
		$add_html = array();
45
		self::add_html_attr( $args['onchange'], 'onchange', $add_html );
46
		self::add_html_attr( $args['class'], 'class', $add_html );
47
48
		?>
49
		<select name="<?php echo esc_attr( $field_name ); ?>"
50
			id="<?php echo esc_attr( $args['field_id'] ); ?>"
51
			<?php echo wp_strip_all_tags( implode( ' ', $add_html ) ); // WPCS: XSS ok. ?>>
52
			<?php if ( $args['blank'] ) { ?>
53
				<option value=""><?php echo ( $args['blank'] == 1 ) ? ' ' : '- ' . esc_attr( $args['blank'] ) . ' -'; ?></option>
54
			<?php } ?>
55
			<?php foreach ( $forms as $form ) { ?>
56
				<option value="<?php echo esc_attr( $form->id ); ?>" <?php selected( $field_value, $form->id ); ?>>
57
					<?php echo esc_html( '' === $form->name ? __( '(no title)', 'formidable' ) : FrmAppHelper::truncate( $form->name, 50 ) . ( $form->parent_form_id ? __( ' (child)', 'formidable' ) : '' ) ); ?>
58
				</option>
59
			<?php } ?>
60
		</select>
61
		<?php
62
	}
63
64
	/**
65
	 * @param string $class
66
	 * @param string $param
67
	 * @param array $add_html
68
	 *
69
	 * @since 2.0.6
70
	 */
71
	public static function add_html_attr( $class, $param, &$add_html ) {
72
		if ( ! empty( $class ) ) {
73
			$add_html[ $param ] = sanitize_title( $param ) . '="' . esc_attr( trim( sanitize_text_field( $class ) ) ) . '"';
74
		}
75
	}
76
77
	/**
78
	 * @param string|object $selected - The label for the placeholder, or the form object.
79
	 */
80
	public static function form_switcher( $selected = false ) {
81
		$where = apply_filters( 'frm_forms_dropdown', array(), '' );
82
		$forms = FrmForm::get_published_forms( $where );
83
84
		$args = array(
85
			'id'   => 0,
86
			'form' => 0,
87
		);
88
		if ( isset( $_GET['id'] ) && ! isset( $_GET['form'] ) ) {
89
			unset( $args['form'] );
90
		} elseif ( isset( $_GET['form'] ) && ! isset( $_GET['id'] ) ) {
91
			unset( $args['id'] );
92
		}
93
94
		$frm_action = FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
95
		if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) && in_array( $frm_action, array( 'edit', 'show', 'destroy', 'destroy_all' ) ) ) {
96
			$args['frm_action'] = 'list';
97
			$args['form']       = 0;
98
		} elseif ( FrmAppHelper::is_admin_page( 'formidable' ) && in_array( $frm_action, array( 'new', 'duplicate' ) ) ) {
99
			$args['frm_action'] = 'edit';
100
		} elseif ( isset( $_GET['post'] ) ) {
101
			$args['form'] = 0;
102
			$base         = admin_url( 'edit.php?post_type=frm_display' );
103
		}
104
105
		$form_id = 0;
106
		if ( is_object( $selected ) ) {
107
			$form_id  = $selected->id;
108
			$selected = $selected->name;
109
		}
110
111
		$name = ( $selected === false ) ? __( 'Switch Form', 'formidable' ) : $selected;
112
		$name = '' === $name ? __( '(no title)', 'formidable' ) : strip_tags( $name );
113
		$truncated_name = FrmAppHelper::truncate( $name, 25 );
114
115
		if ( count( $forms ) < 2 ) {
116
			?>
117
			<div id="frm_bs_dropdown">
118
				<h1>
119
					<span class="frm_bstooltip" title="<?php echo esc_attr( $truncated_name === $name ? '' : $name ); ?>" data-placement="right">
120
						<?php echo esc_html( $name ); ?>
121
					</span>
122
				</h1>
123
			</div>
124
			<?php
125
			return;
126
		}
127
		?>
128
		<div id="frm_bs_dropdown" class="dropdown <?php echo esc_attr( is_rtl() ? 'pull-right' : 'pull-left' ); ?>">
129
			<a href="#" id="frm-navbarDrop" class="frm-dropdown-toggle" data-toggle="dropdown">
130
				<h1>
131
					<span class="frm_bstooltip" title="<?php echo esc_attr( $truncated_name === $name ? '' : $name ); ?>" data-placement="right">
132
						<?php echo esc_html( $name ); ?>
133
					</span>
134
					<?php FrmAppHelper::icon_by_class( 'frmfont frm_arrowdown4_icon', array( 'aria-hidden' => 'true' ) ); ?>
135
				</h1>
136
			</a>
137
			<ul class="frm-dropdown-menu frm-on-top frm-inline-modal frm_code_list frm-full-hover" role="menu" aria-labelledby="frm-navbarDrop">
138 View Code Duplication
				<?php if ( count( $forms ) > 8 ) { ?>
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...
139
				<li class="frm-with-search">
140
					<?php
141
					FrmAppHelper::show_search_box(
142
						array(
143
							'input_id'    => 'dropform',
144
							'placeholder' => __( 'Search Forms', 'formidable' ),
145
							'tosearch'    => 'frm-dropdown-form',
146
						)
147
					);
148
					?>
149
				</li>
150
				<?php } ?>
151
				<?php
152
				foreach ( $forms as $form ) {
153
					if ( $form->id === $form_id ) {
154
						// Don't include the selected form in the switcher since it does nothing.
155
						continue;
156
					}
157
158
					if ( isset( $args['id'] ) ) {
159
						$args['id'] = $form->id;
160
					}
161
					if ( isset( $args['form'] ) ) {
162
						$args['form'] = $form->id;
163
					}
164
165
					$url       = isset( $base ) ? add_query_arg( $args, $base ) : add_query_arg( $args );
166
					$form_name = empty( $form->name ) ? __( '(no title)', 'formidable' ) : $form->name;
167
					?>
168
					<li class="frm-dropdown-form">
169
						<a href="<?php echo esc_url( $url ); ?>" tabindex="-1">
170
							<span class="frm-sub-label">
171
							<?php
172
							printf(
173
								/* translators: %d: Form ID */
174
								esc_html__( '(ID %d)', 'formidable' ),
175
								esc_attr( $form->id )
176
							);
177
							?>
178
							</span>
179
							<?php echo esc_html( $form_name ); ?>
180
							<span class="frm_hidden"><?php echo esc_html( $form->form_key ); ?></span>
181
						</a>
182
					</li>
183
					<?php
184
					unset( $form );
185
				}
186
				?>
187
			</ul>
188
		</div>
189
		<?php
190
	}
191
192
	/**
193
	 * @since 3.05
194
	 * @deprecated 4.0
195
	 *
196
	 * @param array $values - The form array
197
	 */
198
	public static function builder_submit_button( $values ) {
199
		FrmDeprecated::builder_submit_button( $values );
200
	}
201
202
	public static function get_sortable_classes( $col, $sort_col, $sort_dir ) {
203
		echo ( $sort_col == $col ) ? 'sorted' : 'sortable';
204
		echo ( $sort_col == $col && $sort_dir == 'desc' ) ? ' asc' : ' desc';
205
	}
206
207
	/**
208
	 * @since 3.0
209
	 */
210
	public static function get_field_link_name( $field_type ) {
211
		if ( is_array( $field_type ) ) {
212
			$field_label = $field_type['name'];
213
		} else {
214
			$field_label = $field_type;
215
		}
216
217
		return $field_label;
218
	}
219
220
	/**
221
	 * @since 3.0
222
	 */
223
	public static function get_field_link_icon( $field_type ) {
224
		if ( is_array( $field_type ) && isset( $field_type['icon'] ) ) {
225
			$icon = $field_type['icon'];
226
		} else {
227
			$icon = 'frm_icon_font frm_pencil_icon';
228
		}
229
230
		return $icon;
231
	}
232
233
	/**
234
	 * Get the invalid form error message
235
	 *
236
	 * @since 2.02.07
237
	 *
238
	 * @param array $args
239
	 *
240
	 * @return string
241
	 */
242
	public static function get_invalid_error_message( $args ) {
243
		$settings_args = $args;
244
		if ( isset( $args['form'] ) ) {
245
			$settings_args['current_form'] = $args['form']->id;
246
		}
247
248
		$frm_settings = FrmAppHelper::get_settings( $settings_args );
249
		$invalid_msg = do_shortcode( $frm_settings->invalid_msg );
250
		return apply_filters( 'frm_invalid_error_message', $invalid_msg, $args );
251
	}
252
253
	public static function get_success_message( $atts ) {
254
		$message = apply_filters( 'frm_content', $atts['message'], $atts['form'], $atts['entry_id'] );
255
		$message = do_shortcode( FrmAppHelper::use_wpautop( $message ) );
256
		$message = '<div class="' . esc_attr( $atts['class'] ) . '" role="status">' . $message . '</div>';
257
258
		return $message;
259
	}
260
261
	/**
262
	 * Used when a form is created
263
	 */
264
	public static function setup_new_vars( $values = array() ) {
265
		global $wpdb;
266
267
		if ( ! empty( $values ) ) {
268
			$post_values = $values;
269
		} else {
270
			$values      = array();
271
			$post_values = isset( $_POST ) ? $_POST : array();
272
		}
273
274
		$defaults = array(
275
			'name'        => '',
276
			'description' => '',
277
		);
278 View Code Duplication
		foreach ( $defaults as $var => $default ) {
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...
279
			if ( ! isset( $values[ $var ] ) ) {
280
				$values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
281
			}
282
		}
283
284
		$values['description'] = FrmAppHelper::use_wpautop( $values['description'] );
285
286
		$defaults = array(
287
			'form_id'        => '',
288
			'logged_in'      => '',
289
			'editable'       => '',
290
			'is_template'    => 0,
291
			'status'         => 'published',
292
			'parent_form_id' => 0,
293
		);
294 View Code Duplication
		foreach ( $defaults as $var => $default ) {
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...
295
			if ( ! isset( $values[ $var ] ) ) {
296
				$values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
297
			}
298
		}
299
		unset( $defaults );
300
301
		if ( ! isset( $values['form_key'] ) ) {
302
			$values['form_key'] = ( $post_values && isset( $post_values['form_key'] ) ) ? $post_values['form_key'] : FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_forms', 'form_key' );
303
		}
304
305
		$values                 = self::fill_default_opts( $values, false, $post_values );
306
		$values['custom_style'] = FrmAppHelper::custom_style_value( $post_values );
307
308
		return apply_filters( 'frm_setup_new_form_vars', $values );
309
	}
310
311
	/**
312
	 * Used when editing a form
313
	 */
314
	public static function setup_edit_vars( $values, $record, $post_values = array() ) {
315
		if ( empty( $post_values ) ) {
316
			$post_values = wp_unslash( $_POST );
317
		}
318
319
		$values['form_key']    = isset( $post_values['form_key'] ) ? $post_values['form_key'] : $record->form_key;
320
		$values['is_template'] = isset( $post_values['is_template'] ) ? $post_values['is_template'] : $record->is_template;
321
		$values['status']      = $record->status;
322
323
		$values = self::fill_default_opts( $values, $record, $post_values );
324
325
		return apply_filters( 'frm_setup_edit_form_vars', $values );
326
	}
327
328
	public static function fill_default_opts( $values, $record, $post_values ) {
329
330
		$defaults = self::get_default_opts();
331
		foreach ( $defaults as $var => $default ) {
332
			if ( is_array( $default ) ) {
333
				if ( ! isset( $values[ $var ] ) ) {
334
					$values[ $var ] = ( $record && isset( $record->options[ $var ] ) ) ? $record->options[ $var ] : array();
335
				}
336
337
				foreach ( $default as $k => $v ) {
338
					$values[ $var ][ $k ] = ( $post_values && isset( $post_values[ $var ][ $k ] ) ) ? $post_values[ $var ][ $k ] : ( ( $record && isset( $record->options[ $var ] ) && isset( $record->options[ $var ][ $k ] ) ) ? $record->options[ $var ][ $k ] : $v );
339
340
					if ( is_array( $v ) ) {
341
						foreach ( $v as $k1 => $v1 ) {
342
							$values[ $var ][ $k ][ $k1 ] = ( $post_values && isset( $post_values[ $var ][ $k ][ $k1 ] ) ) ? $post_values[ $var ][ $k ][ $k1 ] : ( ( $record && isset( $record->options[ $var ] ) && isset( $record->options[ $var ][ $k ] ) && isset( $record->options[ $var ][ $k ][ $k1 ] ) ) ? $record->options[ $var ][ $k ][ $k1 ] : $v1 );
343
							unset( $k1, $v1 );
344
						}
345
					}
346
347
					unset( $k, $v );
348
				}
349
			} else {
350
				$values[ $var ] = ( $post_values && isset( $post_values['options'][ $var ] ) ) ? $post_values['options'][ $var ] : ( ( $record && isset( $record->options[ $var ] ) ) ? $record->options[ $var ] : $default );
351
			}
352
353
			unset( $var, $default );
354
		}
355
356
		return $values;
357
	}
358
359
	public static function get_default_opts() {
360
		$frm_settings = FrmAppHelper::get_settings();
361
362
		return array(
363
			'submit_value'   => $frm_settings->submit_value,
364
			'success_action' => 'message',
365
			'success_msg'    => $frm_settings->success_msg,
366
			'show_form'      => 0,
367
			'akismet'        => '',
368
			'no_save'        => 0,
369
			'ajax_load'      => 0,
370
			'js_validate'    => 0,
371
			'form_class'     => '',
372
			'custom_style'   => 1,
373
			'before_html'    => self::get_default_html( 'before' ),
374
			'after_html'     => '',
375
			'submit_html'    => self::get_default_html( 'submit' ),
376
		);
377
	}
378
379
	/**
380
	 * @param array $options
381
	 * @param array $values
382
	 *
383
	 * @since 2.0.6
384
	 */
385
	public static function fill_form_options( &$options, $values ) {
386
		$defaults = self::get_default_opts();
387
		foreach ( $defaults as $var => $default ) {
388
			$options[ $var ] = isset( $values['options'][ $var ] ) ? $values['options'][ $var ] : $default;
389
			unset( $var, $default );
390
		}
391
	}
392
393
	/**
394
	 * @param string $loc
395
	 */
396
	public static function get_default_html( $loc ) {
397
		if ( $loc == 'submit' ) {
398
			$draft_link   = self::get_draft_link();
399
			$default_html = <<<SUBMIT_HTML
400
<div class="frm_submit">
401
[if back_button]<button type="submit" name="frm_prev_page" formnovalidate="formnovalidate" class="frm_prev_page" [back_hook]>[back_label]</button>[/if back_button]
402
<button class="frm_button_submit" type="submit"  [button_action]>[button_label]</button>
403
$draft_link
404
</div>
405
SUBMIT_HTML;
406
		} elseif ( $loc == 'before' ) {
407
			$default_html = <<<BEFORE_HTML
408
<legend class="frm_screen_reader">[form_name]</legend>
409
[if form_name]<h3 class="frm_form_title">[form_name]</h3>[/if form_name]
410
[if form_description]<div class="frm_description">[form_description]</div>[/if form_description]
411
BEFORE_HTML;
412
		} else {
413
			$default_html = '';
414
		}
415
416
		return $default_html;
417
	}
418
419
	public static function get_draft_link() {
420
		$link = '[if save_draft]<a href="#" tabindex="0" class="frm_save_draft" [draft_hook]>[draft_label]</a>[/if save_draft]';
421
422
		return $link;
423
	}
424
425
	public static function get_custom_submit( $html, $form, $submit, $form_action, $values ) {
426
		$button = self::replace_shortcodes( $html, $form, $submit, $form_action, $values );
427
		if ( ! strpos( $button, '[button_action]' ) ) {
428
			echo $button; // WPCS: XSS ok.
429
430
			return;
431
		}
432
433
		$button_parts = explode( '[button_action]', $button );
434
435
		$classes = apply_filters( 'frm_submit_button_class', array(), $form );
436
		if ( ! empty( $classes ) ) {
437
			$classes      = implode( ' ', $classes );
438
			$button_class = ' class="frm_button_submit';
439
			if ( strpos( $button_parts[0], $button_class ) !== false ) {
440
				$button_parts[0] = str_replace( $button_class, $button_class . ' ' . esc_attr( $classes ), $button_parts[0] );
441
			} else {
442
				$button_parts[0] .= ' class="' . esc_attr( $classes ) . '"';
443
			}
444
		}
445
446
		echo $button_parts[0]; // WPCS: XSS ok.
447
		do_action( 'frm_submit_button_action', $form, $form_action );
448
		echo $button_parts[1]; // WPCS: XSS ok.
449
	}
450
451
	/**
452
	 * @since 4.0
453
	 */
454
	public static function html_shortcodes() {
455
		$codes = array(
456
			'id'             => array(
457
				'label' => __( 'Field ID', 'formidable' ),
458
				'class' => 'show_field_custom_html',
459
			),
460
			'key'            => array(
461
				'label' => __( 'Field Key', 'formidable' ),
462
				'class' => 'show_field_custom_html',
463
			),
464
			'field_name'     => array(
465
				'label' => __( 'Field Name', 'formidable' ),
466
				'class' => 'show_field_custom_html',
467
			),
468
			'description'    => array(
469
				'label' => __( 'Field Description', 'formidable' ),
470
				'class' => 'show_field_custom_html',
471
			),
472
			'label_position' => array(
473
				'label' => __( 'Label Position', 'formidable' ),
474
				'class' => 'show_field_custom_html',
475
			),
476
			'required_label' => array(
477
				'label' => __( 'Required Label', 'formidable' ),
478
				'class' => 'show_field_custom_html',
479
			),
480
			'input'          => array(
481
				'label' => __( 'Input Field', 'formidable' ),
482
				'class' => 'show_field_custom_html',
483
			),
484
			'input opt=1'    => array(
485
				'label' => __( 'Single Option', 'formidable' ),
486
				'title' => __( 'Show a single radio or checkbox option by replacing 1 with the order of the option', 'formidable' ),
487
				'class' => 'show_field_custom_html',
488
			),
489
			'input label=0'  => array(
490
				'label' => __( 'Hide Option Label', 'formidable' ),
491
				'class' => 'show_field_custom_html',
492
			),
493
			'required_class' => array(
494
				'label' => __( 'Required Class', 'formidable' ),
495
				'title' => __( 'Add class name if field is required', 'formidable' ),
496
				'class' => 'show_field_custom_html',
497
			),
498
			'error_class'    => array(
499
				'label' => __( 'Error Class', 'formidable' ),
500
				'title' => __( 'Add class name if field has an error on form submit', 'formidable' ),
501
				'class' => 'show_field_custom_html',
502
			),
503
504
			'form_name'        => array(
505
				'label' => __( 'Form Name', 'formidable' ),
506
				'class' => 'show_before_html show_after_html',
507
			),
508
			'form_description' => array(
509
				'label' => __( 'Form Description', 'formidable' ),
510
				'class' => 'show_before_html show_after_html',
511
			),
512
			'form_key'         => array(
513
				'label' => __( 'Form Key', 'formidable' ),
514
				'class' => 'show_before_html show_after_html',
515
			),
516
			'deletelink'       => array(
517
				'label' => __( 'Delete Entry Link', 'formidable' ),
518
				'class' => 'show_before_html show_after_html',
519
			),
520
521
			'button_label' => array(
522
				'label' => __( 'Button Label', 'formidable' ),
523
				'class' => 'show_submit_html',
524
			),
525
			'button_action' => array(
526
				'label' => __( 'Button Hook', 'formidable' ),
527
				'class' => 'show_submit_html',
528
			),
529
		);
530
531
		/**
532
		 * @since 4.0
533
		 */
534
		return apply_filters( 'frm_html_codes', $codes );
535
	}
536
537
	/**
538
	 * @since 4.0
539
	 * @param array $args
540
	 */
541
	public static function insert_opt_html( $args ) {
542
		$class  = isset( $args['class'] ) ? $args['class'] : '';
543
		$fields = FrmField::all_field_selection();
544
		$field  = isset( $fields[ $args['type'] ] ) ? $fields[ $args['type'] ] : array();
545
546
		self::prepare_field_type( $field );
547
548
		if ( ! isset( $field['icon'] ) ) {
549
			$field['icon'] = 'frmfont frm_pencil_icon';
550
		}
551
552
		$possible_email_field = FrmFieldFactory::field_has_property( $args['type'], 'holds_email_values' );
553
		if ( $possible_email_field ) {
554
			$class .= ' show_frm_not_email_to';
555
		}
556
		?>
557
		<li class="<?php echo esc_attr( $class ); ?>">
558
			<a href="javascript:void(0)" class="frmids frm_insert_code"
559
				data-code="<?php echo esc_attr( $args['id'] ); ?>">
560
				<span>[<?php echo esc_attr( isset( $args['id_label'] ) ? $args['id_label'] : $args['id'] ); ?>]</span>
561
				<?php FrmAppHelper::icon_by_class( $field['icon'], array( 'aria-hidden' => 'true' ) ); ?>
562
				<?php echo esc_attr( FrmAppHelper::truncate( $args['name'], 60 ) ); ?>
563
			</a>
564
			<a href="javascript:void(0)" class="frmkeys frm_insert_code frm_hidden"
565
				data-code="<?php echo esc_attr( $args['key'] ); ?>">
566
				<span>[<?php echo esc_attr( FrmAppHelper::truncate( isset( $args['key_label'] ) ? $args['key_label'] : $args['key'], 7 ) ); ?>]</span>
567
				<?php if ( isset( $field['icon'] ) ) { ?>
568
					<?php FrmAppHelper::icon_by_class( $field['icon'], array( 'aria-hidden' => 'true' ) ); ?>
569
				<?php } ?>
570
				<?php echo esc_attr( FrmAppHelper::truncate( $args['name'], 60 ) ); ?>
571
			</a>
572
		</li>
573
		<?php
574
	}
575
576
	/**
577
	 * @since 4.0
578
	 * @param array $args
579
	 */
580
	public static function insert_code_html( $args ) {
581
		$defaults = array(
582
			'class' => '',
583
			'code'  => '',
584
			'label' => '',
585
			'title' => '',
586
		);
587
588
		$args        = array_merge( $defaults, $args );
589
		$has_tooltip = ! empty( $args['title'] );
590
591
		?>
592
		<li class="<?php echo esc_attr( $args['class'] ); ?>">
593
			<a href="javascript:void(0)" class="frm_insert_code <?php echo $has_tooltip ? 'frm_help' : ''; ?>"
594
				<?php echo $has_tooltip ? 'title="' . esc_attr( $args['title'] ) . '"' : ''; ?>
595
				data-code="<?php echo esc_attr( $args['code'] ); ?>">
596
				<span>
597
					[<?php echo esc_attr( FrmAppHelper::truncate( $args['code'], 10 ) ); ?>]
598
				</span>
599
				<?php echo esc_attr( FrmAppHelper::truncate( $args['label'], 60 ) ); ?>
600
			</a>
601
		</li>
602
		<?php
603
	}
604
605
	/**
606
	 * Some field types in add-ons may have been added with only
607
	 * a field type and name.
608
	 *
609
	 * @since 4.0
610
	 */
611
	public static function prepare_field_type( &$field ) {
612
		if ( ! is_array( $field ) ) {
613
			$field = array(
614
				'name' => $field,
615
				'icon' => 'frm_icon_font frm_pencil_icon',
616
			);
617
		}
618
	}
619
620
	/**
621
	 * Automatically add end section fields if they don't exist (2.0 migration)
622
	 *
623
	 * @since 2.0
624
	 *
625
	 * @param boolean $reset_fields
626
	 */
627
	public static function auto_add_end_section_fields( $form, $fields, &$reset_fields ) {
628
		if ( empty( $fields ) ) {
629
			return;
630
		}
631
632
		$end_section_values = apply_filters( 'frm_before_field_created', FrmFieldsHelper::setup_new_vars( 'end_divider', $form->id ) );
633
		$open               = false;
634
		$prev_order         = false;
635
		$add_order          = 0;
636
		$last_field         = false;
637
		foreach ( $fields as $field ) {
638
			if ( $prev_order === $field->field_order ) {
639
				$add_order ++;
640
			}
641
642
			if ( $add_order ) {
643
				$reset_fields       = true;
644
				$field->field_order = $field->field_order + $add_order;
645
				FrmField::update( $field->id, array( 'field_order' => $field->field_order ) );
646
			}
647
648
			switch ( $field->type ) {
649
				case 'divider':
650
					// Create an end section if open.
651
					self::maybe_create_end_section( $open, $reset_fields, $add_order, $end_section_values, $field, 'move' );
652
653
					// Mark it open for the next end section.
654
					$open = true;
655
					break;
656
				case 'break':
657
					self::maybe_create_end_section( $open, $reset_fields, $add_order, $end_section_values, $field, 'move' );
658
					break;
659
				case 'end_divider':
660
					if ( ! $open ) {
661
						// The section isn't open, so this is an extra field that needs to be removed.
662
						FrmField::destroy( $field->id );
663
						$reset_fields = true;
664
					}
665
666
					// There is already an end section here, so there is no need to create one.
667
					$open = false;
668
			}
669
			$prev_order = $field->field_order;
670
671
			$last_field = $field;
672
			unset( $field );
673
		}
674
675
		self::maybe_create_end_section( $open, $reset_fields, $add_order, $end_section_values, $last_field );
676
	}
677
678
	/**
679
	 * Create end section field if it doesn't exist. This is for migration from < 2.0
680
	 * Fix any ordering that may be messed up
681
	 */
682
	public static function maybe_create_end_section( &$open, &$reset_fields, &$add_order, $end_section_values, $field, $move = 'no' ) {
683
		if ( ! $open ) {
684
			return;
685
		}
686
687
		$end_section_values['field_order'] = $field->field_order + 1;
688
689
		FrmField::create( $end_section_values );
690
691
		if ( $move == 'move' ) {
692
			// bump the order of current field unless we're at the end of the form
693
			FrmField::update( $field->id, array( 'field_order' => $field->field_order + 2 ) );
694
		}
695
696
		$add_order    += 2;
697
		$open         = false;
698
		$reset_fields = true;
699
	}
700
701
	public static function replace_shortcodes( $html, $form, $title = false, $description = false, $values = array() ) {
702
		$codes = array(
703
			'form_name'        => $title,
704
			'form_description' => $description,
705
			'entry_key'        => true,
706
		);
707
		foreach ( $codes as $code => $show ) {
708
			if ( $code == 'form_name' ) {
709
				$replace_with = $form->name;
710
			} elseif ( $code == 'form_description' ) {
711
				$replace_with = FrmAppHelper::use_wpautop( $form->description );
712
			} elseif ( $code == 'entry_key' && isset( $_GET ) && isset( $_GET['entry'] ) ) {
713
				$replace_with = FrmAppHelper::simple_get( 'entry' );
714
			} else {
715
				$replace_with = '';
716
			}
717
718
			FrmShortcodeHelper::remove_inline_conditions( ( FrmAppHelper::is_true( $show ) && $replace_with != '' ), $code, $replace_with, $html );
719
		}
720
721
		//replace [form_key]
722
		$html = str_replace( '[form_key]', $form->form_key, $html );
723
724
		//replace [frmurl]
725
		$html = str_replace( '[frmurl]', FrmFieldsHelper::dynamic_default_values( 'frmurl' ), $html );
726
727
		if ( strpos( $html, '[button_label]' ) ) {
728
			add_filter( 'frm_submit_button', 'FrmFormsHelper::submit_button_label', 1 );
729
			$submit_label = apply_filters( 'frm_submit_button', $title, $form );
730
			$submit_label = esc_attr( do_shortcode( $submit_label ) );
731
			$html         = str_replace( '[button_label]', $submit_label, $html );
732
		}
733
734
		$html = apply_filters( 'frm_form_replace_shortcodes', $html, $form, $values );
735
736
		if ( strpos( $html, '[if back_button]' ) ) {
737
			$html = preg_replace( '/(\[if\s+back_button\])(.*?)(\[\/if\s+back_button\])/mis', '', $html );
738
		}
739
740
		if ( strpos( $html, '[if save_draft]' ) ) {
741
			$html = preg_replace( '/(\[if\s+save_draft\])(.*?)(\[\/if\s+save_draft\])/mis', '', $html );
742
		}
743
744
		if ( apply_filters( 'frm_do_html_shortcodes', true ) ) {
745
			$html = do_shortcode( $html );
746
		}
747
748
		return $html;
749
	}
750
751
	public static function submit_button_label( $submit ) {
752
		if ( ! $submit || empty( $submit ) ) {
753
			$frm_settings = FrmAppHelper::get_settings();
754
			$submit       = $frm_settings->submit_value;
755
		}
756
757
		return $submit;
758
	}
759
760
	/**
761
	 * If the Formidable styling isn't being loaded,
762
	 * use inline styling to hide the element
763
	 *
764
	 * @since 2.03.05
765
	 */
766
	public static function maybe_hide_inline() {
767
		$frm_settings = FrmAppHelper::get_settings();
768
		if ( $frm_settings->load_style == 'none' ) {
769
			echo ' style="display:none;"';
770
		} elseif ( $frm_settings->load_style == 'dynamic' ) {
771
			FrmStylesController::enqueue_style();
772
		}
773
	}
774
775
	public static function get_form_style_class( $form = false ) {
776
		$style = self::get_form_style( $form );
777
		$class = ' with_frm_style';
778
779
		if ( empty( $style ) ) {
780
			if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) ) {
781
				return $class;
782
			} else {
783
				return;
784
			}
785
		}
786
787
		// If submit button needs to be inline or centered.
788
		if ( is_object( $form ) ) {
789
			$form = $form->options;
790
		}
791
792
		$submit_align = isset( $form['submit_align'] ) ? $form['submit_align'] : '';
793
794
		if ( 'inline' === $submit_align ) {
795
			$class .= ' frm_inline_form';
796
			$class .= self::maybe_align_fields_top( $form );
797
		} elseif ( 'center' === $submit_align ) {
798
			$class .= ' frm_center_submit';
799
		}
800
801
		$class = apply_filters( 'frm_add_form_style_class', $class, $style );
802
803
		return $class;
804
	}
805
806
	/**
807
	 * Returns appropriate class if form has top labels
808
	 *
809
	 * @param $form
810
	 *
811
	 * @return string
812
	 */
813
	private static function maybe_align_fields_top( $form ) {
814
		return self::form_has_top_labels( $form ) ? ' frm_inline_top' : '';
815
	}
816
817
	/**
818
	 * Determine if a form has fields with top labels so submit button can be aligned properly
819
	 *
820
	 * @param $form
821
	 *
822
	 * @return bool
823
	 */
824
	private static function form_has_top_labels( $form ) {
825
		if ( ! isset( $form['fields'] ) ) {
826
			return false;
827
		}
828
829
		$fields = $form['fields'];
830
		if ( count( $fields ) <= 0 ) {
831
			return false;
832
		}
833
834
		$fields = array_reverse( $fields ); // start from the fields closest to the submit button
835
		foreach ( $fields as $field ) {
836
			$type      = isset( $field['original_type'] ) ? $field['original_type'] : $field['type'];
837
			$has_input = FrmFieldFactory::field_has_property( $type, 'has_input' );
838
			if ( $has_input ) {
839
				return self::field_has_top_label( $field, $form );
840
			}
841
		}
842
843
		return false;
844
	}
845
846
	/**
847
	 * Check if a field's label position is set to "top"
848
	 *
849
	 * @param $field
850
	 * @param $form
851
	 *
852
	 * @return bool
853
	 */
854
	private static function field_has_top_label( $field, $form ) {
855
		$label_position = FrmFieldsHelper::label_position( $field['label'], $field, $form );
856
857
		return in_array( $label_position, array( 'top', 'inside', 'hidden' ) );
858
	}
859
860
	/**
861
	 * @param object|string|boolean $form
862
	 *
863
	 * @return string
864
	 */
865
	public static function get_form_style( $form ) {
866
		$style = 1;
867
		if ( empty( $form ) || 'default' == 'form' ) {
868
			return $style;
869
		} elseif ( is_object( $form ) && $form->parent_form_id ) {
870
			// get the parent form if this is a child
871
			$form = $form->parent_form_id;
872
		} elseif ( is_array( $form ) && isset( $form['parent_form_id'] ) && $form['parent_form_id'] ) {
873
			$form = $form['parent_form_id'];
874
		} elseif ( is_array( $form ) && isset( $form['custom_style'] ) ) {
875
			$style = $form['custom_style'];
876
		}
877
878
		if ( $form && is_string( $form ) ) {
879
			$form = FrmForm::getOne( $form );
880
		}
881
882
		$style = ( $form && is_object( $form ) && isset( $form->options['custom_style'] ) ) ? $form->options['custom_style'] : $style;
883
884
		return $style;
885
	}
886
887
	/**
888
	 * Display the validation error messages when an entry is submitted
889
	 *
890
	 * @param array $args - includes img, errors
891
	 *
892
	 * @since 2.0.6
893
	 */
894
	public static function show_errors( $args ) {
895
		$invalid_msg = self::get_invalid_error_message( $args );
896
897
		if ( empty( $invalid_msg ) ) {
898
			$show_img = false;
899
		} else {
900
			echo wp_kses_post( $invalid_msg );
901
			$show_img = true;
902
		}
903
904
		self::show_error(
905
			array(
906
				'img'      => $args['img'],
907
				'errors'   => $args['errors'],
908
				'show_img' => $show_img,
909
			)
910
		);
911
	}
912
913
	/**
914
	 * Display the error message in the front-end along with the image if set
915
	 * The image was removed from the styling settings, but it may still be set with a hook
916
	 * If the message in the global settings is empty, show every validation message in the error box
917
	 *
918
	 * @param array $args - includes img, errors, and show_img
919
	 *
920
	 * @since 2.0.6
921
	 */
922
	public static function show_error( $args ) {
923
		// remove any blank messages
924
		$args['errors'] = array_filter( (array) $args['errors'] );
925
926
		$line_break_first = $args['show_img'];
927
		foreach ( $args['errors'] as $error_key => $error ) {
0 ignored issues
show
Bug introduced by
The expression $args['errors'] of type array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
928
			if ( $line_break_first && ! is_numeric( $error_key ) && ( $error_key == 'cptch_number' || strpos( $error_key, 'field' ) === 0 ) ) {
929
				continue;
930
			}
931
932
			$id = str_replace( 'field', 'field_', $error_key );
933
			echo '<div id="' . esc_attr( $id ) . '_error">';
934
935
			if ( $args['show_img'] && ! empty( $args['img'] ) ) {
936
				echo '<img src="' . esc_attr( $args['img'] ) . '" alt="" />';
937
			} else {
938
				$args['show_img'] = true;
939
			}
940
941
			echo wp_kses_post( $error );
942
943
			echo '</div>';
944
		}
945
	}
946
947
	public static function maybe_get_scroll_js( $id ) {
948
		$offset = apply_filters( 'frm_scroll_offset', 4, array( 'form_id' => $id ) );
949
		if ( $offset != - 1 ) {
950
			self::get_scroll_js( $id );
951
		}
952
	}
953
954
	public static function get_scroll_js( $form_id ) {
955
		echo '<script type="text/javascript">document.addEventListener(\'DOMContentLoaded\',function(){frmFrontForm.scrollMsg(' . (int) $form_id . ');})</script>';
956
	}
957
958
	/**
959
	 * @since 3.0
960
	 */
961
	public static function actions_dropdown( $atts ) {
962
		if ( FrmAppHelper::is_admin_page( 'formidable' ) ) {
963
			$status     = $atts['status'];
964
			$form_id    = isset( $atts['id'] ) ? $atts['id'] : FrmAppHelper::get_param( 'id', 0, 'get', 'absint' );
965
			$trash_link = self::delete_trash_info( $form_id, $status );
966
			$links      = self::get_action_links( $form_id, $status );
967
			include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/actions-dropdown.php' );
968
		}
969
	}
970
971
	/**
972
	 * @since 3.0
973
	 */
974
	public static function get_action_links( $form_id, $form ) {
975
		if ( ! is_object( $form ) ) {
976
			$form = FrmForm::getOne( $form_id );
977
		}
978
979
		$actions     = array();
980
		$trash_links = self::delete_trash_links( $form_id );
981
		if ( 'trash' == $form->status ) {
982
			$actions['restore'] = $trash_links['restore'];
983
984
			if ( current_user_can( 'frm_delete_forms' ) ) {
985
				$actions['trash'] = $trash_links['delete'];
986
			}
987
		} elseif ( current_user_can( 'frm_edit_forms' ) ) {
988
			$duplicate_link = '?page=formidable&frm_action=duplicate&id=' . $form_id;
989
			if ( $form->is_template ) {
990
				$actions['frm_duplicate'] = array(
991
					'url'   => wp_nonce_url( $duplicate_link ),
992
					'label' => __( 'Create Form from Template', 'formidable' ),
993
					'icon'  => 'frm_icon_font frm_clone_icon',
994
				);
995
			} else {
996
				$actions['duplicate'] = array(
997
					'url'   => wp_nonce_url( $duplicate_link ),
998
					'label' => __( 'Duplicate Form', 'formidable' ),
999
					'icon'  => 'frm_icon_font frm_clone_icon',
1000
				);
1001
			}
1002
1003
			$actions['trash'] = self::delete_trash_info( $form_id, $form->status );
1004
		}
1005
1006
		return $actions;
1007
	}
1008
1009
	public static function edit_form_link( $form_id ) {
1010
		if ( is_object( $form_id ) ) {
1011
			$form    = $form_id;
1012
			$name    = $form->name;
1013
			$form_id = $form->id;
1014
		} else {
1015
			$name = FrmForm::getName( $form_id );
1016
		}
1017
1018
		if ( $form_id ) {
1019
			$val = '<a href="' . esc_url( FrmForm::get_edit_link( $form_id ) ) . '">' . ( '' == $name ? __( '(no title)', 'formidable' ) : FrmAppHelper::truncate( $name, 40 ) ) . '</a>';
1020
		} else {
1021
			$val = '';
1022
		}
1023
1024
		return $val;
1025
	}
1026
1027
	public static function delete_trash_link( $id, $status, $length = 'label' ) {
1028
		$link_details = self::delete_trash_info( $id, $status );
1029
1030
		return self::format_link_html( $link_details, $length );
1031
	}
1032
1033
	/**
1034
	 * @since 3.0
1035
	 */
1036
	public static function format_link_html( $link_details, $length = 'label' ) {
1037
		$link = '';
1038
		if ( ! empty( $link_details ) ) {
1039
			$link = '<a href="' . esc_url( $link_details['url'] ) . '" class="frm-trash-link"';
1040
			if ( isset( $link_details['data'] ) ) {
1041
				foreach ( $link_details['data'] as $data => $value ) {
1042
					$link .= ' data-' . esc_attr( $data ) . '="' . esc_attr( $value ) . '"';
1043
				}
1044
			} elseif ( isset( $link_details['confirm'] ) ) {
1045
				$link .= ' onclick="return confirm(\'' . esc_attr( $link_details['confirm'] ) . '\')"';
1046
			}
1047
1048
			$label = ( isset( $link_details[ $length ] ) ? $link_details[ $length ] : $link_details['label'] );
1049
			if ( $length == 'icon' && isset( $link_details[ $length ] ) ) {
1050
				$label = '<span class="' . $label . '" title="' . esc_attr( $link_details['label'] ) . '" aria-hidden="true"></span>';
1051
				$link  .= ' aria-label="' . esc_attr( $link_details['label'] ) . '"';
1052
			}
1053
1054
			$link .= '>' . $label . '</a>';
1055
		}
1056
1057
		return $link;
1058
	}
1059
1060
	/**
1061
	 * @since 3.0
1062
	 */
1063
	public static function delete_trash_info( $id, $status ) {
1064
		$labels = self::delete_trash_links( $id );
1065
1066
		if ( 'trash' == $status ) {
1067
			$info = $labels['restore'];
1068
		} elseif ( current_user_can( 'frm_delete_forms' ) ) {
1069
			if ( EMPTY_TRASH_DAYS ) {
1070
				$info = $labels['trash'];
1071
			} else {
1072
				$info = $labels['delete'];
1073
			}
1074
		} else {
1075
			$info = array();
1076
		}
1077
1078
		return $info;
1079
	}
1080
1081
	/**
1082
	 * @since 3.0
1083
	 */
1084
	private static function delete_trash_links( $id ) {
1085
		$current_page = FrmAppHelper::get_simple_request( array( 'param' => 'form_type' ) );
1086
		$base_url     = '?page=formidable&form_type=' . $current_page . '&id=' . $id;
1087
1088
		return array(
1089
			'restore' => array(
1090
				'label' => __( 'Restore from Trash', 'formidable' ),
1091
				'short' => __( 'Restore', 'formidable' ),
1092
				'url'   => wp_nonce_url( $base_url . '&frm_action=untrash', 'untrash_form_' . absint( $id ) ),
1093
			),
1094
			'trash'   => array(
1095
				'label' => __( 'Move Form to Trash', 'formidable' ),
1096
				'short' => __( 'Trash', 'formidable' ),
1097
				'url'   => wp_nonce_url( $base_url . '&frm_action=trash', 'trash_form_' . absint( $id ) ),
1098
				'icon'  => 'frm_icon_font frm_delete_icon',
1099
				'data'  => array( 'frmverify' => __( 'Do you want to move this form to the trash?', 'formidable' ) ),
1100
			),
1101
			'delete'  => array(
1102
				'label'   => __( 'Delete Permanently', 'formidable' ),
1103
				'short'   => __( 'Delete', 'formidable' ),
1104
				'url'     => wp_nonce_url( $base_url . '&frm_action=destroy', 'destroy_form_' . absint( $id ) ),
1105
				'confirm' => __( 'Are you sure you want to delete this form and all its entries?', 'formidable' ),
1106
				'icon'    => 'frm_icon_font frm_delete_icon',
1107
				'data'    => array( 'frmverify' => __( 'This will permanently delete the form and all its entries. This is irreversible. Are you sure you want to continue?', 'formidable' ) ),
1108
			),
1109
		);
1110
	}
1111
1112
	/**
1113
	 * @since 3.0
1114
	 */
1115
	public static function css_classes() {
1116
		$classes = array(
1117
			'frm_total'      => array(
1118
				'label' => __( 'Total', 'formidable' ),
1119
				'title' => __( 'Add this to a read-only field to display the text in bold without a border or background.', 'formidable' ),
1120
			),
1121
			'frm_total_big'  => array(
1122
				'label' => __( 'Big Total', 'formidable' ),
1123
				'title' => __( 'Add this to a read-only field to display the text in large, bold text without a border or background.', 'formidable' ),
1124
			),
1125
			'frm_scroll_box' => array(
1126
				'label' => __( 'Scroll Box', 'formidable' ),
1127
				'title' => __( 'If you have many checkbox or radio button options, you may add this class to allow your user to easily scroll through the options. Or add a scrolling area around content in an HTML field.', 'formidable' ),
1128
			),
1129
			'frm_first'      => array(
1130
				'label' => __( 'First', 'formidable' ),
1131
				'title' => __( 'Add this to the first field in each row along with a width. ie frm_first frm4', 'formidable' ),
1132
			),
1133
			'frm_alignright' => __( 'Right', 'formidable' ),
1134
			'frm_grid_first' => __( 'First Grid Row', 'formidable' ),
1135
			'frm_grid'       => __( 'Even Grid Row', 'formidable' ),
1136
			'frm_grid_odd'   => __( 'Odd Grid Row', 'formidable' ),
1137
			'frm_color_block' => array(
1138
				'label' => __( 'Color Block', 'formidable' ),
1139
				'title' => __( 'Add a background color to the field or section.', 'formidable' ),
1140
			),
1141
			'frm_capitalize' => array(
1142
				'label' => __( 'Capitalize', 'formidable' ),
1143
				'title' => __( 'Automatically capitalize the first letter in each word.', 'formidable' ),
1144
			),
1145
		);
1146
1147
		return apply_filters( 'frm_layout_classes', $classes );
1148
	}
1149
1150
	public static function grid_classes() {
1151
		$base = array(
1152
			'frm_half' => '1/2',
1153
1154
			'frm_third'      => '1/3',
1155
			'frm_two_thirds' => '2/3',
1156
1157
			'frm_fourth'        => '1/4',
1158
			'frm_three_fourths' => '3/4',
1159
		);
1160
1161
		$frm_settings = FrmAppHelper::get_settings();
1162
		if ( $frm_settings->old_css ) {
1163
			$classes = array(
1164
				'frm_sixth' => '1/6',
1165
				'frm10'     => '5/6',
1166
1167
				'frm_full' => '100%',
1168
			);
1169
		} else {
1170
			$classes = array(
1171
				'frm_sixth' => '1/6',
1172
				'frm10'     => '5/6',
1173
				'frm12' => '100%',
1174
			);
1175
		}
1176
1177
		return array_merge( $base, $classes );
1178
	}
1179
1180
	/**
1181
	 * @since 3.0
1182
	 */
1183
	public static function style_class_label( $style, $class ) {
1184
		$label = '';
1185
		if ( empty( $style ) ) {
1186
			$label = $class;
1187
		} elseif ( ! is_array( $style ) ) {
1188
			$label = $style;
1189
		} elseif ( isset( $style['label'] ) ) {
1190
			$label = $style['label'];
1191
		}
1192
1193
		return $label;
1194
	}
1195
1196
	public static function status_nice_name( $status ) {
1197
		$nice_names = array(
1198
			'draft'   => __( 'Draft', 'formidable' ),
1199
			'trash'   => __( 'Trash', 'formidable' ),
1200
			'publish' => __( 'Published', 'formidable' ),
1201
		);
1202
1203
		if ( ! in_array( $status, array_keys( $nice_names ) ) ) {
1204
			$status = 'publish';
1205
		}
1206
1207
		$name = $nice_names[ $status ];
1208
1209
		return $name;
1210
	}
1211
1212
	public static function template_icon( $categories ) {
1213
		$ignore     = self::ignore_template_categories();
1214
		$categories = array_diff( $categories, $ignore );
1215
1216
		$icons = array(
1217
			'WooCommerce'         => array( 'woocommerce', 'var(--purple)' ),
1218
			'Post'                => array( 'wordpress', 'rgb(0,160,210)' ),
1219
			'User Registration'   => array( 'register', 'var(--pink)' ),
1220
			'PayPal'              => array( 'paypal' ),
1221
			'Stripe'              => array( 'credit_card', 'var(--green)' ),
1222
			'Twilio'              => array( 'sms', 'rgb(0,160,210)' ),
1223
			'Payment'             => array( 'credit_card', 'var(--green)' ),
1224
			'Health and Wellness' => array( 'heart', 'var(--pink)' ),
1225
			'Event Planning'      => array( 'calendar', 'var(--orange)' ),
1226
			'Real Estate'         => array( 'house', 'var(--purple)' ),
1227
			'Calculator'          => array( 'calculator', 'var(--purple)' ),
1228
			'Registrations'       => array( 'address_card' ),
1229
			'Customer Service'    => array( 'users_solid', 'var(--pink)' ),
1230
			'Education'           => array( 'pencil', 'var(--primary-color)' ),
1231
			'Marketing'           => array( 'eye', 'rgb(0,160,210)' ),
1232
			'Feedback'            => array( 'smile', 'var(--green)' ),
1233
			'Business Operations' => array( 'case' ),
1234
			'Contact Form'        => array( 'email' ),
1235
			'Survey'              => array( 'comment', 'var(--primary-color)' ),
1236
			'Application Form'    => array( 'align_right', 'rgb(0,160,210)' ),
1237
			''                    => array( 'align_right' ),
1238
		);
1239
1240
		$icons[ __( 'My Templates', 'formidable' ) ] = array( 'user', 'var(--orange)' );
1241
1242
		$icon = $icons[''];
1243
1244
		if ( count( $categories ) === 1 ) {
1245
			$category = reset( $categories );
1246
			$icon     = isset( $icons[ $category ] ) ? $icons[ $category ] : $icon;
1247
		} elseif ( ! empty( $categories ) ) {
1248
			foreach ( $icons as $cat => $icon ) {
1249
				if ( ! in_array( $cat, $categories ) ) {
1250
					unset( $icons[ $cat ] );
1251
				}
1252
			}
1253
			$icon = reset( $icons );
1254
		}
1255
1256
		echo '<span class="frm-inner-circle" ' . ( isset( $icon[1] ) ? 'style="background-color:' . esc_attr( $icon[1] ) : '' ) . '">';
1257
		FrmAppHelper::icon_by_class( 'frmfont frm_' . $icon[0] . '_icon' );
1258
		echo '<span class="frm_hidden">';
1259
		FrmAppHelper::icon_by_class( 'frmfont frm_lock_icon' );
1260
		echo '</span>';
1261
		echo '</span>';
1262
	}
1263
1264
	/**
1265
	 * @since 4.03.01
1266
	 */
1267
	public static function ignore_template_categories() {
1268
		return array( 'Business', 'Elite', 'Personal', 'Creator', 'Basic', 'free' );
1269
	}
1270
1271
	/**
1272
	 * @since 4.02
1273
	 */
1274
	public static function get_template_install_link( $template, $args ) {
1275
		$defaults = array(
1276
			'class' => 'install-now',
1277
			'href'  => 'href',
1278
			'atts'  => true,
1279
		);
1280
1281
		if ( ! empty( $template['url'] ) ) {
1282
			$link = array(
1283
				'url'   => $template['url'],
1284
				'label' => __( 'Create Form', 'formidable' ),
1285
				'class' => 'frm-install-template',
1286
				'href'  => 'rel',
1287
				'atts'  => '',
1288
			);
1289
		} elseif ( self::plan_is_allowed( $args ) ) {
1290
			$link = array(
1291
				'url'   => FrmAppHelper::admin_upgrade_link( 'addons', 'account/downloads/' ) . '&utm_content=' . $template['slug'],
1292
				'label' => __( 'Renew', 'formidable' ),
1293
			);
1294
		} else {
1295
			$link = array(
1296
				'url'   => $args['pricing'],
1297
				'label' => __( 'Upgrade', 'formidable' ),
1298
			);
1299
		}
1300
1301
		return array_merge( $defaults, $link );
1302
	}
1303
1304
	/**
1305
	 * Is the template included with the license type?
1306
	 *
1307
	 * @since 4.02.02
1308
	 *
1309
	 * @param array $args
1310
	 *
1311
	 * @return bool
1312
	 */
1313
	public static function plan_is_allowed( $args ) {
1314
		if ( empty( $args['license_type'] ) ) {
1315
			return false;
1316
		}
1317
1318
		$included = $args['license_type'] === strtolower( $args['plan_required'] );
1319
1320
		$plans = array( 'free', 'personal', 'business', 'elite' );
1321
		if ( $included || ! in_array( strtolower( $args['plan_required'] ), $plans, true ) ) {
1322
			return $included;
1323
		}
1324
1325
		foreach ( $plans as $plan ) {
1326
			if ( $included || $plan === $args['license_type'] ) {
1327
				break;
1328
			}
1329
			$included = $plan === strtolower( $args['plan_required'] );
1330
		}
1331
1332
		return $included;
1333
	}
1334
1335
	/**
1336
	 * @since 4.02
1337
	 */
1338
	public static function template_install_html( $link, $class = '' ) {
1339
		$link['class'] .= ' ' . $class;
1340
		echo '<a ' . esc_attr( $link['href'] ) . '="' . esc_url( $link['url'] ) . '" class="' . esc_attr( $link['class'] ) . ' " aria-label="' . esc_attr( $link['label'] ) . '"' . ( $link['atts'] ? ' target="_blank" rel="noopener"' : '' ) . '>';
1341
	}
1342
1343
	/**
1344
	 * If a template or add-on cannot be installed, show a message
1345
	 * about which plan is required.
1346
	 *
1347
	 * @since 4.0
1348
	 */
1349
	public static function show_plan_required( $requires, $link ) {
1350
		if ( empty( $requires ) ) {
1351
			return;
1352
		}
1353
1354
		?>
1355
		<p class="frm_plan_required">
1356
			<?php esc_html_e( 'License plan required:', 'formidable' ); ?>
1357
			<a href="<?php echo esc_url( $link ); ?>" target="_blank" rel="noopener">
1358
				<?php echo esc_html( $requires ); ?>
1359
			</a>
1360
		</p>
1361
		<?php
1362
	}
1363
1364
	/**
1365
	 * @since 4.0
1366
	 */
1367
	public static function get_plan_required( &$item ) {
1368
		if ( ! isset( $item['categories'] ) || ! empty( $item['url'] ) ) {
1369
			return false;
1370
		}
1371
1372
		$plans = array( 'free', 'Basic', 'Personal', 'Business', 'Elite' );
1373
1374
		foreach ( $item['categories'] as $k => $category ) {
1375
			if ( in_array( $category, $plans, true ) ) {
1376
				unset( $item['categories'][ $k ] );
1377
1378
				if ( $category === 'Personal' ) {
1379
					// Show the current package name.
1380
					$category = 'Basic';
1381
				}
1382
1383
				return $category;
1384
			}
1385
		}
1386
1387
		return false;
1388
	}
1389
1390
	/**
1391
	 * Checks for warnings to be displayed after form settings are saved.
1392
	 *
1393
	 * @since 4.04
1394
	 *
1395
	 * @param array $values The $_POST array, which contains values submitted in a form.
1396
	 *
1397
	 * @return array An array of warnings or an empty array.
1398
	 */
1399
	public static function check_for_warnings( $values ) {
1400
		$warnings = array();
1401
1402
		$redirect_warning = self::check_redirect_url_for_unsafe_params( $values );
1403
1404
		if ( $redirect_warning ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_warning of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1405
			$warnings[] = $redirect_warning;
1406
		}
1407
1408
		return apply_filters( 'frm_check_for_warnings', $warnings, $values );
1409
	}
1410
1411
	/**
1412
	 * Checks the redirect URL for params whose names are reserved words.
1413
	 *
1414
	 * @since 4.04
1415
	 *
1416
	 * @param array $values The $_POST array, which contains the values submitted in a form.
1417
	 *
1418
	 * @return bool|string A warning message about unsafe params or false.
1419
	 */
1420
	private static function check_redirect_url_for_unsafe_params( $values ) {
1421
		if ( ! isset( $values['options'] ) ) {
1422
			return false;
1423
		}
1424
1425
		$options = $values['options'];
1426
		FrmAppHelper::sanitize_with_html( $options );
1427
1428
		if ( ( ! isset( $options['success_action'] ) ) || $options['success_action'] !== 'redirect' || ! isset( $options['success_url'] ) ) {
1429
			return false;
1430
		}
1431
1432
		$unsafe_params_in_redirect = self::get_unsafe_params( $options['success_url'] );
1433
1434
		return self::create_unsafe_param_warning( $unsafe_params_in_redirect );
1435
	}
1436
1437
	/**
1438
	 * Returns an array of params whose names are reserved words in the specified URL.
1439
	 *
1440
	 * @since 4.04
1441
	 *
1442
	 * @param string $url The URL whose params are being checked.
1443
	 *
1444
	 * @return array An array of params whose names are reserved words or an empty array.
1445
	 */
1446
	private static function get_unsafe_params( $url ) {
1447
		$redirect_components = parse_url( $url );
1448
		if ( empty( $redirect_components['query'] ) ) {
1449
			return array();
1450
		}
1451
		parse_str( $redirect_components['query'], $redirect_params );
1452
		$redirect_param_names      = array_keys( $redirect_params );
1453
		$reserved_words            = self::reserved_words();
1454
		$unsafe_params_in_redirect = array_intersect( $redirect_param_names, $reserved_words );
1455
1456
		return array_values( $unsafe_params_in_redirect );
1457
	}
1458
1459
	/**
1460
	 * Returns a warning if reserved words have been used as param names in the redirect URL.
1461
	 *
1462
	 * @since 4.04
1463
	 *
1464
	 * @param array $unsafe_params_in_redirect Array of params from the redirect URL whose names are reserved words.
1465
	 *
1466
	 * @return bool|string A string with an unsafe param message or false.
1467
	 */
1468
	private static function create_unsafe_param_warning( $unsafe_params_in_redirect ) {
1469
		$count                = count( $unsafe_params_in_redirect );
1470
		$caution              = esc_html__( 'Is this intentional?', 'formidable' );
1471
		$reserved_words_intro = esc_html__( 'See the list of reserved words in WordPress.', 'formidable' );
1472
		$reserved_words_link  = '<a href="https://codex.wordpress.org/WordPress_Query_Vars" target="_blank"> ' . $reserved_words_intro . '</a>';
1473
1474
		if ( $count === 0 ) {
1475
			return false;
1476
		}
1477
1478
		if ( $count == 1 ) {
1479
			/* translators: %s: the name of a single parameter in the redirect URL */
1480
			return sprintf( esc_html__( 'The redirect URL is using the parameter "%s", which is reserved by WordPress. ', 'formidable' ), $unsafe_params_in_redirect[0] ) . $caution . $reserved_words_link;
1481
		}
1482
1483
		$unsafe_params_string = implode( '", "', $unsafe_params_in_redirect );
1484
1485
		/* translators: %s: the names of two or more parameters in the redirect URL, separated by commas */
1486
		return sprintf( esc_html__( 'The redirect URL is using the parameters "%s", which are reserved by WordPress. ', 'formidable' ), $unsafe_params_string ) . $caution . $reserved_words_link;
1487
	}
1488
1489
	/**
1490
	 * Returns an array of common reserved words in WordPress.
1491
	 *
1492
	 * An edited list of reserved terms from the Codex.
1493
	 * https://codex.wordpress.org/Reserved_Terms
1494
	 *
1495
	 * @since 4.04
1496
	 *
1497
	 * @return array Array of WordPress reserved words.
1498
	 */
1499
	public static function reserved_words() {
1500
		return array(
1501
			'id',
1502
			'attachment',
1503
			'author',
1504
			'author_name',
1505
			'calendar',
1506
			'cat',
1507
			'category',
1508
			'category_name',
1509
			'cpage',
1510
			'custom',
1511
			'day',
1512
			'date',
1513
			'error',
1514
			'feed',
1515
			'hour',
1516
			'm',
1517
			'minute',
1518
			'more',
1519
			'name',
1520
			'order',
1521
			'p',
1522
			'page',
1523
			'page_id',
1524
			'paged',
1525
			'pb',
1526
			'post',
1527
			'posts',
1528
			'preview',
1529
			's',
1530
			'search',
1531
			'second',
1532
			'sentence',
1533
			'tag',
1534
			'taxonomy',
1535
			'tb',
1536
			'term',
1537
			'terms',
1538
			'theme',
1539
			'title',
1540
			'type',
1541
			'w',
1542
			'year',
1543
		);
1544
	}
1545
1546
	/**
1547
	 * Check an array of templates, determine how many the logged in user can use
1548
	 *
1549
	 * @param array $templates
1550
	 * @param array $args
1551
	 * @return int
1552
	 */
1553
	public static function available_count( $templates, $args ) {
1554
		return array_reduce(
1555
			$templates,
1556
			function( $total, $template ) use ( $args ) {
1557
				if ( ! empty( $template['url'] ) ) {
1558
					return $total + 1;
1559
				}
1560
1561
				$args['plan_required'] = self::get_plan_required( $template );
1562
				if ( self::plan_is_allowed( $args ) ) {
1563
					return $total + 1;
1564
				}
1565
1566
				return $total;
1567
			},
1568
			0
1569
		);
1570
	}
1571
}
1572