Completed
Push — master ( 023e44...95bd05 )
by Stephanie
02:26
created

FrmFormsHelper   F

Complexity

Total Complexity 248

Size/Duplication

Total Lines 1332
Duplicated Lines 1.73 %

Coupling/Cohesion

Components 3
Dependencies 9

Importance

Changes 0
Metric Value
dl 23
loc 1332
rs 0.8
c 0
b 0
f 0
wmc 248
lcom 3
cbo 9

54 Methods

Rating   Name   Duplication   Size   Complexity  
A form_error_class() 0 3 1
A get_direct_link() 0 6 1
B forms_dropdown() 0 41 8
A add_html_attr() 0 5 2
F form_switcher() 13 99 22
A builder_submit_button() 0 3 1
A get_sortable_classes() 0 4 4
A get_field_link_name() 0 9 2
A get_field_link_icon() 0 9 3
A get_invalid_error_message() 0 10 2
A get_success_message() 0 7 1
B setup_new_vars() 10 46 10
A setup_edit_vars() 0 13 4
D fill_default_opts() 0 30 24
A get_default_opts() 0 19 1
A fill_form_options() 0 7 3
A get_default_html() 0 22 3
A get_draft_link() 0 5 1
A get_custom_submit() 0 25 4
B html_shortcodes() 0 82 1
B insert_opt_html() 0 34 8
A insert_code_html() 0 24 3
A prepare_field_type() 0 8 2
B auto_add_end_section_fields() 0 50 9
A maybe_create_end_section() 0 18 3
C replace_shortcodes() 0 49 12
A submit_button_label() 0 8 3
A maybe_hide_inline() 0 8 3
B get_form_style_class() 0 30 7
A maybe_align_fields_top() 0 3 2
B form_has_top_labels() 0 21 6
A field_has_top_label() 0 5 1
C get_form_style() 0 21 15
A show_errors() 0 18 2
B show_error() 0 24 8
A maybe_get_scroll_js() 0 6 2
A get_scroll_js() 0 3 1
A actions_dropdown() 0 9 3
B get_action_links() 0 34 6
A edit_form_link() 0 17 4
A delete_trash_link() 0 5 1
B format_link_html() 0 23 8
A delete_trash_info() 0 17 4
A delete_trash_links() 0 27 1
A css_classes() 0 26 1
A grid_classes() 0 29 2
A style_class_label() 0 12 4
A status_nice_name() 0 15 2
B template_icon() 0 39 6
A get_template_install_link() 0 29 4
B plan_is_allowed() 0 14 7
A template_install_html() 0 4 2
A show_plan_required() 0 14 2
A get_plan_required() 0 16 6

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 FrmFormsHelper 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 FrmFormsHelper, 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 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_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
		?>
116
		<div id="frm_bs_dropdown" class="dropdown <?php echo esc_attr( is_rtl() ? 'pull-right' : 'pull-left' ); ?>">
117
			<a href="#" id="frm-navbarDrop" class="frm-dropdown-toggle" data-toggle="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
					<?php FrmAppHelper::icon_by_class( 'frmfont frm_arrowdown4_icon', array( 'aria-hidden' => 'true' ) ); ?>
123
				</h1>
124
			</a>
125
			<ul class="frm-dropdown-menu frm-on-top frm-inline-modal frm_code_list frm-full-hover" role="menu" aria-labelledby="frm-navbarDrop">
126 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...
127
				<li class="frm-with-search">
128
					<?php
129
					FrmAppHelper::show_search_box(
130
						array(
131
							'input_id'    => 'dropform',
132
							'placeholder' => __( 'Search Forms', 'formidable' ),
133
							'tosearch'    => 'frm-dropdown-form',
134
						)
135
					);
136
					?>
137
				</li>
138
				<?php } ?>
139
				<?php
140
				foreach ( $forms as $form ) {
141
					if ( $form->id === $form_id ) {
142
						// Don't include the selected form in the switcher since it does nothing.
143
						continue;
144
					}
145
146
					if ( isset( $args['id'] ) ) {
147
						$args['id'] = $form->id;
148
					}
149
					if ( isset( $args['form'] ) ) {
150
						$args['form'] = $form->id;
151
					}
152
153
					$url       = isset( $base ) ? add_query_arg( $args, $base ) : add_query_arg( $args );
154
					$form_name = empty( $form->name ) ? __( '(no title)', 'formidable' ) : $form->name;
155
					?>
156
					<li class="frm-dropdown-form">
157
						<a href="<?php echo esc_url( $url ); ?>" tabindex="-1">
158
							<span class="frm-sub-label">
159
							<?php
160
							printf(
161
								/* translators: %d: Form ID */
162
								esc_html__( '(ID %d)', 'formidable' ),
163
								esc_attr( $form->id )
164
							);
165
							?>
166
							</span>
167
							<?php echo esc_html( $form_name ); ?>
168
							<span class="frm_hidden"><?php echo esc_html( $form->form_key ); ?></span>
169
						</a>
170
					</li>
171
					<?php
172
					unset( $form );
173
				}
174
				?>
175
			</ul>
176
		</div>
177
		<?php
178
	}
179
180
	/**
181
	 * @since 3.05
182
	 * @deprecated 4.0
183
	 *
184
	 * @param array $values - The form array
185
	 */
186
	public static function builder_submit_button( $values ) {
187
		FrmDeprecated::builder_submit_button( $values );
188
	}
189
190
	public static function get_sortable_classes( $col, $sort_col, $sort_dir ) {
191
		echo ( $sort_col == $col ) ? 'sorted' : 'sortable';
192
		echo ( $sort_col == $col && $sort_dir == 'desc' ) ? ' asc' : ' desc';
193
	}
194
195
	/**
196
	 * @since 3.0
197
	 */
198
	public static function get_field_link_name( $field_type ) {
199
		if ( is_array( $field_type ) ) {
200
			$field_label = $field_type['name'];
201
		} else {
202
			$field_label = $field_type;
203
		}
204
205
		return $field_label;
206
	}
207
208
	/**
209
	 * @since 3.0
210
	 */
211
	public static function get_field_link_icon( $field_type ) {
212
		if ( is_array( $field_type ) && isset( $field_type['icon'] ) ) {
213
			$icon = $field_type['icon'];
214
		} else {
215
			$icon = 'frm_icon_font frm_pencil_icon';
216
		}
217
218
		return $icon;
219
	}
220
221
	/**
222
	 * Get the invalid form error message
223
	 *
224
	 * @since 2.02.07
225
	 *
226
	 * @param array $args
227
	 *
228
	 * @return string
229
	 */
230
	public static function get_invalid_error_message( $args ) {
231
		$settings_args = $args;
232
		if ( isset( $args['form'] ) ) {
233
			$settings_args['current_form'] = $args['form']->id;
234
		}
235
236
		$frm_settings = FrmAppHelper::get_settings( $settings_args );
237
		$invalid_msg = do_shortcode( $frm_settings->invalid_msg );
238
		return apply_filters( 'frm_invalid_error_message', $invalid_msg, $args );
239
	}
240
241
	public static function get_success_message( $atts ) {
242
		$message = apply_filters( 'frm_content', $atts['message'], $atts['form'], $atts['entry_id'] );
243
		$message = FrmAppHelper::use_wpautop( do_shortcode( $message ) );
244
		$message = '<div class="' . esc_attr( $atts['class'] ) . '">' . $message . '</div>';
245
246
		return $message;
247
	}
248
249
	/**
250
	 * Used when a form is created
251
	 */
252
	public static function setup_new_vars( $values = array() ) {
253
		global $wpdb;
254
255
		if ( ! empty( $values ) ) {
256
			$post_values = $values;
257
		} else {
258
			$values      = array();
259
			$post_values = isset( $_POST ) ? $_POST : array();
260
		}
261
262
		$defaults = array(
263
			'name'        => '',
264
			'description' => '',
265
		);
266 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...
267
			if ( ! isset( $values[ $var ] ) ) {
268
				$values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
269
			}
270
		}
271
272
		$values['description'] = FrmAppHelper::use_wpautop( $values['description'] );
273
274
		$defaults = array(
275
			'form_id'        => '',
276
			'logged_in'      => '',
277
			'editable'       => '',
278
			'is_template'    => 0,
279
			'status'         => 'published',
280
			'parent_form_id' => 0,
281
		);
282 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...
283
			if ( ! isset( $values[ $var ] ) ) {
284
				$values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
285
			}
286
		}
287
		unset( $defaults );
288
289
		if ( ! isset( $values['form_key'] ) ) {
290
			$values['form_key'] = ( $post_values && isset( $post_values['form_key'] ) ) ? $post_values['form_key'] : FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_forms', 'form_key' );
291
		}
292
293
		$values                 = self::fill_default_opts( $values, false, $post_values );
294
		$values['custom_style'] = FrmAppHelper::custom_style_value( $post_values );
295
296
		return apply_filters( 'frm_setup_new_form_vars', $values );
297
	}
298
299
	/**
300
	 * Used when editing a form
301
	 */
302
	public static function setup_edit_vars( $values, $record, $post_values = array() ) {
303
		if ( empty( $post_values ) ) {
304
			$post_values = wp_unslash( $_POST );
305
		}
306
307
		$values['form_key']    = isset( $post_values['form_key'] ) ? $post_values['form_key'] : $record->form_key;
308
		$values['is_template'] = isset( $post_values['is_template'] ) ? $post_values['is_template'] : $record->is_template;
309
		$values['status']      = $record->status;
310
311
		$values = self::fill_default_opts( $values, $record, $post_values );
312
313
		return apply_filters( 'frm_setup_edit_form_vars', $values );
314
	}
315
316
	public static function fill_default_opts( $values, $record, $post_values ) {
317
318
		$defaults = self::get_default_opts();
319
		foreach ( $defaults as $var => $default ) {
320
			if ( is_array( $default ) ) {
321
				if ( ! isset( $values[ $var ] ) ) {
322
					$values[ $var ] = ( $record && isset( $record->options[ $var ] ) ) ? $record->options[ $var ] : array();
323
				}
324
325
				foreach ( $default as $k => $v ) {
326
					$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 );
327
328
					if ( is_array( $v ) ) {
329
						foreach ( $v as $k1 => $v1 ) {
330
							$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 );
331
							unset( $k1, $v1 );
332
						}
333
					}
334
335
					unset( $k, $v );
336
				}
337
			} else {
338
				$values[ $var ] = ( $post_values && isset( $post_values['options'][ $var ] ) ) ? $post_values['options'][ $var ] : ( ( $record && isset( $record->options[ $var ] ) ) ? $record->options[ $var ] : $default );
339
			}
340
341
			unset( $var, $default );
342
		}
343
344
		return $values;
345
	}
346
347
	public static function get_default_opts() {
348
		$frm_settings = FrmAppHelper::get_settings();
349
350
		return array(
351
			'submit_value'   => $frm_settings->submit_value,
352
			'success_action' => 'message',
353
			'success_msg'    => $frm_settings->success_msg,
354
			'show_form'      => 0,
355
			'akismet'        => '',
356
			'no_save'        => 0,
357
			'ajax_load'      => 0,
358
			'js_validate'    => 0,
359
			'form_class'     => '',
360
			'custom_style'   => 1,
361
			'before_html'    => self::get_default_html( 'before' ),
362
			'after_html'     => '',
363
			'submit_html'    => self::get_default_html( 'submit' ),
364
		);
365
	}
366
367
	/**
368
	 * @param array $options
369
	 * @param array $values
370
	 *
371
	 * @since 2.0.6
372
	 */
373
	public static function fill_form_options( &$options, $values ) {
374
		$defaults = self::get_default_opts();
375
		foreach ( $defaults as $var => $default ) {
376
			$options[ $var ] = isset( $values['options'][ $var ] ) ? $values['options'][ $var ] : $default;
377
			unset( $var, $default );
378
		}
379
	}
380
381
	/**
382
	 * @param string $loc
383
	 */
384
	public static function get_default_html( $loc ) {
385
		if ( $loc == 'submit' ) {
386
			$draft_link   = self::get_draft_link();
387
			$default_html = <<<SUBMIT_HTML
388
<div class="frm_submit">
389
[if back_button]<button type="submit" name="frm_prev_page" formnovalidate="formnovalidate" class="frm_prev_page" [back_hook]>[back_label]</button>[/if back_button]
390
<button class="frm_button_submit" type="submit"  [button_action]>[button_label]</button>
391
$draft_link
392
</div>
393
SUBMIT_HTML;
394
		} elseif ( $loc == 'before' ) {
395
			$default_html = <<<BEFORE_HTML
396
<legend class="frm_screen_reader">[form_name]</legend>
397
[if form_name]<h3 class="frm_form_title">[form_name]</h3>[/if form_name]
398
[if form_description]<div class="frm_description">[form_description]</div>[/if form_description]
399
BEFORE_HTML;
400
		} else {
401
			$default_html = '';
402
		}
403
404
		return $default_html;
405
	}
406
407
	public static function get_draft_link() {
408
		$link = '[if save_draft]<a href="#" tabindex="0" class="frm_save_draft" [draft_hook]>[draft_label]</a>[/if save_draft]';
409
410
		return $link;
411
	}
412
413
	public static function get_custom_submit( $html, $form, $submit, $form_action, $values ) {
414
		$button = self::replace_shortcodes( $html, $form, $submit, $form_action, $values );
415
		if ( ! strpos( $button, '[button_action]' ) ) {
416
			echo $button; // WPCS: XSS ok.
417
418
			return;
419
		}
420
421
		$button_parts = explode( '[button_action]', $button );
422
423
		$classes = apply_filters( 'frm_submit_button_class', array(), $form );
424
		if ( ! empty( $classes ) ) {
425
			$classes      = implode( ' ', $classes );
426
			$button_class = ' class="frm_button_submit';
427
			if ( strpos( $button_parts[0], $button_class ) !== false ) {
428
				$button_parts[0] = str_replace( $button_class, $button_class . ' ' . esc_attr( $classes ), $button_parts[0] );
429
			} else {
430
				$button_parts[0] .= ' class="' . esc_attr( $classes ) . '"';
431
			}
432
		}
433
434
		echo $button_parts[0]; // WPCS: XSS ok.
435
		do_action( 'frm_submit_button_action', $form, $form_action );
436
		echo $button_parts[1]; // WPCS: XSS ok.
437
	}
438
439
	/**
440
	 * @since 4.0
441
	 */
442
	public static function html_shortcodes() {
443
		$codes = array(
444
			'id'             => array(
445
				'label' => __( 'Field ID', 'formidable' ),
446
				'class' => 'show_field_custom_html',
447
			),
448
			'key'            => array(
449
				'label' => __( 'Field Key', 'formidable' ),
450
				'class' => 'show_field_custom_html',
451
			),
452
			'field_name'     => array(
453
				'label' => __( 'Field Name', 'formidable' ),
454
				'class' => 'show_field_custom_html',
455
			),
456
			'description'    => array(
457
				'label' => __( 'Field Description', 'formidable' ),
458
				'class' => 'show_field_custom_html',
459
			),
460
			'label_position' => array(
461
				'label' => __( 'Label Position', 'formidable' ),
462
				'class' => 'show_field_custom_html',
463
			),
464
			'required_label' => array(
465
				'label' => __( 'Required Label', 'formidable' ),
466
				'class' => 'show_field_custom_html',
467
			),
468
			'input'          => array(
469
				'label' => __( 'Input Field', 'formidable' ),
470
				'class' => 'show_field_custom_html',
471
			),
472
			'input opt=1'    => array(
473
				'label' => __( 'Single Option', 'formidable' ),
474
				'title' => __( 'Show a single radio or checkbox option by replacing 1 with the order of the option', 'formidable' ),
475
				'class' => 'show_field_custom_html',
476
			),
477
			'input label=0'  => array(
478
				'label' => __( 'Hide Option Label', 'formidable' ),
479
				'class' => 'show_field_custom_html',
480
			),
481
			'required_class' => array(
482
				'label' => __( 'Required Class', 'formidable' ),
483
				'title' => __( 'Add class name if field is required', 'formidable' ),
484
				'class' => 'show_field_custom_html',
485
			),
486
			'error_class'    => array(
487
				'label' => __( 'Error Class', 'formidable' ),
488
				'title' => __( 'Add class name if field has an error on form submit', 'formidable' ),
489
				'class' => 'show_field_custom_html',
490
			),
491
492
			'form_name'        => array(
493
				'label' => __( 'Form Name', 'formidable' ),
494
				'class' => 'show_before_html show_after_html',
495
			),
496
			'form_description' => array(
497
				'label' => __( 'Form Description', 'formidable' ),
498
				'class' => 'show_before_html show_after_html',
499
			),
500
			'form_key'         => array(
501
				'label' => __( 'Form Key', 'formidable' ),
502
				'class' => 'show_before_html show_after_html',
503
			),
504
			'deletelink'       => array(
505
				'label' => __( 'Delete Entry Link', 'formidable' ),
506
				'class' => 'show_before_html show_after_html',
507
			),
508
509
			'button_label' => array(
510
				'label' => __( 'Button Label', 'formidable' ),
511
				'class' => 'show_submit_html',
512
			),
513
			'button_action' => array(
514
				'label' => __( 'Button Hook', 'formidable' ),
515
				'class' => 'show_submit_html',
516
			),
517
		);
518
519
		/**
520
		 * @since 4.0
521
		 */
522
		return apply_filters( 'frm_html_codes', $codes );
523
	}
524
525
	/**
526
	 * @since 4.0
527
	 * @param array $args
528
	 */
529
	public static function insert_opt_html( $args ) {
530
		$class  = isset( $args['class'] ) ? $args['class'] : '';
531
		$fields = FrmField::all_field_selection();
532
		$field  = isset( $fields[ $args['type'] ] ) ? $fields[ $args['type'] ] : array();
533
534
		self::prepare_field_type( $field );
535
536
		if ( ! isset( $field['icon'] ) ) {
537
			$field['icon'] = 'frmfont frm_pencil_icon';
538
		}
539
540
		$possible_email_field = FrmFieldFactory::field_has_property( $args['type'], 'holds_email_values' );
541
		if ( $possible_email_field ) {
542
			$class .= ' show_frm_not_email_to';
543
		}
544
		?>
545
		<li class="<?php echo esc_attr( $class ); ?>">
546
			<a href="javascript:void(0)" class="frmids frm_insert_code"
547
				data-code="<?php echo esc_attr( $args['id'] ); ?>">
548
				<span>[<?php echo esc_attr( isset( $args['id_label'] ) ? $args['id_label'] : $args['id'] ); ?>]</span>
549
				<?php FrmAppHelper::icon_by_class( $field['icon'], array( 'aria-hidden' => 'true' ) ); ?>
550
				<?php echo esc_attr( FrmAppHelper::truncate( $args['name'], 60 ) ); ?>
551
			</a>
552
			<a href="javascript:void(0)" class="frmkeys frm_insert_code frm_hidden"
553
				data-code="<?php echo esc_attr( $args['key'] ); ?>">
554
				<span>[<?php echo esc_attr( FrmAppHelper::truncate( isset( $args['key_label'] ) ? $args['key_label'] : $args['key'], 7 ) ); ?>]</span>
555
				<?php if ( isset( $field['icon'] ) ) { ?>
556
					<?php FrmAppHelper::icon_by_class( $field['icon'], array( 'aria-hidden' => 'true' ) ); ?>
557
				<?php } ?>
558
				<?php echo esc_attr( FrmAppHelper::truncate( $args['name'], 60 ) ); ?>
559
			</a>
560
		</li>
561
		<?php
562
	}
563
564
	/**
565
	 * @since 4.0
566
	 * @param array $args
567
	 */
568
	public static function insert_code_html( $args ) {
569
		$defaults = array(
570
			'class' => '',
571
			'code'  => '',
572
			'label' => '',
573
			'title' => '',
574
		);
575
576
		$args        = array_merge( $defaults, $args );
577
		$has_tooltip = ! empty( $args['title'] );
578
579
		?>
580
		<li class="<?php echo esc_attr( $args['class'] ); ?>">
581
			<a href="javascript:void(0)" class="frm_insert_code <?php echo $has_tooltip ? 'frm_help' : ''; ?>"
582
				<?php echo $has_tooltip ? 'title="' . esc_attr( $args['title'] ) . '"' : ''; ?>
583
				data-code="<?php echo esc_attr( $args['code'] ); ?>">
584
				<span>
585
					[<?php echo esc_attr( FrmAppHelper::truncate( $args['code'], 10 ) ); ?>]
586
				</span>
587
				<?php echo esc_attr( FrmAppHelper::truncate( $args['label'], 60 ) ); ?>
588
			</a>
589
		</li>
590
		<?php
591
	}
592
593
	/**
594
	 * Some field types in add-ons may have been added with only
595
	 * a field type and name.
596
	 *
597
	 * @since 4.0
598
	 */
599
	public static function prepare_field_type( &$field ) {
600
		if ( ! is_array( $field ) ) {
601
			$field = array(
602
				'name' => $field,
603
				'icon' => 'frm_icon_font frm_pencil_icon',
604
			);
605
		}
606
	}
607
608
	/**
609
	 * Automatically add end section fields if they don't exist (2.0 migration)
610
	 *
611
	 * @since 2.0
612
	 *
613
	 * @param boolean $reset_fields
614
	 */
615
	public static function auto_add_end_section_fields( $form, $fields, &$reset_fields ) {
616
		if ( empty( $fields ) ) {
617
			return;
618
		}
619
620
		$end_section_values = apply_filters( 'frm_before_field_created', FrmFieldsHelper::setup_new_vars( 'end_divider', $form->id ) );
621
		$open               = false;
622
		$prev_order         = false;
623
		$add_order          = 0;
624
		$last_field         = false;
625
		foreach ( $fields as $field ) {
626
			if ( $prev_order === $field->field_order ) {
627
				$add_order ++;
628
			}
629
630
			if ( $add_order ) {
631
				$reset_fields       = true;
632
				$field->field_order = $field->field_order + $add_order;
633
				FrmField::update( $field->id, array( 'field_order' => $field->field_order ) );
634
			}
635
636
			switch ( $field->type ) {
637
				case 'divider':
638
					// Create an end section if open.
639
					self::maybe_create_end_section( $open, $reset_fields, $add_order, $end_section_values, $field, 'move' );
640
641
					// Mark it open for the next end section.
642
					$open = true;
643
					break;
644
				case 'break':
645
					self::maybe_create_end_section( $open, $reset_fields, $add_order, $end_section_values, $field, 'move' );
646
					break;
647
				case 'end_divider':
648
					if ( ! $open ) {
649
						// The section isn't open, so this is an extra field that needs to be removed.
650
						FrmField::destroy( $field->id );
651
						$reset_fields = true;
652
					}
653
654
					// There is already an end section here, so there is no need to create one.
655
					$open = false;
656
			}
657
			$prev_order = $field->field_order;
658
659
			$last_field = $field;
660
			unset( $field );
661
		}
662
663
		self::maybe_create_end_section( $open, $reset_fields, $add_order, $end_section_values, $last_field );
664
	}
665
666
	/**
667
	 * Create end section field if it doesn't exist. This is for migration from < 2.0
668
	 * Fix any ordering that may be messed up
669
	 */
670
	public static function maybe_create_end_section( &$open, &$reset_fields, &$add_order, $end_section_values, $field, $move = 'no' ) {
671
		if ( ! $open ) {
672
			return;
673
		}
674
675
		$end_section_values['field_order'] = $field->field_order + 1;
676
677
		FrmField::create( $end_section_values );
678
679
		if ( $move == 'move' ) {
680
			// bump the order of current field unless we're at the end of the form
681
			FrmField::update( $field->id, array( 'field_order' => $field->field_order + 2 ) );
682
		}
683
684
		$add_order    += 2;
685
		$open         = false;
686
		$reset_fields = true;
687
	}
688
689
	public static function replace_shortcodes( $html, $form, $title = false, $description = false, $values = array() ) {
690
		$codes = array(
691
			'form_name'        => $title,
692
			'form_description' => $description,
693
			'entry_key'        => true,
694
		);
695
		foreach ( $codes as $code => $show ) {
696
			if ( $code == 'form_name' ) {
697
				$replace_with = $form->name;
698
			} elseif ( $code == 'form_description' ) {
699
				$replace_with = FrmAppHelper::use_wpautop( $form->description );
700
			} elseif ( $code == 'entry_key' && isset( $_GET ) && isset( $_GET['entry'] ) ) {
701
				$replace_with = FrmAppHelper::simple_get( 'entry' );
702
			} else {
703
				$replace_with = '';
704
			}
705
706
			FrmShortcodeHelper::remove_inline_conditions( ( FrmAppHelper::is_true( $show ) && $replace_with != '' ), $code, $replace_with, $html );
707
		}
708
709
		//replace [form_key]
710
		$html = str_replace( '[form_key]', $form->form_key, $html );
711
712
		//replace [frmurl]
713
		$html = str_replace( '[frmurl]', FrmFieldsHelper::dynamic_default_values( 'frmurl' ), $html );
714
715
		if ( strpos( $html, '[button_label]' ) ) {
716
			add_filter( 'frm_submit_button', 'FrmFormsHelper::submit_button_label', 1 );
717
			$submit_label = apply_filters( 'frm_submit_button', $title, $form );
718
			$submit_label = esc_attr( do_shortcode( $submit_label ) );
719
			$html         = str_replace( '[button_label]', $submit_label, $html );
720
		}
721
722
		$html = apply_filters( 'frm_form_replace_shortcodes', $html, $form, $values );
723
724
		if ( strpos( $html, '[if back_button]' ) ) {
725
			$html = preg_replace( '/(\[if\s+back_button\])(.*?)(\[\/if\s+back_button\])/mis', '', $html );
726
		}
727
728
		if ( strpos( $html, '[if save_draft]' ) ) {
729
			$html = preg_replace( '/(\[if\s+save_draft\])(.*?)(\[\/if\s+save_draft\])/mis', '', $html );
730
		}
731
732
		if ( apply_filters( 'frm_do_html_shortcodes', true ) ) {
733
			$html = do_shortcode( $html );
734
		}
735
736
		return $html;
737
	}
738
739
	public static function submit_button_label( $submit ) {
740
		if ( ! $submit || empty( $submit ) ) {
741
			$frm_settings = FrmAppHelper::get_settings();
742
			$submit       = $frm_settings->submit_value;
743
		}
744
745
		return $submit;
746
	}
747
748
	/**
749
	 * If the Formidable styling isn't being loaded,
750
	 * use inline styling to hide the element
751
	 *
752
	 * @since 2.03.05
753
	 */
754
	public static function maybe_hide_inline() {
755
		$frm_settings = FrmAppHelper::get_settings();
756
		if ( $frm_settings->load_style == 'none' ) {
757
			echo ' style="display:none;"';
758
		} elseif ( $frm_settings->load_style == 'dynamic' ) {
759
			FrmStylesController::enqueue_style();
760
		}
761
	}
762
763
	public static function get_form_style_class( $form = false ) {
764
		$style = self::get_form_style( $form );
765
		$class = ' with_frm_style';
766
767
		if ( empty( $style ) ) {
768
			if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) ) {
769
				return $class;
770
			} else {
771
				return;
772
			}
773
		}
774
775
		// If submit button needs to be inline or centered.
776
		if ( is_object( $form ) ) {
777
			$form = $form->options;
778
		}
779
780
		$submit_align = isset( $form['submit_align'] ) ? $form['submit_align'] : '';
781
782
		if ( 'inline' === $submit_align ) {
783
			$class .= ' frm_inline_form';
784
			$class .= self::maybe_align_fields_top( $form );
785
		} elseif ( 'center' === $submit_align ) {
786
			$class .= ' frm_center_submit';
787
		}
788
789
		$class = apply_filters( 'frm_add_form_style_class', $class, $style );
790
791
		return $class;
792
	}
793
794
	/**
795
	 * Returns appropriate class if form has top labels
796
	 *
797
	 * @param $form
798
	 *
799
	 * @return string
800
	 */
801
	private static function maybe_align_fields_top( $form ) {
802
		return self::form_has_top_labels( $form ) ? ' frm_inline_top' : '';
803
	}
804
805
	/**
806
	 * Determine if a form has fields with top labels so submit button can be aligned properly
807
	 *
808
	 * @param $form
809
	 *
810
	 * @return bool
811
	 */
812
	private static function form_has_top_labels( $form ) {
813
		if ( ! isset( $form['fields'] ) ) {
814
			return false;
815
		}
816
817
		$fields = $form['fields'];
818
		if ( count( $fields ) <= 0 ) {
819
			return false;
820
		}
821
822
		$fields = array_reverse( $fields ); // start from the fields closest to the submit button
823
		foreach ( $fields as $field ) {
824
			$type      = isset( $field['original_type'] ) ? $field['original_type'] : $field['type'];
825
			$has_input = FrmFieldFactory::field_has_property( $type, 'has_input' );
826
			if ( $has_input ) {
827
				return self::field_has_top_label( $field, $form );
828
			}
829
		}
830
831
		return false;
832
	}
833
834
	/**
835
	 * Check if a field's label position is set to "top"
836
	 *
837
	 * @param $field
838
	 * @param $form
839
	 *
840
	 * @return bool
841
	 */
842
	private static function field_has_top_label( $field, $form ) {
843
		$label_position = FrmFieldsHelper::label_position( $field['label'], $field, $form );
844
845
		return in_array( $label_position, array( 'top', 'inside', 'hidden' ) );
846
	}
847
848
	/**
849
	 * @param object|string|boolean $form
850
	 *
851
	 * @return string
852
	 */
853
	public static function get_form_style( $form ) {
854
		$style = 1;
855
		if ( empty( $form ) || 'default' == 'form' ) {
856
			return $style;
857
		} elseif ( is_object( $form ) && $form->parent_form_id ) {
858
			// get the parent form if this is a child
859
			$form = $form->parent_form_id;
860
		} elseif ( is_array( $form ) && isset( $form['parent_form_id'] ) && $form['parent_form_id'] ) {
861
			$form = $form['parent_form_id'];
862
		} elseif ( is_array( $form ) && isset( $form['custom_style'] ) ) {
863
			$style = $form['custom_style'];
864
		}
865
866
		if ( $form && is_string( $form ) ) {
867
			$form = FrmForm::getOne( $form );
868
		}
869
870
		$style = ( $form && is_object( $form ) && isset( $form->options['custom_style'] ) ) ? $form->options['custom_style'] : $style;
871
872
		return $style;
873
	}
874
875
	/**
876
	 * Display the validation error messages when an entry is submitted
877
	 *
878
	 * @param array $args - includes img, errors
879
	 *
880
	 * @since 2.0.6
881
	 */
882
	public static function show_errors( $args ) {
883
		$invalid_msg = self::get_invalid_error_message( $args );
884
885
		if ( empty( $invalid_msg ) ) {
886
			$show_img = false;
887
		} else {
888
			echo wp_kses_post( $invalid_msg );
889
			$show_img = true;
890
		}
891
892
		self::show_error(
893
			array(
894
				'img'      => $args['img'],
895
				'errors'   => $args['errors'],
896
				'show_img' => $show_img,
897
			)
898
		);
899
	}
900
901
	/**
902
	 * Display the error message in the front-end along with the image if set
903
	 * The image was removed from the styling settings, but it may still be set with a hook
904
	 * If the message in the global settings is empty, show every validation message in the error box
905
	 *
906
	 * @param array $args - includes img, errors, and show_img
907
	 *
908
	 * @since 2.0.6
909
	 */
910
	public static function show_error( $args ) {
911
		// remove any blank messages
912
		$args['errors'] = array_filter( (array) $args['errors'] );
913
914
		$line_break_first = $args['show_img'];
915
		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...
916
			if ( $line_break_first && ! is_numeric( $error_key ) && ( $error_key == 'cptch_number' || strpos( $error_key, 'field' ) === 0 ) ) {
917
				continue;
918
			}
919
920
			$id = str_replace( 'field', 'field_', $error_key );
921
			echo '<div id="' . esc_attr( $id ) . '_error">';
922
923
			if ( $args['show_img'] && ! empty( $args['img'] ) ) {
924
				echo '<img src="' . esc_attr( $args['img'] ) . '" alt="" />';
925
			} else {
926
				$args['show_img'] = true;
927
			}
928
929
			echo wp_kses_post( $error );
930
931
			echo '</div>';
932
		}
933
	}
934
935
	public static function maybe_get_scroll_js( $id ) {
936
		$offset = apply_filters( 'frm_scroll_offset', 4, array( 'form_id' => $id ) );
937
		if ( $offset != - 1 ) {
938
			self::get_scroll_js( $id );
939
		}
940
	}
941
942
	public static function get_scroll_js( $form_id ) {
943
		echo '<script type="text/javascript">document.addEventListener(\'DOMContentLoaded\',function(){frmFrontForm.scrollMsg(' . (int) $form_id . ');})</script>';
944
	}
945
946
	/**
947
	 * @since 3.0
948
	 */
949
	public static function actions_dropdown( $atts ) {
950
		if ( FrmAppHelper::is_admin_page( 'formidable' ) ) {
951
			$status     = $atts['status'];
952
			$form_id    = isset( $atts['id'] ) ? $atts['id'] : FrmAppHelper::get_param( 'id', 0, 'get', 'absint' );
953
			$trash_link = self::delete_trash_info( $form_id, $status );
954
			$links      = self::get_action_links( $form_id, $status );
955
			include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/actions-dropdown.php' );
956
		}
957
	}
958
959
	/**
960
	 * @since 3.0
961
	 */
962
	public static function get_action_links( $form_id, $form ) {
963
		if ( ! is_object( $form ) ) {
964
			$form = FrmForm::getOne( $form_id );
965
		}
966
967
		$actions     = array();
968
		$trash_links = self::delete_trash_links( $form_id );
969
		if ( 'trash' == $form->status ) {
970
			$actions['restore'] = $trash_links['restore'];
971
972
			if ( current_user_can( 'frm_delete_forms' ) ) {
973
				$actions['trash'] = $trash_links['delete'];
974
			}
975
		} elseif ( current_user_can( 'frm_edit_forms' ) ) {
976
			$duplicate_link = '?page=formidable&frm_action=duplicate&id=' . $form_id;
977
			if ( $form->is_template ) {
978
				$actions['frm_duplicate'] = array(
979
					'url'   => wp_nonce_url( $duplicate_link ),
980
					'label' => __( 'Create Form from Template', 'formidable' ),
981
					'icon'  => 'frm_icon_font frm_clone_icon',
982
				);
983
			} else {
984
				$actions['duplicate'] = array(
985
					'url'   => wp_nonce_url( $duplicate_link ),
986
					'label' => __( 'Duplicate Form', 'formidable' ),
987
					'icon'  => 'frm_icon_font frm_clone_icon',
988
				);
989
			}
990
991
			$actions['trash'] = self::delete_trash_info( $form_id, $form->status );
992
		}
993
994
		return $actions;
995
	}
996
997
	public static function edit_form_link( $form_id ) {
998
		if ( is_object( $form_id ) ) {
999
			$form    = $form_id;
1000
			$name    = $form->name;
1001
			$form_id = $form->id;
1002
		} else {
1003
			$name = FrmForm::getName( $form_id );
1004
		}
1005
1006
		if ( $form_id ) {
1007
			$val = '<a href="' . esc_url( FrmForm::get_edit_link( $form_id ) ) . '">' . ( '' == $name ? __( '(no title)', 'formidable' ) : FrmAppHelper::truncate( $name, 40 ) ) . '</a>';
1008
		} else {
1009
			$val = '';
1010
		}
1011
1012
		return $val;
1013
	}
1014
1015
	public static function delete_trash_link( $id, $status, $length = 'label' ) {
1016
		$link_details = self::delete_trash_info( $id, $status );
1017
1018
		return self::format_link_html( $link_details, $length );
1019
	}
1020
1021
	/**
1022
	 * @since 3.0
1023
	 */
1024
	public static function format_link_html( $link_details, $length = 'label' ) {
1025
		$link = '';
1026
		if ( ! empty( $link_details ) ) {
1027
			$link = '<a href="' . esc_url( $link_details['url'] ) . '" class="frm-trash-link"';
1028
			if ( isset( $link_details['data'] ) ) {
1029
				foreach ( $link_details['data'] as $data => $value ) {
1030
					$link .= ' data-' . esc_attr( $data ) . '="' . esc_attr( $value ) . '"';
1031
				}
1032
			} elseif ( isset( $link_details['confirm'] ) ) {
1033
				$link .= ' onclick="return confirm(\'' . esc_attr( $link_details['confirm'] ) . '\')"';
1034
			}
1035
1036
			$label = ( isset( $link_details[ $length ] ) ? $link_details[ $length ] : $link_details['label'] );
1037
			if ( $length == 'icon' && isset( $link_details[ $length ] ) ) {
1038
				$label = '<span class="' . $label . '" title="' . esc_attr( $link_details['label'] ) . '" aria-hidden="true"></span>';
1039
				$link  .= ' aria-label="' . esc_attr( $link_details['label'] ) . '"';
1040
			}
1041
1042
			$link .= '>' . $label . '</a>';
1043
		}
1044
1045
		return $link;
1046
	}
1047
1048
	/**
1049
	 * @since 3.0
1050
	 */
1051
	public static function delete_trash_info( $id, $status ) {
1052
		$labels = self::delete_trash_links( $id );
1053
1054
		if ( 'trash' == $status ) {
1055
			$info = $labels['restore'];
1056
		} elseif ( current_user_can( 'frm_delete_forms' ) ) {
1057
			if ( EMPTY_TRASH_DAYS ) {
1058
				$info = $labels['trash'];
1059
			} else {
1060
				$info = $labels['delete'];
1061
			}
1062
		} else {
1063
			$info = array();
1064
		}
1065
1066
		return $info;
1067
	}
1068
1069
	/**
1070
	 * @since 3.0
1071
	 */
1072
	private static function delete_trash_links( $id ) {
1073
		$current_page = FrmAppHelper::get_simple_request( array( 'param' => 'form_type' ) );
1074
		$base_url     = '?page=formidable&form_type=' . $current_page . '&id=' . $id;
1075
1076
		return array(
1077
			'restore' => array(
1078
				'label' => __( 'Restore from Trash', 'formidable' ),
1079
				'short' => __( 'Restore', 'formidable' ),
1080
				'url'   => wp_nonce_url( $base_url . '&frm_action=untrash', 'untrash_form_' . absint( $id ) ),
1081
			),
1082
			'trash'   => array(
1083
				'label' => __( 'Move Form to Trash', 'formidable' ),
1084
				'short' => __( 'Trash', 'formidable' ),
1085
				'url'   => wp_nonce_url( $base_url . '&frm_action=trash', 'trash_form_' . absint( $id ) ),
1086
				'icon'  => 'frm_icon_font frm_delete_icon',
1087
				'data'  => array( 'frmverify' => __( 'Do you want to move this form to the trash?', 'formidable' ) ),
1088
			),
1089
			'delete'  => array(
1090
				'label'   => __( 'Delete Permanently', 'formidable' ),
1091
				'short'   => __( 'Delete', 'formidable' ),
1092
				'url'     => wp_nonce_url( $base_url . '&frm_action=destroy', 'destroy_form_' . absint( $id ) ),
1093
				'confirm' => __( 'Are you sure you want to delete this form and all its entries?', 'formidable' ),
1094
				'icon'    => 'frm_icon_font frm_delete_icon',
1095
				'data'    => array( 'frmverify' => __( 'This will permanently delete the form and all its entries. This is irreversible. Are you sure you want to continue?', 'formidable' ) ),
1096
			),
1097
		);
1098
	}
1099
1100
	/**
1101
	 * @since 3.0
1102
	 */
1103
	public static function css_classes() {
1104
		$classes = array(
1105
			'frm_total'      => array(
1106
				'label' => __( 'Total', 'formidable' ),
1107
				'title' => __( 'Add this to a read-only field to display the text in bold without a border or background.', 'formidable' ),
1108
			),
1109
			'frm_scroll_box' => array(
1110
				'label' => __( 'Scroll Box', 'formidable' ),
1111
				'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' ),
1112
			),
1113
			'frm_first'      => array(
1114
				'label' => __( 'First', 'formidable' ),
1115
				'title' => __( 'Add this to the first field in each row along with a width. ie frm_first frm4', 'formidable' ),
1116
			),
1117
			'frm_alignright' => __( 'Right', 'formidable' ),
1118
			'frm_grid_first' => __( 'First Grid Row', 'formidable' ),
1119
			'frm_grid'       => __( 'Even Grid Row', 'formidable' ),
1120
			'frm_grid_odd'   => __( 'Odd Grid Row', 'formidable' ),
1121
			'frm_capitalize' => array(
1122
				'label' => __( 'Capitalize', 'formidable' ),
1123
				'title' => __( 'Automatically capitalize the first letter in each word.', 'formidable' ),
1124
			),
1125
		);
1126
1127
		return apply_filters( 'frm_layout_classes', $classes );
1128
	}
1129
1130
	public static function grid_classes() {
1131
		$base = array(
1132
			'frm_half' => '1/2',
1133
1134
			'frm_third'      => '1/3',
1135
			'frm_two_thirds' => '2/3',
1136
1137
			'frm_fourth'        => '1/4',
1138
			'frm_three_fourths' => '3/4',
1139
		);
1140
1141
		$frm_settings = FrmAppHelper::get_settings();
1142
		if ( $frm_settings->old_css ) {
1143
			$classes = array(
1144
				'frm_sixth' => '1/6',
1145
				'frm10'     => '5/6',
1146
1147
				'frm_full' => '100%',
1148
			);
1149
		} else {
1150
			$classes = array(
1151
				'frm_sixth' => '1/6',
1152
				'frm10'     => '5/6',
1153
				'frm12' => '100%',
1154
			);
1155
		}
1156
1157
		return array_merge( $base, $classes );
1158
	}
1159
1160
	/**
1161
	 * @since 3.0
1162
	 */
1163
	public static function style_class_label( $style, $class ) {
1164
		$label = '';
1165
		if ( empty( $style ) ) {
1166
			$label = $class;
1167
		} elseif ( ! is_array( $style ) ) {
1168
			$label = $style;
1169
		} elseif ( isset( $style['label'] ) ) {
1170
			$label = $style['label'];
1171
		}
1172
1173
		return $label;
1174
	}
1175
1176
	public static function status_nice_name( $status ) {
1177
		$nice_names = array(
1178
			'draft'   => __( 'Draft', 'formidable' ),
1179
			'trash'   => __( 'Trash', 'formidable' ),
1180
			'publish' => __( 'Published', 'formidable' ),
1181
		);
1182
1183
		if ( ! in_array( $status, array_keys( $nice_names ) ) ) {
1184
			$status = 'publish';
1185
		}
1186
1187
		$name = $nice_names[ $status ];
1188
1189
		return $name;
1190
	}
1191
1192
	public static function template_icon( $categories ) {
1193
		$ignore     = array( 'Business', 'Elite', 'Personal', 'Creator', 'Basic', 'free' );
1194
		$categories = array_diff( $categories, $ignore );
1195
1196
		$icons = array(
1197
			'WooCommerce'       => array( 'woocommerce', 'var(--purple)' ),
1198
			'Post'              => array( 'wordpress', 'rgb(0,160,210)' ),
1199
			'User Registration' => array( 'register', 'var(--pink)' ),
1200
			'PayPal'            => array( 'paypal' ),
1201
			'Stripe'            => array( 'credit_card', 'var(--green)' ),
1202
			'Twilio'            => array( 'sms', 'rgb(0,160,210)' ),
1203
			'Calculator'        => array( 'calculator', 'var(--orange)' ),
1204
			'Contact Form'      => array( 'address_card' ),
1205
			'Survey'            => array( 'align_right', 'var(--pink)' ),
1206
			'Application Form'  => array( 'align_right', 'rgb(0,160,210)' ),
1207
			''                  => array( 'align_right' ),
1208
		);
1209
1210
		if ( empty( $categories ) ) {
1211
			$icon = $icons[''];
1212
		} elseif ( count( $categories ) === 1 ) {
1213
			$category = reset( $categories );
1214
			$icon     = $icons[ $category ];
1215
		} else {
1216
			foreach ( $icons as $cat => $icon ) {
1217
				if ( ! in_array( $cat, $categories ) ) {
1218
					unset( $icons[ $cat ] );
1219
				}
1220
			}
1221
			$icon = reset( $icons );
1222
		}
1223
1224
		echo '<span class="frm-inner-circle" ' . ( isset( $icon[1] ) ? 'style="background-color:' . esc_attr( $icon[1] ) : '' ) . '">';
1225
		FrmAppHelper::icon_by_class( 'frmfont frm_' . $icon[0] . '_icon' );
1226
		echo '<span class="frm_hidden">';
1227
		FrmAppHelper::icon_by_class( 'frmfont frm_lock_icon' );
1228
		echo '</span>';
1229
		echo '</span>';
1230
	}
1231
1232
	/**
1233
	 * @since 4.02
1234
	 */
1235
	public static function get_template_install_link( $template, $args ) {
1236
		$defaults = array(
1237
			'class' => 'install-now',
1238
			'href'  => 'href',
1239
			'atts'  => true,
1240
		);
1241
1242
		if ( isset( $template['url'] ) && ! empty( $template['url'] ) ) {
1243
			$link = array(
1244
				'url'   => $template['url'],
1245
				'label' => __( 'Create Form', 'formidable' ),
1246
				'class' => 'frm-install-template',
1247
				'href'  => 'rel',
1248
				'atts'  => '',
1249
			);
1250
		} elseif ( self::plan_is_allowed( $args ) ) {
1251
			$link = array(
1252
				'url'   => FrmAppHelper::admin_upgrade_link( 'addons', 'account/licenses/' ) . '&utm_content=' . $template['slug'],
1253
				'label' => __( 'Renew', 'formidable' ),
1254
			);
1255
		} else {
1256
			$link = array(
1257
				'url'   => $args['pricing'],
1258
				'label' => __( 'Upgrade', 'formidable' ) . $args['license_type'] .' '. $args['plan_required'],
1259
			);
1260
		}
1261
1262
		return array_merge( $defaults, $link );
1263
	}
1264
1265
	/**
1266
	 * Is the template included with the license type?
1267
	 *
1268
	 * @since 4.02.02
1269
	 *
1270
	 * @param array $args
1271
	 *
1272
	 * @return bool
1273
	 */
1274
	private static function plan_is_allowed( $args ) {
1275
		$plans = array( 'free', 'personal', 'business', 'elite' );
1276
		$included = ! empty( $args['license_type'] ) && $args['license_type'] === strtolower( $args['plan_required'] );
1277
		if ( ! empty( $args['license_type'] ) && in_array( strtolower( $args['plan_required'] ), $plans ) ) {
1278
			foreach ( $plans as $plan ) {
1279
				if ( $included || $plan === $args['license_type'] ) {
1280
					break;
1281
				}
1282
				$included = $plan === strtolower( $args['plan_required'] );
1283
			}
1284
		}
1285
1286
		return $included;
1287
	}
1288
1289
	/**
1290
	 * @since 4.02
1291
	 */
1292
	public static function template_install_html( $link, $class = '' ) {
1293
		$link['class'] .= ' ' . $class;
1294
		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"' : '' ) . '>';
1295
	}
1296
1297
	/**
1298
	 * If a template or add-on cannot be installed, show a message
1299
	 * about which plan is required.
1300
	 *
1301
	 * @since 4.0
1302
	 */
1303
	public static function show_plan_required( $requires, $link ) {
1304
		if ( empty( $requires ) ) {
1305
			return;
1306
		}
1307
1308
		?>
1309
		<p class="frm_plan_required">
1310
			<?php esc_html_e( 'License plan required:', 'formidable' ); ?>
1311
			<a href="<?php echo esc_url( $link ); ?>" target="_blank" rel="noopener">
1312
				<?php echo esc_html( $requires ); ?>
1313
			</a>
1314
		</p>
1315
		<?php
1316
	}
1317
1318
	/**
1319
	 * @since 4.0
1320
	 */
1321
	public static function get_plan_required( &$item ) {
1322
		if ( ! isset( $item['categories'] ) || ( isset( $item['url'] ) && ! empty( $item['url'] ) ) ) {
1323
			return false;
1324
		}
1325
1326
		$plans = array( 'free', 'Personal', 'Business', 'Elite' );
1327
1328
		foreach ( $item['categories'] as $k => $category ) {
1329
			if ( in_array( $category, $plans ) ) {
1330
				unset( $item['categories'][ $k ] );
1331
				return $category;
1332
			}
1333
		}
1334
1335
		return false;
1336
	}
1337
}
1338