Completed
Pull Request — master (#237)
by
unknown
02:46
created

FrmAppHelper::use_wpautop()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 1
dl 0
loc 7
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 FrmAppHelper {
7
	public static $db_version = 97; //version of the database we are moving to
8
	public static $pro_db_version = 37; //deprecated
9
	public static $font_version = 7;
10
11
	/**
12
	 * @since 2.0
13
	 */
14
	public static $plug_version = '4.07';
15
16
	/**
17
	 * @since 1.07.02
18
	 *
19
	 * @param none
20
	 *
21
	 * @return string The version of this plugin
22
	 */
23
	public static function plugin_version() {
24
		return self::$plug_version;
25
	}
26
27
	public static function plugin_folder() {
28
		return basename( self::plugin_path() );
29
	}
30
31
	public static function plugin_path() {
32
		return dirname( dirname( dirname( __FILE__ ) ) );
33
	}
34
35
	public static function plugin_url() {
36
		// Prevously FRM_URL constant.
37
		return plugins_url( '', self::plugin_path() . '/formidable.php' );
38
	}
39
40
	public static function relative_plugin_url() {
41
		return str_replace( array( 'https:', 'http:' ), '', self::plugin_url() );
42
	}
43
44
	/**
45
	 * @return string Site URL
46
	 */
47
	public static function site_url() {
48
		return site_url();
49
	}
50
51
	/**
52
	 * Get the name of this site
53
	 * Used for [sitename] shortcode
54
	 *
55
	 * @since 2.0
56
	 * @return string
57
	 */
58
	public static function site_name() {
59
		return get_option( 'blogname' );
60
	}
61
62
	public static function make_affiliate_url( $url ) {
63
		$affiliate_id = self::get_affiliate();
64
		if ( ! empty( $affiliate_id ) ) {
65
			$url = str_replace( array( 'http://', 'https://' ), '', $url );
66
			$url = 'http://www.shareasale.com/r.cfm?u=' . absint( $affiliate_id ) . '&b=841990&m=64739&afftrack=plugin&urllink=' . urlencode( $url );
67
		}
68
69
		return $url;
70
	}
71
72
	public static function get_affiliate() {
73
		return absint( apply_filters( 'frm_affiliate_id', 0 ) );
74
	}
75
76
	/**
77
	 * @since 3.04.02
78
	 * @param array|string $args
79
	 * @param string       $page
80
	 */
81
	public static function admin_upgrade_link( $args, $page = '' ) {
82
		if ( empty( $page ) ) {
83
			$page = 'https://formidableforms.com/lite-upgrade/';
84
		} else {
85
			$page = str_replace( 'https://formidableforms.com/', '', $page );
86
			$page = 'https://formidableforms.com/' . $page;
87
		}
88
89
		$anchor = '';
90
		if ( is_array( $args ) ) {
91
			$medium  = $args['medium'];
92
			$content = $args['content'];
93
			if ( isset( $args['anchor'] ) ) {
94
				$anchor = '#' . $args['anchor'];
95
			}
96
		} else {
97
			$medium = $args;
98
		}
99
100
		$query_args = array(
101
			'utm_source'   => 'WordPress',
102
			'utm_medium'   => $medium,
103
			'utm_campaign' => 'liteplugin',
104
		);
105
106
		if ( isset( $content ) ) {
107
			$query_args['utm_content'] = $content;
108
		}
109
110
		if ( is_array( $args ) && isset( $args['param'] ) ) {
111
			$query_args['f'] = $args['param'];
112
		}
113
114
		$link = add_query_arg( $query_args, $page ) . $anchor;
115
		return self::make_affiliate_url( $link );
116
	}
117
118
	/**
119
	 * @since 4.07
120
	 */
121
	public static function renewal_message() {
122
		if ( ! FrmAddonsController::is_license_expired() ) {
123
			return;
124
		}
125
		?>
126
		<div class="frm_error_style" style="text-align:left">
127
			<?php self::icon_by_class( 'frmfont frm_alert_icon' ); ?>
128
			&nbsp;
129
			<?php esc_attr_e( 'Your account has expired', 'formidable' ); ?>
130
			<div style="float:right">
131
				<a href="<?php echo esc_url( self::admin_upgrade_link( 'form-renew', 'account/downloads/' ) ); ?>">
132
					Renew Now
133
				</a>
134
			</div>
135
		</div>
136
		<?php
137
	}
138
139
	/**
140
	 * Get the Formidable settings
141
	 *
142
	 * @since 2.0
143
	 *
144
	 * @param array $args - May include the form id when values need translation.
145
	 * @return FrmSettings $frm_setings
146
	 */
147
	public static function get_settings( $args = array() ) {
148
		global $frm_settings;
149
		if ( empty( $frm_settings ) ) {
150
			$frm_settings = new FrmSettings( $args );
151
		} elseif ( isset( $args['current_form'] ) ) {
152
			// If the global has already been set, allow strings to be filtered.
153
			$frm_settings->maybe_filter_for_form( $args );
154
		}
155
156
		return $frm_settings;
157
	}
158
159
	public static function get_menu_name() {
160
		$frm_settings = self::get_settings();
161
162
		return $frm_settings->menu;
163
	}
164
165
	/**
166
	 * @since 3.05
167
	 */
168
	public static function svg_logo( $atts = array() ) {
169
		$defaults = array(
170
			'height' => 18,
171
			'width'  => 18,
172
			'fill'   => '#4d4d4d',
173
			'orange' => '#f05a24',
174
		);
175
		$atts     = array_merge( $defaults, $atts );
176
177
		return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 599.68 601.37" width="' . esc_attr( $atts['width'] ) . '" height="' . esc_attr( $atts['height'] ) . '">
178
			<path fill="' . esc_attr( $atts['orange'] ) . '" d="M289.6 384h140v76h-140z"/>
179
			<path fill="' . esc_attr( $atts['fill'] ) . '" d="M400.2 147h-200c-17 0-30.6 12.2-30.6 29.3V218h260v-71zM397.9 264H169.6v196h75V340H398a32.2 32.2 0 0 0 30.1-21.4 24.3 24.3 0 0 0 1.7-8.7V264zM299.8 601.4A300.3 300.3 0 0 1 0 300.7a299.8 299.8 0 1 1 511.9 212.6 297.4 297.4 0 0 1-212 88zm0-563A262 262 0 0 0 38.3 300.7a261.6 261.6 0 1 0 446.5-185.5 259.5 259.5 0 0 0-185-76.8z"/>
180
		</svg>';
181
	}
182
183
	/**
184
	 * @since 4.0
185
	 */
186
	public static function show_logo( $atts = array() ) {
187
		echo self::kses( self::svg_logo( $atts ), 'all' ); // WPCS: XSS ok.
188
	}
189
190
	/**
191
	 * @since 4.03.02
192
	 */
193
	public static function show_header_logo() {
194
		$icon = self::svg_logo(
195
			array(
196
				'height' => 35,
197
				'width'  => 35,
198
			)
199
		);
200
201
		$new_icon = apply_filters( 'frm_icon', $icon, true );
202
		if ( $new_icon !== $icon ) {
203
			if ( strpos( $new_icon, '<svg' ) === 0 ) {
204
				$icon = str_replace( 'viewBox="0 0 20', 'width="30" height="35" style="color:#929699" viewBox="0 0 20', $new_icon );
205
			} else {
206
				// Show nothing if it isn't an SVG.
207
				$icon = '<div style="height:39px"></div>';
208
			}
209
		}
210
		echo self::kses( $icon, 'all' ); // WPCS: XSS ok.
211
	}
212
213
	/**
214
	 * @since 2.02.04
215
	 */
216
	public static function ips_saved() {
217
		$frm_settings = self::get_settings();
218
219
		return ! $frm_settings->no_ips;
220
	}
221
222
	public static function pro_is_installed() {
223
		return apply_filters( 'frm_pro_installed', false );
224
	}
225
226
	/**
227
	 * @since 4.06.02
228
	 */
229
	public static function pro_is_connected() {
230
		global $frm_vars;
231
		return self::pro_is_installed() && $frm_vars['pro_is_authorized'];
232
	}
233
234
	/**
235
	 * @since 4.06
236
	 */
237
	public static function is_form_builder_page() {
238
		$action = self::simple_get( 'frm_action', 'sanitize_title' );
239
		return self::is_admin_page( 'formidable' ) && ( $action === 'edit' || $action === 'settings' || $action === 'duplicate' );
240
	}
241
242
	public static function is_formidable_admin() {
243
		$page          = self::simple_get( 'page', 'sanitize_title' );
244
		$is_formidable = strpos( $page, 'formidable' ) !== false;
245
		if ( empty( $page ) ) {
246
			$is_formidable = self::is_view_builder_page();
247
		}
248
249
		return $is_formidable;
250
	}
251
252
	/**
253
	 * Check for certain page in Formidable settings
254
	 *
255
	 * @since 2.0
256
	 *
257
	 * @param string $page The name of the page to check
258
	 *
259
	 * @return boolean
260
	 */
261
	public static function is_admin_page( $page = 'formidable' ) {
262
		global $pagenow;
263
		$get_page = self::simple_get( 'page', 'sanitize_title' );
264
		if ( $pagenow ) {
265
			// allow this to be true during ajax load i.e. ajax form builder loading
266
			$is_page = ( $pagenow == 'admin.php' || $pagenow == 'admin-ajax.php' ) && $get_page == $page;
267
			if ( $is_page ) {
268
				return true;
269
			}
270
		}
271
272
		return is_admin() && $get_page == $page;
273
	}
274
275
	/**
276
	 * If the current page is for editing or creating a view.
277
	 * Returns false for the views listing page.
278
	 *
279
	 * @since 4.0
280
	 */
281
	public static function is_view_builder_page() {
282
		global $pagenow;
283
284
		if ( $pagenow !== 'post.php' && $pagenow !== 'post-new.php' && $pagenow !== 'edit.php' ) {
285
			return false;
286
		}
287
288
		$post_type = self::simple_get( 'post_type', 'sanitize_title' );
289
290
		if ( empty( $post_type ) ) {
291
			$post_id = self::simple_get( 'post', 'absint' );
292
			$post    = get_post( $post_id );
293
			$post_type = $post ? $post->post_type : '';
294
		}
295
296
		return $post_type === 'frm_display';
297
	}
298
299
	/**
300
	 * Check for the form preview page
301
	 *
302
	 * @since 2.0
303
	 *
304
	 * @param None
305
	 *
306
	 * @return boolean
307
	 */
308
	public static function is_preview_page() {
309
		global $pagenow;
310
		$action = self::simple_get( 'action', 'sanitize_title' );
311
312
		return $pagenow && $pagenow == 'admin-ajax.php' && $action == 'frm_forms_preview';
313
	}
314
315
	/**
316
	 * Check for ajax except the form preview page
317
	 *
318
	 * @since 2.0
319
	 *
320
	 * @param None
321
	 *
322
	 * @return boolean
323
	 */
324
	public static function doing_ajax() {
325
		return wp_doing_ajax() && ! self::is_preview_page();
326
	}
327
328
	public static function js_suffix() {
329
		return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
330
	}
331
332
	/**
333
	 * @since 2.0.8
334
	 */
335
	public static function prevent_caching() {
336
		global $frm_vars;
337
338
		return isset( $frm_vars['prevent_caching'] ) && $frm_vars['prevent_caching'];
339
	}
340
341
	/**
342
	 * Check if on an admin page
343
	 *
344
	 * @since 2.0
345
	 *
346
	 * @param None
347
	 *
348
	 * @return boolean
349
	 */
350
	public static function is_admin() {
351
		return is_admin() && ! wp_doing_ajax();
352
	}
353
354
	/**
355
	 * Check if value contains blank value or empty array
356
	 *
357
	 * @since 2.0
358
	 *
359
	 * @param mixed $value - value to check
360
	 * @param string
361
	 *
362
	 * @return boolean
363
	 */
364
	public static function is_empty_value( $value, $empty = '' ) {
365
		return ( is_array( $value ) && empty( $value ) ) || $value === $empty;
366
	}
367
368
	public static function is_not_empty_value( $value, $empty = '' ) {
369
		return ! self::is_empty_value( $value, $empty );
370
	}
371
372
	/**
373
	 * Get any value from the $_SERVER
374
	 *
375
	 * @since 2.0
376
	 *
377
	 * @param string $value
378
	 *
379
	 * @return string
380
	 */
381
	public static function get_server_value( $value ) {
382
		return isset( $_SERVER[ $value ] ) ? wp_strip_all_tags( wp_unslash( $_SERVER[ $value ] ) ) : '';
383
	}
384
385
	/**
386
	 * Check for the IP address in several places
387
	 * Used by [ip] shortcode
388
	 *
389
	 * @return string The IP address of the current user
390
	 */
391
	public static function get_ip_address() {
392
		$ip_options = array(
393
			'HTTP_CLIENT_IP',
394
			'HTTP_CF_CONNECTING_IP',
395
			'HTTP_X_FORWARDED_FOR',
396
			'HTTP_X_FORWARDED',
397
			'HTTP_X_CLUSTER_CLIENT_IP',
398
			'HTTP_X_REAL_IP',
399
			'HTTP_FORWARDED_FOR',
400
			'HTTP_FORWARDED',
401
			'REMOTE_ADDR',
402
		);
403
		$ip = '';
404
		foreach ( $ip_options as $key ) {
405
			if ( ! isset( $_SERVER[ $key ] ) ) {
406
				continue;
407
			}
408
409
			$key = self::get_server_value( $key );
410
			foreach ( explode( ',', $key ) as $ip ) {
411
				$ip = trim( $ip ); // just to be safe.
412
413
				if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
414
					return sanitize_text_field( $ip );
415
				}
416
			}
417
		}
418
419
		return sanitize_text_field( $ip );
420
	}
421
422
	public static function get_param( $param, $default = '', $src = 'get', $sanitize = '' ) {
423
		if ( strpos( $param, '[' ) ) {
424
			$params = explode( '[', $param );
425
			$param  = $params[0];
426
		}
427
428
		if ( $src == 'get' ) {
429
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
430
			$value = isset( $_POST[ $param ] ) ? wp_unslash( $_POST[ $param ] ) : ( isset( $_GET[ $param ] ) ? wp_unslash( $_GET[ $param ] ) : $default );
431
			if ( ! isset( $_POST[ $param ] ) && isset( $_GET[ $param ] ) && ! is_array( $value ) ) {
432
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
433
				$value = htmlspecialchars_decode( wp_unslash( $_GET[ $param ] ) );
434
			}
435
			self::sanitize_value( $sanitize, $value );
436
		} else {
437
			$value = self::get_simple_request(
438
				array(
439
					'type'     => $src,
440
					'param'    => $param,
441
					'default'  => $default,
442
					'sanitize' => $sanitize,
443
				)
444
			);
445
		}
446
447
		if ( isset( $params ) && is_array( $value ) && ! empty( $value ) ) {
448
			foreach ( $params as $k => $p ) {
449
				if ( ! $k || ! is_array( $value ) ) {
450
					continue;
451
				}
452
453
				$p     = trim( $p, ']' );
454
				$value = isset( $value[ $p ] ) ? $value[ $p ] : $default;
455
			}
456
		}
457
458
		return $value;
459
	}
460
461 View Code Duplication
	public static function get_post_param( $param, $default = '', $sanitize = '', $serialized = false ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
462
		return self::get_simple_request(
463
			array(
464
				'type'     => 'post',
465
				'param'    => $param,
466
				'default'  => $default,
467
				'sanitize' => $sanitize,
468
				'serialized' => $serialized,
469
			)
470
		);
471
	}
472
473
	/**
474
	 * @since 2.0
475
	 *
476
	 * @param string $param
477
	 * @param string $sanitize
478
	 * @param string $default
479
	 *
480
	 * @return string|array
481
	 */
482 View Code Duplication
	public static function simple_get( $param, $sanitize = 'sanitize_text_field', $default = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
483
		return self::get_simple_request(
484
			array(
485
				'type'     => 'get',
486
				'param'    => $param,
487
				'default'  => $default,
488
				'sanitize' => $sanitize,
489
			)
490
		);
491
	}
492
493
	/**
494
	 * Get a GET/POST/REQUEST value and sanitize it
495
	 *
496
	 * @since 2.0.6
497
	 *
498
	 * @param array $args
499
	 *
500
	 * @return string|array
501
	 */
502
	public static function get_simple_request( $args ) {
503
		$defaults = array(
504
			'param'    => '',
505
			'default'  => '',
506
			'type'     => 'get',
507
			'sanitize' => 'sanitize_text_field',
508
			'serialized' => false,
509
		);
510
		$args     = wp_parse_args( $args, $defaults );
511
512
		$value = $args['default'];
513
		if ( $args['type'] == 'get' ) {
514 View Code Duplication
			if ( $_GET && isset( $_GET[ $args['param'] ] ) ) {
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...
515
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
516
				$value = wp_unslash( $_GET[ $args['param'] ] );
517
			}
518
		} elseif ( $args['type'] == 'post' ) {
519
			if ( isset( $_POST[ $args['param'] ] ) ) {
520
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
521
				$value = wp_unslash( $_POST[ $args['param'] ] );
522
				if ( $args['serialized'] === true && is_serialized_string( $value ) && is_serialized( $value ) ) {
523
					self::unserialize_or_decode( $value );
524
				}
525
			}
526 View Code Duplication
		} else {
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...
527
			if ( isset( $_REQUEST[ $args['param'] ] ) ) {
528
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
529
				$value = wp_unslash( $_REQUEST[ $args['param'] ] );
530
			}
531
		}
532
533
		self::sanitize_value( $args['sanitize'], $value );
534
535
		return $value;
536
	}
537
538
	/**
539
	 * Preserve backslashes in a value, but make sure value doesn't get compounding slashes
540
	 *
541
	 * @since 2.0.8
542
	 *
543
	 * @param string $value
544
	 *
545
	 * @return string $value
546
	 */
547
	public static function preserve_backslashes( $value ) {
548
		// If backslashes have already been added, don't add them again
549
		if ( strpos( $value, '\\\\' ) === false ) {
550
			$value = addslashes( $value );
551
		}
552
553
		return $value;
554
	}
555
556
	public static function sanitize_value( $sanitize, &$value ) {
557
		if ( ! empty( $sanitize ) ) {
558
			if ( is_array( $value ) ) {
559
				$temp_values = $value;
560
				foreach ( $temp_values as $k => $v ) {
561
					self::sanitize_value( $sanitize, $value[ $k ] );
562
				}
563
			} else {
564
				$value = call_user_func( $sanitize, $value );
565
			}
566
		}
567
	}
568
569
	public static function sanitize_request( $sanitize_method, &$values ) {
570
		$temp_values = $values;
571
		foreach ( $temp_values as $k => $val ) {
572
			if ( isset( $sanitize_method[ $k ] ) ) {
573
				$values[ $k ] = call_user_func( $sanitize_method[ $k ], $val );
574
			}
575
		}
576
	}
577
578
	/**
579
	 * @since 4.0.04
580
	 */
581
	public static function sanitize_with_html( &$value ) {
582
		self::sanitize_value( 'wp_kses_post', $value );
583
		self::decode_specialchars( $value );
584
	}
585
586
	/**
587
	 * Do wp_specialchars_decode to get back '&' that wp_kses_post might have turned to '&amp;'
588
	 * this MUST be done, else we'll be back to the '& entity' problem.
589
	 *
590
	 * @since 4.0.04
591
	 */
592
	public static function decode_specialchars( &$value ) {
593
		if ( is_array( $value ) ) {
594
			$temp_values = $value;
595
			foreach ( $temp_values as $k => $v ) {
596
				self::decode_specialchars( $value[ $k ] );
597
			}
598
		} else {
599
			self::decode_amp( $value );
600
		}
601
	}
602
603
	/**
604
	 * The wp_specialchars_decode function changes too much.
605
	 * This will leave HTML as is, but still convert &.
606
	 * Adapted from wp_specialchars_decode().
607
	 *
608
	 * @since 4.03.01
609
	 *
610
	 * @param string $string The string to prep.
611
	 */
612
	private static function decode_amp( &$string ) {
613
		// Don't bother if there are no entities - saves a lot of processing
614
		if ( empty( $string ) || strpos( $string, '&' ) === false ) {
615
			return;
616
		}
617
618
		$translation = array(
619
			'&quot;'  => '"',
620
			'&#034;'  => '"',
621
			'&#x22;'  => '"',
622
			'&lt; '   => '< ', // The space preserves the HTML.
623
			'&#060; ' => '< ', // The space preserves the HTML.
624
			'&gt;'    => '>',
625
			'&#062;'  => '>',
626
			'&amp;'   => '&',
627
			'&#038;'  => '&',
628
			'&#x26;'  => '&',
629
		);
630
631
		$translation_preg = array(
632
			'/&#0*34;/'   => '&#034;',
633
			'/&#x0*22;/i' => '&#x22;',
634
			'/&#0*60;/'   => '&#060;',
635
			'/&#0*62;/'   => '&#062;',
636
			'/&#0*38;/'   => '&#038;',
637
			'/&#x0*26;/i' => '&#x26;',
638
		);
639
640
		// Remove zero padding on numeric entities
641
		$string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string );
642
643
		// Replace characters according to translation table
644
		$string = strtr( $string, $translation );
645
	}
646
647
	/**
648
	 * Sanitize the value, and allow some HTML
649
	 *
650
	 * @since 2.0
651
	 *
652
	 * @param string $value
653
	 * @param array|string $allowed 'all' for everything included as defaults
654
	 *
655
	 * @return string
656
	 */
657
	public static function kses( $value, $allowed = array() ) {
658
		$allowed_html = self::allowed_html( $allowed );
659
660
		return wp_kses( $value, $allowed_html );
661
	}
662
663
	/**
664
	 * @since 2.05.03
665
	 */
666
	private static function allowed_html( $allowed ) {
667
		$html         = self::safe_html();
668
		$allowed_html = array();
669
		if ( $allowed == 'all' ) {
670
			$allowed_html = $html;
671
		} elseif ( ! empty( $allowed ) ) {
672
			foreach ( (array) $allowed as $a ) {
673
				$allowed_html[ $a ] = isset( $html[ $a ] ) ? $html[ $a ] : array();
674
			}
675
		}
676
677
		return apply_filters( 'frm_striphtml_allowed_tags', $allowed_html );
678
	}
679
680
	/**
681
	 * @since 2.05.03
682
	 */
683
	private static function safe_html() {
684
		$allow_class = array(
685
			'class' => true,
686
			'id'    => true,
687
		);
688
689
		return array(
690
			'a'          => array(
691
				'class'  => true,
692
				'href'   => true,
693
				'id'     => true,
694
				'rel'    => true,
695
				'target' => true,
696
				'title'  => true,
697
			),
698
			'abbr'       => array(
699
				'title' => true,
700
			),
701
			'aside'      => $allow_class,
702
			'b'          => array(),
703
			'blockquote' => array(
704
				'cite' => true,
705
			),
706
			'br'         => array(),
707
			'cite'       => array(
708
				'title' => true,
709
			),
710
			'code'       => array(),
711
			'defs'       => array(),
712
			'del'        => array(
713
				'datetime' => true,
714
				'title'    => true,
715
			),
716
			'dd'         => array(),
717
			'div'        => array(
718
				'class' => true,
719
				'id'    => true,
720
				'title' => true,
721
				'style' => true,
722
			),
723
			'dl'         => array(),
724
			'dt'         => array(),
725
			'em'         => array(),
726
			'h1'         => $allow_class,
727
			'h2'         => $allow_class,
728
			'h3'         => $allow_class,
729
			'h4'         => $allow_class,
730
			'h5'         => $allow_class,
731
			'h6'         => $allow_class,
732
			'i'          => array(
733
				'class' => true,
734
				'id'    => true,
735
				'icon'  => true,
736
				'style' => true,
737
			),
738
			'img'        => array(
739
				'alt'    => true,
740
				'class'  => true,
741
				'height' => true,
742
				'id'     => true,
743
				'src'    => true,
744
				'width'  => true,
745
			),
746
			'li'         => $allow_class,
747
			'ol'         => $allow_class,
748
			'p'          => $allow_class,
749
			'path'       => array(
750
				'd'    => true,
751
				'fill' => true,
752
			),
753
			'pre'        => array(),
754
			'q'          => array(
755
				'cite'  => true,
756
				'title' => true,
757
			),
758
			'rect'       => array(
759
				'class'  => true,
760
				'fill'   => true,
761
				'height' => true,
762
				'width'  => true,
763
				'x'      => true,
764
				'y'      => true,
765
				'rx'     => true,
766
				'stroke' => true,
767
				'stroke-opacity' => true,
768
				'stroke-width'   => true,
769
			),
770
			'section'    => $allow_class,
771
			'span'       => array(
772
				'class' => true,
773
				'id'    => true,
774
				'title' => true,
775
				'style' => true,
776
			),
777
			'strike'     => array(),
778
			'strong'     => array(),
779
			'symbol'     => array(
780
				'class'   => true,
781
				'id'      => true,
782
				'viewbox' => true,
783
			),
784
			'svg'        => array(
785
				'class'   => true,
786
				'id'      => true,
787
				'xmlns'   => true,
788
				'viewbox' => true,
789
				'width'   => true,
790
				'height'  => true,
791
				'style'   => true,
792
				'fill'    => true,
793
			),
794
			'use'        => array(
795
				'href'   => true,
796
				'xlink:href' => true,
797
			),
798
			'ul'         => $allow_class,
799
		);
800
	}
801
802
	/**
803
	 * Used when switching the action for a bulk action
804
	 *
805
	 * @since 2.0
806
	 */
807
	public static function remove_get_action() {
808
		if ( ! isset( $_GET ) ) {
809
			return;
810
		}
811
812
		$action_name = isset( $_GET['action'] ) ? 'action' : ( isset( $_GET['action2'] ) ? 'action2' : '' );
813
		if ( empty( $action_name ) ) {
814
			return;
815
		}
816
817
		$new_action = self::get_param( $action_name, '', 'get', 'sanitize_text_field' );
818
		if ( ! empty( $new_action ) ) {
819
			$_SERVER['REQUEST_URI'] = str_replace( '&action=' . $new_action, '', self::get_server_value( 'REQUEST_URI' ) );
820
		}
821
	}
822
823
	/**
824
	 * Check the WP query for a parameter
825
	 *
826
	 * @since 2.0
827
	 * @return string|array
828
	 */
829
	public static function get_query_var( $value, $param ) {
830
		if ( $value != '' ) {
831
			return $value;
832
		}
833
834
		global $wp_query;
835
		if ( isset( $wp_query->query_vars[ $param ] ) ) {
836
			$value = $wp_query->query_vars[ $param ];
837
		}
838
839
		return $value;
840
	}
841
842
	/**
843
	 * Try to show the SVG if possible. Otherwise, use the font icon.
844
	 *
845
	 * @since 4.0.02
846
	 * @param string $class
847
	 * @param array  $atts
848
	 */
849
	public static function icon_by_class( $class, $atts = array() ) {
850
		$echo = ! isset( $atts['echo'] ) || $atts['echo'];
851
		if ( isset( $atts['echo'] ) ) {
852
			unset( $atts['echo'] );
853
		}
854
855
		$html_atts = self::array_to_html_params( $atts );
856
857
		$icon = trim( str_replace( array( 'frm_icon_font', 'frmfont ' ), '', $class ) );
858
		if ( $icon === $class ) {
859
			$icon = '<i class="' . esc_attr( $class ) . '"' . $html_atts . '></i>';
860
		} else {
861
			$class = strpos( $icon, ' ' ) === false ? '' : ' ' . $icon;
862
			if ( strpos( $icon, ' ' ) ) {
863
				$icon = explode( ' ', $icon );
864
				$icon = reset( $icon );
865
			}
866
			$icon  = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '>
867
				<use xlink:href="#' . esc_attr( $icon ) . '" />
868
			</svg>';
869
		}
870
871
		if ( $echo ) {
872
			echo $icon; // WPCS: XSS ok.
873
		} else {
874
			return $icon;
875
		}
876
	}
877
878
	/**
879
	 * Include svg images.
880
	 *
881
	 * @since 4.0.02
882
	 */
883
	public static function include_svg() {
884
		include_once( self::plugin_path() . '/images/icons.svg' );
885
	}
886
887
	/**
888
	 * Convert an associative array to HTML values.
889
	 *
890
	 * @since 4.0.02
891
	 * @param array $atts
892
	 * @return string
893
	 */
894
	public static function array_to_html_params( $atts ) {
895
		$html = '';
896
		if ( ! empty( $atts ) ) {
897
			foreach ( $atts as $key => $value ) {
898
				$html .= ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
899
			}
900
		}
901
		return $html;
902
	}
903
904
	/**
905
	 * @since 3.0
906
	 */
907
	public static function get_admin_header( $atts ) {
908
		$has_nav = ( isset( $atts['form'] ) && ! empty( $atts['form'] ) && ( ! isset( $atts['is_template'] ) || ! $atts['is_template'] ) );
909
		if ( ! isset( $atts['close'] ) || empty( $atts['close'] ) ) {
910
			$atts['close'] = admin_url( 'admin.php?page=formidable' );
911
		}
912
		if ( ! isset( $atts['import_link'] ) ) {
913
			$atts['import_link'] = false;
914
		}
915
916
		include( self::plugin_path() . '/classes/views/shared/admin-header.php' );
917
	}
918
919
	/**
920
	 * @since 3.0
921
	 */
922
	public static function add_new_item_link( $atts ) {
923
		if ( isset( $atts['new_link'] ) && ! empty( $atts['new_link'] ) ) {
924
			?>
925
			<a href="<?php echo esc_url( $atts['new_link'] ); ?>" class="button button-primary frm-button-primary frm-with-plus">
926
				<?php self::icon_by_class( 'frmfont frm_plus_icon frm_svg15' ); ?>
927
				<?php esc_html_e( 'Add New', 'formidable' ); ?>
928
			</a>
929
			<?php
930
		} elseif ( isset( $atts['link_hook'] ) ) {
931
			do_action( $atts['link_hook']['hook'], $atts['link_hook']['param'] );
932
		}
933
	}
934
935
	/**
936
	 * @since 3.06
937
	 */
938
	public static function show_search_box( $atts ) {
939
		$defaults = array(
940
			'placeholder' => '',
941
			'tosearch'    => '',
942
			'text'        => __( 'Search', 'formidable' ),
943
			'input_id'    => '',
944
		);
945
		$atts = array_merge( $defaults, $atts );
946
947
		if ( $atts['input_id'] === 'template' && empty( $atts['tosearch'] ) ) {
948
			$atts['tosearch'] = 'frm-card';
949
		}
950
951
		$class = 'frm-search-input';
952
		if ( ! empty( $atts['tosearch'] ) ) {
953
			$class .= ' frm-auto-search';
954
		}
955
956
		$input_id = $atts['input_id'] . '-search-input';
957
958
		?>
959
		<p class="frm-search">
960
			<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
961
				<?php echo esc_html( $atts['text'] ); ?>:
962
			</label>
963
			<span class="frmfont frm_search_icon"></span>
964
			<input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s"
965
				value="<?php _admin_search_query(); ?>" placeholder="<?php echo esc_attr( $atts['placeholder'] ); ?>"
966
				class="<?php echo esc_attr( $class ); ?>" data-tosearch="<?php echo esc_attr( $atts['tosearch'] ); ?>"
967
				<?php if ( ! empty( $atts['tosearch'] ) ) { ?>
968
				autocomplete="off"
969
				<?php } ?>
970
				/>
971
			<?php
972
			if ( empty( $atts['tosearch'] ) ) {
973
				submit_button( $atts['text'], 'button-secondary', '', false, array( 'id' => 'search-submit' ) );
974
			}
975
			?>
976
		</p>
977
		<?php
978
	}
979
980
	/**
981
	 * @param string $type
982
	 */
983
	public static function trigger_hook_load( $type, $object = null ) {
984
		// Only load the form hooks once.
985
		$hooks_loaded = apply_filters( 'frm_' . $type . '_hooks_loaded', false, $object );
986
		if ( ! $hooks_loaded ) {
987
			do_action( 'frm_load_' . $type . '_hooks' );
988
		}
989
	}
990
991
	/**
992
	 * Save all front-end js scripts into a single file
993
	 *
994
	 * @since 3.0
995
	 */
996
	public static function save_combined_js() {
997
		$file_atts = apply_filters(
998
			'frm_js_location',
999
			array(
1000
				'file_name'     => 'frm.min.js',
1001
				'new_file_path' => self::plugin_path() . '/js',
1002
			)
1003
		);
1004
		$new_file  = new FrmCreateFile( $file_atts );
1005
1006
		$files = array(
1007
			self::plugin_path() . '/js/jquery/jquery.placeholder.min.js',
1008
			self::plugin_path() . '/js/formidable.min.js',
1009
		);
1010
		$files = apply_filters( 'frm_combined_js_files', $files );
1011
		$new_file->combine_files( $files );
1012
	}
1013
1014
	/**
1015
	 * Check a value from a shortcode to see if true or false.
1016
	 * True when value is 1, true, 'true', 'yes'
1017
	 *
1018
	 * @since 1.07.10
1019
	 *
1020
	 * @param string $value The value to compare
1021
	 *
1022
	 * @return boolean True or False
1023
	 */
1024
	public static function is_true( $value ) {
1025
		return ( true === $value || 1 == $value || 'true' == $value || 'yes' == $value );
1026
	}
1027
1028
	public static function get_pages() {
1029
		$query = array(
1030
			'post_type'   => 'page',
1031
			'post_status' => array( 'publish', 'private' ),
1032
			'numberposts' => - 1,
1033
			'orderby'     => 'title',
1034
			'order'       => 'ASC',
1035
		);
1036
1037
		return get_posts( $query );
1038
	}
1039
1040
	/**
1041
	 * Renders an autocomplete page selection or a regular dropdown depending on
1042
	 * the total page count
1043
	 *
1044
	 * @since 4.03.06
1045
	 */
1046
	public static function maybe_autocomplete_pages_options( $args ) {
1047
		$args = self::preformat_selection_args( $args );
1048
1049
		$pages_count = wp_count_posts( 'page' );
1050
1051
		if ( $pages_count->publish <= 50 ) {
1052
			self::wp_pages_dropdown( $args );
1053
			return;
1054
		}
1055
1056
		wp_enqueue_script( 'jquery-ui-autocomplete' );
1057
1058
		$selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
0 ignored issues
show
Security Bug introduced by
It seems like $args['page_id'] can also be of type false; however, FrmAppHelper::get_post_param() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1059
		$title = '';
1060
1061
		if ( $selected ) {
1062
			$title = get_the_title( $selected );
1063
		}
1064
1065
		?>
1066
		<input type="text" class="frm-page-search"
1067
			placeholder="<?php esc_html_e( 'Select a Page', 'formidable' ); ?>"
1068
			value="<?php echo esc_attr( $title ); ?>" />
1069
		<input type="hidden" name="<?php echo esc_attr( $args['field_name'] ); ?>"
1070
			value="<?php echo esc_attr( $selected ); ?>" />
1071
		<?php
1072
	}
1073
1074
	/**
1075
	 * @param array   $args
1076
	 * @param string  $page_id Deprecated.
1077
	 * @param boolean $truncate Deprecated.
1078
	 */
1079
	public static function wp_pages_dropdown( $args = array(), $page_id = '', $truncate = false ) {
1080
		self::prep_page_dropdown_params( $page_id, $truncate, $args );
1081
1082
		$pages    = self::get_pages();
1083
		$selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1084
1085
		?>
1086
		<select name="<?php echo esc_attr( $args['field_name'] ); ?>" id="<?php echo esc_attr( $args['field_name'] ); ?>" class="frm-pages-dropdown">
1087
			<option value=""><?php echo esc_html( $args['placeholder'] ); ?></option>
1088
			<?php foreach ( $pages as $page ) { ?>
1089
				<option value="<?php echo esc_attr( $page->ID ); ?>" <?php selected( $selected, $page->ID ); ?>>
1090
					<?php echo esc_html( $args['truncate'] ? self::truncate( $page->post_title, $args['truncate'] ) : $page->post_title ); ?>
1091
				</option>
1092
			<?php } ?>
1093
		</select>
1094
		<?php
1095
	}
1096
1097
	/**
1098
	 * Fill in missing parameters passed to wp_pages_dropdown().
1099
	 * This is for reverse compatibility with switching 3 params to 1.
1100
	 *
1101
	 * @since 4.03.06
1102
	 */
1103
	private static function prep_page_dropdown_params( $page_id, $truncate, &$args ) {
1104
		if ( ! is_array( $args ) ) {
1105
			$args = array(
1106
				'field_name' => $args,
1107
				'page_id'    => $page_id,
1108
				'truncate'   => $truncate,
1109
			);
1110
		}
1111
1112
		$args = self::preformat_selection_args( $args );
1113
	}
1114
1115
	/**
1116
	 * Filter to format args for page dropdown or autocomplete
1117
	 *
1118
	 * @since 4.03.06
1119
	 */
1120
	private static function preformat_selection_args( $args ) {
1121
		$defaults = array(
1122
			'truncate'    => false,
1123
			'placeholder' => ' ',
1124
			'field_name'  => '',
1125
			'page_id'     => '',
1126
		);
1127
1128
		return array_merge( $defaults, $args );
1129
	}
1130
1131
	public static function post_edit_link( $post_id ) {
1132
		$post = get_post( $post_id );
1133
		if ( $post ) {
1134
			$post_url = admin_url( 'post.php?post=' . $post_id . '&action=edit' );
1135
			$post_url = self::maybe_full_screen_link( $post_url );
1136
1137
			return '<a href="' . esc_url( $post_url ) . '">' . self::truncate( $post->post_title, 50 ) . '</a>';
1138
		}
1139
1140
		return '';
1141
	}
1142
1143
	/**
1144
	 * Hide the WordPress menus on some pages.
1145
	 *
1146
	 * @since 4.0
1147
	 */
1148
	public static function is_full_screen() {
1149
		$full_builder = self::is_form_builder_page();
1150
		$styler       = self::is_admin_page( 'formidable-styles' ) || self::is_admin_page( 'formidable-styles2' );
1151
		$full_entries = self::simple_get( 'frm-full', 'absint' );
1152
1153
		return $full_builder || $full_entries || $styler || self::is_view_builder_page();
1154
	}
1155
1156
	/**
1157
	 * @since 4.0
1158
	 */
1159
	public static function maybe_full_screen_link( $link ) {
1160
		$is_full = self::simple_get( 'frm-full', 'absint' );
1161
		if ( $is_full && ! empty( $link ) && $link !== '#' ) {
1162
			$link .= '&frm-full=1';
1163
		}
1164
		return $link;
1165
	}
1166
1167
	/**
1168
	 * @param string        $field_name
1169
	 * @param string|array  $capability
1170
	 * @param string        $multiple 'single' and 'multiple'
1171
	 */
1172
	public static function wp_roles_dropdown( $field_name, $capability, $multiple = 'single' ) {
1173
		?>
1174
		<select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $field_name ); ?>"
1175
			<?php echo ( 'multiple' === $multiple ) ? 'multiple="multiple"' : ''; ?>
1176
			class="frm_multiselect">
1177
			<?php self::roles_options( $capability ); ?>
1178
		</select>
1179
		<?php
1180
	}
1181
1182
	/**
1183
	 * @since 4.07
1184
	 * @param array|string $selected
1185
	 * @param string $current
1186
	 */
1187
	private static function selected( $selected, $current ) {
1188
		if ( is_callable( 'FrmProAppHelper::selected' ) ) {
1189
			FrmProAppHelper::selected( $selected, $current );
1190
		} else {
1191
			selected( in_array( $current, (array) $selected, true ) );
1192
		}
1193
	}
1194
1195
	/**
1196
	 * @param string|array $capability
1197
	 */
1198
	public static function roles_options( $capability ) {
1199
		global $frm_vars;
1200
		if ( isset( $frm_vars['editable_roles'] ) ) {
1201
			$editable_roles = $frm_vars['editable_roles'];
1202
		} else {
1203
			$editable_roles             = get_editable_roles();
1204
			$frm_vars['editable_roles'] = $editable_roles;
1205
		}
1206
1207
		foreach ( $editable_roles as $role => $details ) {
1208
			$name = translate_user_role( $details['name'] );
1209
			?>
1210
			<option value="<?php echo esc_attr( $role ); ?>" <?php self::selected( $capability, $role ); ?>><?php echo esc_attr( $name ); ?> </option>
1211
			<?php
1212
			unset( $role, $details );
1213
		}
1214
	}
1215
1216
	public static function frm_capabilities( $type = 'auto' ) {
1217
		$cap = array(
1218
			'frm_view_forms'      => __( 'View Forms', 'formidable' ),
1219
			'frm_edit_forms'      => __( 'Add and Edit Forms', 'formidable' ),
1220
			'frm_delete_forms'    => __( 'Delete Forms', 'formidable' ),
1221
			'frm_change_settings' => __( 'Access this Settings Page', 'formidable' ),
1222
			'frm_view_entries'    => __( 'View Entries from Admin Area', 'formidable' ),
1223
			'frm_delete_entries'  => __( 'Delete Entries from Admin Area', 'formidable' ),
1224
		);
1225
1226
		if ( ! self::pro_is_installed() && 'pro' != $type ) {
1227
			return $cap;
1228
		}
1229
1230
		$cap['frm_create_entries'] = __( 'Add Entries from Admin Area', 'formidable' );
1231
		$cap['frm_edit_entries']   = __( 'Edit Entries from Admin Area', 'formidable' );
1232
		$cap['frm_view_reports']   = __( 'View Reports', 'formidable' );
1233
		$cap['frm_edit_displays']  = __( 'Add/Edit Views', 'formidable' );
1234
1235
		return $cap;
1236
	}
1237
1238
	/**
1239
	 * Call the WordPress current_user_can but also validate empty strings as true for any logged in user
1240
	 *
1241
	 * @since 4.06.03
1242
	 *
1243
	 * @param string $role
1244
	 *
1245
	 * @return bool
1246
	 */
1247
	public static function current_user_can( $role ) {
1248
		if ( $role === '-1' ) {
1249
			return false;
1250
		}
1251
1252
		if ( $role === 'loggedout' ) {
1253
			return ! is_user_logged_in();
1254
		}
1255
1256
		if ( $role === 'loggedin' || ! $role ) {
1257
			return is_user_logged_in();
1258
		}
1259
1260
		if ( $role == 1 ) {
1261
			$role = 'administrator';
1262
		}
1263
1264
		if ( ! is_user_logged_in() ) {
1265
			return false;
1266
		}
1267
1268
		return current_user_can( $role );
1269
	}
1270
1271
	/**
1272
	 * @param string|array $needed_role
1273
	 * @return bool
1274
	 */
1275
	public static function user_has_permission( $needed_role ) {
1276
		if ( is_array( $needed_role ) ) {
1277
			foreach ( $needed_role as $role ) {
1278
				if ( self::current_user_can( $role ) ) {
1279
					return true;
1280
				}
1281
			}
1282
1283
			return false;
1284
		}
1285
1286
		$can = self::current_user_can( $needed_role );
1287
1288
		if ( $can || in_array( $needed_role, array( '-1', 'loggedout' ) ) ) {
1289
			return $can;
1290
		}
1291
1292
		$roles = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' );
1293
		foreach ( $roles as $role ) {
1294
			if ( current_user_can( $role ) ) {
1295
				return true;
1296
			}
1297
			if ( $role == $needed_role ) {
1298
				break;
1299
			}
1300
		}
1301
1302
		return false;
1303
	}
1304
1305
	/**
1306
	 * Make sure administrators can see Formidable menu
1307
	 *
1308
	 * @since 2.0
1309
	 */
1310
	public static function maybe_add_permissions() {
1311
		self::force_capability( 'frm_view_entries' );
1312
1313
		if ( ! current_user_can( 'administrator' ) || current_user_can( 'frm_view_forms' ) ) {
1314
			return;
1315
		}
1316
1317
		$user_id   = get_current_user_id();
1318
		$user      = new WP_User( $user_id );
1319
		$frm_roles = self::frm_capabilities();
1320
		foreach ( $frm_roles as $frm_role => $frm_role_description ) {
1321
			$user->add_cap( $frm_role );
1322
			unset( $frm_role, $frm_role_description );
1323
		}
1324
	}
1325
1326
	/**
1327
	 * Make sure admins have permission to see the menu items
1328
	 *
1329
	 * @since 2.0.6
1330
	 */
1331
	public static function force_capability( $cap = 'frm_change_settings' ) {
1332
		if ( current_user_can( 'administrator' ) && ! current_user_can( $cap ) ) {
1333
			$role      = get_role( 'administrator' );
1334
			$frm_roles = self::frm_capabilities();
1335
			foreach ( $frm_roles as $frm_role => $frm_role_description ) {
1336
				$role->add_cap( $frm_role );
1337
			}
1338
		}
1339
	}
1340
1341
	/**
1342
	 * Check if the user has permision for action.
1343
	 * Return permission message and stop the action if no permission
1344
	 *
1345
	 * @since 2.0
1346
	 *
1347
	 * @param string $permission
1348
	 */
1349
	public static function permission_check( $permission, $show_message = 'show' ) {
1350
		$permission_error = self::permission_nonce_error( $permission );
1351
		if ( $permission_error !== false ) {
1352
			if ( 'hide' == $show_message ) {
1353
				$permission_error = '';
1354
			}
1355
			wp_die( esc_html( $permission_error ) );
1356
		}
1357
	}
1358
1359
	/**
1360
	 * Check user permission and nonce
1361
	 *
1362
	 * @since 2.0
1363
	 *
1364
	 * @param string $permission
1365
	 *
1366
	 * @return false|string The permission message or false if allowed
1367
	 */
1368
	public static function permission_nonce_error( $permission, $nonce_name = '', $nonce = '' ) {
1369
		if ( ! empty( $permission ) && ! current_user_can( $permission ) && ! current_user_can( 'administrator' ) ) {
1370
			$frm_settings = self::get_settings();
1371
1372
			return $frm_settings->admin_permission;
1373
		}
1374
1375
		$error = false;
1376
		if ( empty( $nonce_name ) ) {
1377
			return $error;
1378
		}
1379
1380
		$nonce_value = ( $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
1381
		if ( $_REQUEST && ( ! isset( $_REQUEST[ $nonce_name ] ) || ! wp_verify_nonce( $nonce_value, $nonce ) ) ) {
1382
			$frm_settings = self::get_settings();
1383
			$error        = $frm_settings->admin_permission;
1384
		}
1385
1386
		return $error;
1387
	}
1388
1389
	public static function checked( $values, $current ) {
1390
		if ( self::check_selected( $values, $current ) ) {
1391
			echo ' checked="checked"';
1392
		}
1393
	}
1394
1395
	public static function check_selected( $values, $current ) {
1396
		$values  = self::recursive_function_map( $values, 'trim' );
1397
		$values  = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1398
		$current = htmlspecialchars_decode( trim( $current ) );
1399
1400
		return ( is_array( $values ) && in_array( $current, $values ) ) || ( ! is_array( $values ) && $values == $current );
1401
	}
1402
1403
	public static function recursive_function_map( $value, $function ) {
1404
		if ( is_array( $value ) ) {
1405
			$original_function = $function;
1406
			if ( count( $value ) ) {
1407
				$function = explode( ', ', FrmDb::prepare_array_values( $value, $function ) );
1408
			} else {
1409
				$function = array( $function );
1410
			}
1411
			if ( ! self::is_assoc( $value ) ) {
1412
				$value = array_map( array( 'FrmAppHelper', 'recursive_function_map' ), $value, $function );
1413
			} else {
1414
				foreach ( $value as $k => $v ) {
1415
					if ( ! is_array( $v ) ) {
1416
						$value[ $k ] = call_user_func( $original_function, $v );
1417
					}
1418
				}
1419
			}
1420
		} else {
1421
			$value = call_user_func( $function, $value );
1422
		}
1423
1424
		return $value;
1425
	}
1426
1427
	public static function is_assoc( $array ) {
1428
		return (bool) count( array_filter( array_keys( $array ), 'is_string' ) );
1429
	}
1430
1431
	/**
1432
	 * Flatten a multi-dimensional array
1433
	 */
1434
	public static function array_flatten( $array, $keys = 'keep' ) {
1435
		$return = array();
1436
		foreach ( $array as $key => $value ) {
1437
			if ( is_array( $value ) ) {
1438
				$return = array_merge( $return, self::array_flatten( $value, $keys ) );
1439
			} else {
1440
				if ( $keys == 'keep' ) {
1441
					$return[ $key ] = $value;
1442
				} else {
1443
					$return[] = $value;
1444
				}
1445
			}
1446
		}
1447
1448
		return $return;
1449
	}
1450
1451
	public static function esc_textarea( $text, $is_rich_text = false ) {
1452
		$safe_text = str_replace( '&quot;', '"', $text );
1453
		if ( ! $is_rich_text ) {
1454
			$safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
1455
		}
1456
		$safe_text = str_replace( '&amp; ', '& ', $safe_text );
1457
1458
		return apply_filters( 'esc_textarea', $safe_text, $text );
1459
	}
1460
1461
	/**
1462
	 * Add auto paragraphs to text areas
1463
	 *
1464
	 * @since 2.0
1465
	 */
1466
	public static function use_wpautop( $content ) {
1467
		if ( apply_filters( 'frm_use_wpautop', true ) && ! is_array( $content ) ) {
1468
			$content = wpautop( str_replace( '<br>', '<br />', $content ) );
1469
		}
1470
1471
		return $content;
1472
	}
1473
1474
	public static function replace_quotes( $val ) {
1475
		// Replace double quotes.
1476
		$val = str_replace( array( '&#8220;', '&#8221;', '&#8243;' ), '"', $val );
1477
1478
		// Replace single quotes.
1479
		$val = str_replace( array( '&#8216;', '&#8217;', '&#8242;', '&prime;', '&rsquo;', '&lsquo;' ), "'", $val );
1480
1481
		return $val;
1482
	}
1483
1484
	/**
1485
	 * @since 2.0
1486
	 * @return string The base Google APIS url for the current version of jQuery UI
1487
	 */
1488
	public static function jquery_ui_base_url() {
1489
		$url = 'http' . ( is_ssl() ? 's' : '' ) . '://ajax.googleapis.com/ajax/libs/jqueryui/' . self::script_version( 'jquery-ui-core', '1.11.4' );
1490
		$url = apply_filters( 'frm_jquery_ui_base_url', $url );
1491
1492
		return $url;
1493
	}
1494
1495
	/**
1496
	 * @param string $handle
1497
	 */
1498
	public static function script_version( $handle, $default = 0 ) {
1499
		global $wp_scripts;
1500
		if ( ! $wp_scripts ) {
1501
			return $default;
1502
		}
1503
1504
		$ver = $default;
1505
		if ( ! isset( $wp_scripts->registered[ $handle ] ) ) {
1506
			return $ver;
1507
		}
1508
1509
		$query = $wp_scripts->registered[ $handle ];
1510
		if ( is_object( $query ) && ! empty( $query->ver ) ) {
1511
			$ver = $query->ver;
1512
		}
1513
1514
		return $ver;
1515
	}
1516
1517
	public static function js_redirect( $url ) {
1518
		return '<script type="text/javascript">window.location="' . esc_url_raw( $url ) . '"</script>';
1519
	}
1520
1521
	public static function get_user_id_param( $user_id ) {
1522
		if ( ! $user_id || empty( $user_id ) || is_numeric( $user_id ) ) {
1523
			return $user_id;
1524
		}
1525
1526
		$user_id = sanitize_text_field( $user_id );
1527
		if ( $user_id == 'current' ) {
1528
			$user_id = get_current_user_id();
1529
		} else {
1530
			if ( is_email( $user_id ) ) {
1531
				$user = get_user_by( 'email', $user_id );
1532
			} else {
1533
				$user = get_user_by( 'login', $user_id );
1534
			}
1535
1536
			if ( $user ) {
1537
				$user_id = $user->ID;
1538
			}
1539
			unset( $user );
1540
		}
1541
1542
		return $user_id;
1543
	}
1544
1545
	public static function get_file_contents( $filename, $atts = array() ) {
1546
		if ( ! is_file( $filename ) ) {
1547
			return false;
1548
		}
1549
1550
		extract( $atts );
1551
		ob_start();
1552
		include( $filename );
1553
		$contents = ob_get_contents();
1554
		ob_end_clean();
1555
1556
		return $contents;
1557
	}
1558
1559
	/**
1560
	 * @param string $table_name
1561
	 * @param string $column
1562
	 * @param int $id
1563
	 * @param int $num_chars
1564
	 */
1565
	public static function get_unique_key( $name = '', $table_name, $column, $id = 0, $num_chars = 5 ) {
1566
		$key = '';
1567
1568
		if ( ! empty( $name ) ) {
1569
			$key = sanitize_key( $name );
1570
		}
1571
1572
		if ( empty( $key ) ) {
1573
			$max_slug_value = pow( 36, $num_chars );
1574
			$min_slug_value = 37; // we want to have at least 2 characters in the slug
1575
			$key            = base_convert( rand( $min_slug_value, $max_slug_value ), 10, 36 );
1576
		}
1577
1578
		$not_allowed = array(
1579
			'id',
1580
			'key',
1581
			'created-at',
1582
			'detaillink',
1583
			'editlink',
1584
			'siteurl',
1585
			'evenodd',
1586
		);
1587
1588
		if ( is_numeric( $key ) || in_array( $key, $not_allowed ) ) {
1589
			$key = $key . 'a';
1590
		}
1591
1592
		$key_check = FrmDb::get_var(
1593
			$table_name,
1594
			array(
1595
				$column => $key,
1596
				'ID !'  => $id,
1597
			),
1598
			$column
1599
		);
1600
1601
		if ( $key_check || is_numeric( $key_check ) ) {
1602
			// Create a unique field id if it has already been used.
1603
			$key = $key . substr( md5( microtime() . rand() ), 0, 10 );
1604
		}
1605
1606
		return $key;
1607
	}
1608
1609
	/**
1610
	 * Editing a Form or Entry
1611
	 *
1612
	 * @param string $table
1613
	 *
1614
	 * @return bool|array
1615
	 */
1616
	public static function setup_edit_vars( $record, $table, $fields = '', $default = false, $post_values = array(), $args = array() ) {
1617
		if ( ! $record ) {
1618
			return false;
1619
		}
1620
1621
		if ( empty( $post_values ) ) {
1622
			$post_values = wp_unslash( $_POST );
1623
		}
1624
1625
		$values = array(
1626
			'id'     => $record->id,
1627
			'fields' => array(),
1628
		);
1629
1630
		foreach ( array( 'name', 'description' ) as $var ) {
1631
			$default_val    = isset( $record->{$var} ) ? $record->{$var} : '';
1632
			$values[ $var ] = self::get_param( $var, $default_val, 'get', 'wp_kses_post' );
1633
			unset( $var, $default_val );
1634
		}
1635
1636
		$values['description'] = self::use_wpautop( $values['description'] );
1637
1638
		self::fill_form_opts( $record, $table, $post_values, $values );
1639
1640
		self::prepare_field_arrays( $fields, $record, $values, array_merge( $args, compact( 'default', 'post_values' ) ) );
1641
1642
		if ( $table == 'entries' ) {
1643
			$values = FrmEntriesHelper::setup_edit_vars( $values, $record );
1644
		} elseif ( $table == 'forms' ) {
1645
			$values = FrmFormsHelper::setup_edit_vars( $values, $record, $post_values );
1646
		}
1647
1648
		return $values;
1649
	}
1650
1651
	private static function prepare_field_arrays( $fields, $record, array &$values, $args ) {
1652
		if ( ! empty( $fields ) ) {
1653
			foreach ( (array) $fields as $field ) {
1654
				if ( ! self::is_admin_page() ) {
1655
					// Don't prep default values on the form settings page.
1656
					$field->default_value = apply_filters( 'frm_get_default_value', $field->default_value, $field, true );
1657
				}
1658
				$args['parent_form_id'] = isset( $args['parent_form_id'] ) ? $args['parent_form_id'] : $field->form_id;
1659
				self::fill_field_defaults( $field, $record, $values, $args );
1660
			}
1661
		}
1662
	}
1663
1664
	private static function fill_field_defaults( $field, $record, array &$values, $args ) {
1665
		$post_values = $args['post_values'];
1666
1667
		if ( $args['default'] ) {
1668
			$meta_value = $field->default_value;
1669
		} else {
1670
			if ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
1671
				if ( ! isset( $field->field_options['custom_field'] ) ) {
1672
					$field->field_options['custom_field'] = '';
1673
				}
1674
				$meta_value = FrmProEntryMetaHelper::get_post_value(
1675
					$record->post_id,
1676
					$field->field_options['post_field'],
1677
					$field->field_options['custom_field'],
1678
					array(
1679
						'truncate' => false,
1680
						'type'     => $field->type,
1681
						'form_id'  => $field->form_id,
1682
						'field'    => $field,
1683
					)
1684
				);
1685
			} else {
1686
				$meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
1687
			}
1688
		}
1689
1690
		$field_type = isset( $post_values['field_options'][ 'type_' . $field->id ] ) ? $post_values['field_options'][ 'type_' . $field->id ] : $field->type;
1691
		if ( isset( $post_values['item_meta'][ $field->id ] ) ) {
1692
			$new_value = $post_values['item_meta'][ $field->id ];
1693
			self::unserialize_or_decode( $new_value );
1694
		} else {
1695
			$new_value = $meta_value;
1696
		}
1697
1698
		$field_array                   = self::start_field_array( $field );
1699
		$field_array['value']          = $new_value;
1700
		$field_array['type']           = apply_filters( 'frm_field_type', $field_type, $field, $new_value );
1701
		$field_array['parent_form_id'] = $args['parent_form_id'];
1702
1703
		$args['field_type'] = $field_type;
1704
1705
		FrmFieldsHelper::prepare_edit_front_field( $field_array, $field, $values['id'], $args );
1706
1707
		if ( ! isset( $field_array['unique'] ) || ! $field_array['unique'] ) {
1708
			$field_array['unique_msg'] = '';
1709
		}
1710
1711
		$field_array = array_merge( (array) $field->field_options, $field_array );
1712
1713
		$values['fields'][ $field->id ] = $field_array;
1714
	}
1715
1716
	/**
1717
	 * @since 3.0
1718
	 *
1719
	 * @param object $field
1720
	 *
1721
	 * @return array
1722
	 */
1723
	public static function start_field_array( $field ) {
1724
		return array(
1725
			'id'            => $field->id,
1726
			'default_value' => $field->default_value,
1727
			'name'          => $field->name,
1728
			'description'   => $field->description,
1729
			'options'       => $field->options,
1730
			'required'      => $field->required,
1731
			'field_key'     => $field->field_key,
1732
			'field_order'   => $field->field_order,
1733
			'form_id'       => $field->form_id,
1734
		);
1735
	}
1736
1737
	/**
1738
	 * @param string $table
1739
	 */
1740
	private static function fill_form_opts( $record, $table, $post_values, array &$values ) {
1741
		if ( $table == 'entries' ) {
1742
			$form = $record->form_id;
1743
			FrmForm::maybe_get_form( $form );
1744
		} else {
1745
			$form = $record;
1746
		}
1747
1748
		if ( ! $form ) {
1749
			return;
1750
		}
1751
1752
		$values['form_name']      = isset( $record->form_id ) ? $form->name : '';
1753
		$values['parent_form_id'] = isset( $record->form_id ) ? $form->parent_form_id : 0;
1754
1755
		if ( ! is_array( $form->options ) ) {
1756
			return;
1757
		}
1758
1759
		foreach ( $form->options as $opt => $value ) {
1760
			if ( isset( $post_values[ $opt ] ) ) {
1761
				$values[ $opt ] = $post_values[ $opt ];
1762
				self::unserialize_or_decode( $values[ $opt ] );
1763
			} else {
1764
				$values[ $opt ] = $value;
1765
			}
1766
		}
1767
1768
		self::fill_form_defaults( $post_values, $values );
1769
	}
1770
1771
	/**
1772
	 * Set to POST value or default
1773
	 */
1774
	private static function fill_form_defaults( $post_values, array &$values ) {
1775
		$form_defaults = FrmFormsHelper::get_default_opts();
1776
1777
		foreach ( $form_defaults as $opt => $default ) {
1778
			if ( ! isset( $values[ $opt ] ) || $values[ $opt ] == '' ) {
1779
				$values[ $opt ] = ( $post_values && isset( $post_values['options'][ $opt ] ) ) ? $post_values['options'][ $opt ] : $default;
1780
			}
1781
1782
			unset( $opt, $default );
1783
		}
1784
1785
		if ( ! isset( $values['custom_style'] ) ) {
1786
			$values['custom_style'] = self::custom_style_value( $post_values );
1787
		}
1788
1789
		foreach ( array( 'before', 'after', 'submit' ) as $h ) {
1790
			if ( ! isset( $values[ $h . '_html' ] ) ) {
1791
				$values[ $h . '_html' ] = ( isset( $post_values['options'][ $h . '_html' ] ) ? $post_values['options'][ $h . '_html' ] : FrmFormsHelper::get_default_html( $h ) );
1792
			}
1793
			unset( $h );
1794
		}
1795
	}
1796
1797
	/**
1798
	 * @since 2.2.10
1799
	 *
1800
	 * @param array $post_values
1801
	 *
1802
	 * @return boolean|int
1803
	 */
1804
	public static function custom_style_value( $post_values ) {
1805
		if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
1806
			$custom_style = absint( $post_values['options']['custom_style'] );
1807
		} else {
1808
			$frm_settings = self::get_settings();
1809
			$custom_style = ( $frm_settings->load_style != 'none' );
1810
		}
1811
1812
		return $custom_style;
1813
	}
1814
1815
	public static function truncate( $str, $length, $minword = 3, $continue = '...' ) {
1816
		if ( is_array( $str ) ) {
1817
			return '';
1818
		}
1819
1820
		$length       = (int) $length;
1821
		$str          = wp_strip_all_tags( $str );
1822
		$original_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $str ) );
1823
1824
		if ( $length == 0 ) {
1825
			return '';
1826
		} elseif ( $length <= 10 ) {
1827
			$sub = self::mb_function( array( 'mb_substr', 'substr' ), array( $str, 0, $length ) );
1828
1829
			return $sub . ( ( $length < $original_len ) ? $continue : '' );
1830
		}
1831
1832
		$sub = '';
1833
		$len = 0;
1834
1835
		$words = self::mb_function( array( 'mb_split', 'explode' ), array( ' ', $str ) );
1836
1837
		foreach ( $words as $word ) {
1838
			$part      = ( ( $sub != '' ) ? ' ' : '' ) . $word;
1839
			$total_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $sub . $part ) );
1840
			if ( $total_len > $length && substr_count( $sub, ' ' ) ) {
1841
				break;
1842
			}
1843
1844
			$sub .= $part;
1845
			$len += self::mb_function( array( 'mb_strlen', 'strlen' ), array( $part ) );
1846
1847
			if ( substr_count( $sub, ' ' ) > $minword && $total_len >= $length ) {
1848
				break;
1849
			}
1850
1851
			unset( $total_len, $word );
1852
		}
1853
1854
		return $sub . ( ( $len < $original_len ) ? $continue : '' );
1855
	}
1856
1857
	public static function mb_function( $function_names, $args ) {
1858
		$mb_function_name = $function_names[0];
1859
		$function_name    = $function_names[1];
1860
		if ( function_exists( $mb_function_name ) ) {
1861
			$function_name = $mb_function_name;
1862
		}
1863
1864
		return call_user_func_array( $function_name, $args );
1865
	}
1866
1867
	public static function get_formatted_time( $date, $date_format = '', $time_format = '' ) {
1868
		if ( empty( $date ) ) {
1869
			return $date;
1870
		}
1871
1872
		if ( empty( $date_format ) ) {
1873
			$date_format = get_option( 'date_format' );
1874
		}
1875
1876
		if ( preg_match( '/^\d{1-2}\/\d{1-2}\/\d{4}$/', $date ) && self::pro_is_installed() ) {
1877
			$frmpro_settings = new FrmProSettings();
1878
			$date            = FrmProAppHelper::convert_date( $date, $frmpro_settings->date_format, 'Y-m-d' );
1879
		}
1880
1881
		$formatted = self::get_localized_date( $date_format, $date );
1882
1883
		$do_time = ( gmdate( 'H:i:s', strtotime( $date ) ) != '00:00:00' );
1884
		if ( $do_time ) {
1885
			$formatted .= self::add_time_to_date( $time_format, $date );
1886
		}
1887
1888
		return $formatted;
1889
	}
1890
1891
	private static function add_time_to_date( $time_format, $date ) {
1892
		if ( empty( $time_format ) ) {
1893
			$time_format = get_option( 'time_format' );
1894
		}
1895
1896
		$trimmed_format = trim( $time_format );
1897
		$time           = '';
1898
		if ( $time_format && ! empty( $trimmed_format ) ) {
1899
			$time = ' ' . __( 'at', 'formidable' ) . ' ' . self::get_localized_date( $time_format, $date );
1900
		}
1901
1902
		return $time;
1903
	}
1904
1905
	/**
1906
	 * @since 2.0.8
1907
	 */
1908
	public static function get_localized_date( $date_format, $date ) {
1909
		$date = get_date_from_gmt( $date );
1910
1911
		return date_i18n( $date_format, strtotime( $date ) );
1912
	}
1913
1914
	/**
1915
	 * Gets the time ago in words
1916
	 *
1917
	 * @param int $from in seconds
1918
	 * @param int|string $to in seconds
1919
	 *
1920
	 * @return string $time_ago
1921
	 */
1922
	public static function human_time_diff( $from, $to = '', $levels = 1 ) {
1923
		if ( empty( $to ) ) {
1924
			$now = new DateTime();
1925
		} else {
1926
			$now = new DateTime( '@' . $to );
1927
		}
1928
		$ago = new DateTime( '@' . $from );
1929
1930
		// Get the time difference
1931
		$diff_object = $now->diff( $ago );
1932
		$diff        = get_object_vars( $diff_object );
1933
1934
		// Add week amount and update day amount
1935
		$diff['w'] = floor( $diff['d'] / 7 );
1936
		$diff['d'] -= $diff['w'] * 7;
1937
1938
		$time_strings = self::get_time_strings();
1939
1940
		if ( ! is_numeric( $levels ) ) {
1941
			// Show time in specified unit.
1942
			$levels = self::get_unit( $levels );
1943
			if ( isset( $time_strings[ $levels ] ) ) {
1944
				$diff = array(
1945
					$levels => self::time_format( $levels, $diff ),
1946
				);
1947
				$time_strings = array(
1948
					$levels => $time_strings[ $levels ],
1949
				);
1950
			}
1951
			$levels = 1;
1952
		}
1953
1954
		foreach ( $time_strings as $k => $v ) {
1955
			if ( isset( $diff[ $k ] ) && $diff[ $k ] ) {
1956
				$time_strings[ $k ] = $diff[ $k ] . ' ' . ( $diff[ $k ] > 1 ? $v[1] : $v[0] );
1957
			} elseif ( isset( $diff[ $k ] ) && count( $time_strings ) === 1 ) {
1958
				// Account for 0.
1959
				$time_strings[ $k ] = $diff[ $k ] . ' ' . $v[1];
1960
			} else {
1961
				unset( $time_strings[ $k ] );
1962
			}
1963
		}
1964
1965
		$levels_deep     = apply_filters( 'frm_time_ago_levels', $levels, compact( 'time_strings', 'from', 'to' ) );
1966
		$time_strings    = array_slice( $time_strings, 0, absint( $levels_deep ) );
1967
		$time_ago_string = implode( ' ', $time_strings );
1968
1969
		return $time_ago_string;
1970
	}
1971
1972
	/**
1973
	 * @since 4.05.01
1974
	 */
1975
	private static function time_format( $unit, $diff ) {
1976
		$return = array(
1977
			'y' => 'y',
1978
			'd' => 'days',
1979
		);
1980
		if ( isset( $return[ $unit ] ) ) {
1981
			return $diff[ $return[ $unit ] ];
1982
		}
1983
1984
		$total = $diff['days'] * self::convert_time( 'd', $unit );
1985
1986
		$times = array( 'h', 'i', 's' );
1987
1988
		foreach ( $times as $time ) {
1989
			if ( ! isset( $diff[ $time ] ) ) {
1990
				continue;
1991
			}
1992
1993
			$total += $diff[ $time ] * self::convert_time( $time, $unit );
1994
		}
1995
1996
		return floor( $total );
1997
	}
1998
1999
	/**
2000
	 * @since 4.05.01
2001
	 */
2002
	private static function convert_time( $from, $to ) {
2003
		$convert = array(
2004
			's' => 1,
2005
			'i' => MINUTE_IN_SECONDS,
2006
			'h' => HOUR_IN_SECONDS,
2007
			'd' => DAY_IN_SECONDS,
2008
			'w' => WEEK_IN_SECONDS,
2009
			'm' => DAY_IN_SECONDS * 30.42,
2010
			'y' => DAY_IN_SECONDS * 365.25,
2011
		);
2012
2013
		return $convert[ $from ] / $convert[ $to ];
2014
	}
2015
2016
	/**
2017
	 * @since 4.05.01
2018
	 */
2019
	private static function get_unit( $unit ) {
2020
		$units = self::get_time_strings();
2021
		if ( isset( $units[ $unit ] ) || is_numeric( $unit ) ) {
2022
			return $unit;
2023
		}
2024
2025
		foreach ( $units as $u => $strings ) {
2026
			if ( in_array( $unit, $strings ) ) {
2027
				return $u;
2028
			}
2029
		}
2030
		return 1;
2031
	}
2032
2033
	/**
2034
	 * Get the translatable time strings. The untranslated version is a failsafe
2035
	 * in case langauges are changing for the unit set in the shortcode.
2036
	 *
2037
	 * @since 2.0.20
2038
	 * @return array
2039
	 */
2040
	private static function get_time_strings() {
2041
		return array(
2042
			'y' => array(
2043
				__( 'year', 'formidable' ),
2044
				__( 'years', 'formidable' ),
2045
				'year',
2046
			),
2047
			'm' => array(
2048
				__( 'month', 'formidable' ),
2049
				__( 'months', 'formidable' ),
2050
				'month',
2051
			),
2052
			'w' => array(
2053
				__( 'week', 'formidable' ),
2054
				__( 'weeks', 'formidable' ),
2055
				'week',
2056
			),
2057
			'd' => array(
2058
				__( 'day', 'formidable' ),
2059
				__( 'days', 'formidable' ),
2060
				'day',
2061
			),
2062
			'h' => array(
2063
				__( 'hour', 'formidable' ),
2064
				__( 'hours', 'formidable' ),
2065
				'hour',
2066
			),
2067
			'i' => array(
2068
				__( 'minute', 'formidable' ),
2069
				__( 'minutes', 'formidable' ),
2070
				'minute',
2071
			),
2072
			's' => array(
2073
				__( 'second', 'formidable' ),
2074
				__( 'seconds', 'formidable' ),
2075
				'second',
2076
			),
2077
		);
2078
	}
2079
2080
	// Pagination Methods.
2081
2082
	/**
2083
	 * @param integer $current_p
2084
	 */
2085
	public static function get_last_record_num( $r_count, $current_p, $p_size ) {
2086
		return ( ( $r_count < ( $current_p * $p_size ) ) ? $r_count : ( $current_p * $p_size ) );
2087
	}
2088
2089
	/**
2090
	 * @param integer $current_p
2091
	 */
2092
	public static function get_first_record_num( $r_count, $current_p, $p_size ) {
2093
		if ( $current_p == 1 ) {
2094
			return 1;
2095
		} else {
2096
			return ( self::get_last_record_num( $r_count, ( $current_p - 1 ), $p_size ) + 1 );
2097
		}
2098
	}
2099
2100
	/**
2101
	 * @return array
2102
	 */
2103
	public static function json_to_array( $json_vars ) {
2104
		$vars = array();
2105
		foreach ( $json_vars as $jv ) {
2106
			$jv_name = explode( '[', $jv['name'] );
2107
			$last    = count( $jv_name ) - 1;
2108
			foreach ( $jv_name as $p => $n ) {
2109
				$name = trim( $n, ']' );
2110
				if ( ! isset( $l1 ) ) {
2111
					$l1 = $name;
2112
				}
2113
2114
				if ( ! isset( $l2 ) ) {
2115
					$l2 = $name;
2116
				}
2117
2118
				if ( ! isset( $l3 ) ) {
2119
					$l3 = $name;
2120
				}
2121
2122
				$this_val = ( $p == $last ) ? $jv['value'] : array();
2123
2124
				switch ( $p ) {
2125
					case 0:
2126
						$l1 = $name;
2127
						self::add_value_to_array( $name, $l1, $this_val, $vars );
2128
						break;
2129
2130
					case 1:
2131
						$l2 = $name;
2132
						self::add_value_to_array( $name, $l2, $this_val, $vars[ $l1 ] );
2133
						break;
2134
2135 View Code Duplication
					case 2:
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...
2136
						$l3 = $name;
2137
						self::add_value_to_array( $name, $l3, $this_val, $vars[ $l1 ][ $l2 ] );
2138
						break;
2139
2140 View Code Duplication
					case 3:
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...
2141
						$l4 = $name;
2142
						self::add_value_to_array( $name, $l4, $this_val, $vars[ $l1 ][ $l2 ][ $l3 ] );
2143
				}
2144
2145
				unset( $this_val, $n );
2146
			}
2147
2148
			unset( $last, $jv );
2149
		}
2150
2151
		return $vars;
2152
	}
2153
2154
	/**
2155
	 * @param string $name
2156
	 * @param string $l1
2157
	 */
2158
	public static function add_value_to_array( $name, $l1, $val, &$vars ) {
2159
		if ( $name == '' ) {
2160
			$vars[] = $val;
2161
		} elseif ( ! isset( $vars[ $l1 ] ) ) {
2162
			$vars[ $l1 ] = $val;
2163
		}
2164
	}
2165
2166
	public static function maybe_add_tooltip( $name, $class = 'closed', $form_name = '' ) {
2167
		$tooltips = array(
2168
			'action_title'  => __( 'Give this action a label for easy reference.', 'formidable' ),
2169
			'email_to'      => __( 'Add one or more recipient addresses separated by a ",".  FORMAT: Name <[email protected]> or [email protected].  [admin_email] is the address set in WP General Settings.', 'formidable' ),
2170
			'cc'            => __( 'Add CC addresses separated by a ",".  FORMAT: Name <[email protected]> or [email protected].', 'formidable' ),
2171
			'bcc'           => __( 'Add BCC addresses separated by a ",".  FORMAT: Name <[email protected]> or [email protected].', 'formidable' ),
2172
			'reply_to'      => __( 'If you would like a different reply to address than the "from" address, add a single address here.  FORMAT: Name <[email protected]> or [email protected].', 'formidable' ),
2173
			'from'          => __( 'Enter the name and/or email address of the sender. FORMAT: John Bates <[email protected]> or [email protected].', 'formidable' ),
2174
			/* translators: %1$s: Form name, %2$s: Date */
2175
			'email_subject' => esc_attr( sprintf( __( 'If you leave the subject blank, the default will be used: %1$s Form submitted on %2$s', 'formidable' ), $form_name, self::site_name() ) ),
2176
		);
2177
2178
		if ( ! isset( $tooltips[ $name ] ) ) {
2179
			return;
2180
		}
2181
2182
		if ( 'open' == $class ) {
2183
			echo ' frm_help"';
2184
		} else {
2185
			echo ' class="frm_help"';
2186
		}
2187
2188
		echo ' title="' . esc_attr( $tooltips[ $name ] );
2189
2190
		if ( 'open' != $class ) {
2191
			echo '"';
2192
		}
2193
	}
2194
2195
	/**
2196
	 * Add the current_page class to that page in the form nav
2197
	 */
2198
	public static function select_current_page( $page, $current_page, $action = array() ) {
2199
		if ( $current_page != $page ) {
2200
			return;
2201
		}
2202
2203
		$frm_action = self::simple_get( 'frm_action', 'sanitize_title' );
2204
		if ( empty( $action ) || ( ! empty( $frm_action ) && in_array( $frm_action, $action ) ) ) {
2205
			echo ' class="current_page"';
2206
		}
2207
	}
2208
2209
	/**
2210
	 * Prepare and json_encode post content
2211
	 *
2212
	 * @since 2.0
2213
	 *
2214
	 * @param array $post_content
2215
	 *
2216
	 * @return string $post_content ( json encoded array )
2217
	 */
2218
	public static function prepare_and_encode( $post_content ) {
2219
		// Loop through array to strip slashes and add only the needed ones.
2220
		foreach ( $post_content as $key => $val ) {
2221
			// Replace problematic characters (like &quot;)
2222
			$val = str_replace( '&quot;', '"', $val );
2223
2224
			self::prepare_action_slashes( $val, $key, $post_content );
2225
			unset( $key, $val );
2226
		}
2227
2228
		// json_encode the array.
2229
		$post_content = json_encode( $post_content );
2230
2231
		// Add extra slashes for \r\n since WP strips them.
2232
		$post_content = str_replace( array( '\\r', '\\n', '\\u', '\\t' ), array( '\\\\r', '\\\\n', '\\\\u', '\\\\t' ), $post_content );
2233
2234
		// allow for &quot
2235
		$post_content = str_replace( '&quot;', '\\"', $post_content );
2236
2237
		return $post_content;
2238
	}
2239
2240
	private static function prepare_action_slashes( $val, $key, &$post_content ) {
2241
		if ( ! isset( $post_content[ $key ] ) ) {
2242
			return;
2243
		}
2244
2245
		if ( is_array( $val ) ) {
2246
			foreach ( $val as $k1 => $v1 ) {
2247
				self::prepare_action_slashes( $v1, $k1, $post_content[ $key ] );
2248
				unset( $k1, $v1 );
2249
			}
2250
		} else {
2251
			// Strip all slashes so everything is the same, no matter where the value is coming from
2252
			$val = stripslashes( $val );
2253
2254
			// Add backslashes before double quotes and forward slashes only
2255
			$post_content[ $key ] = addcslashes( $val, '"\\/' );
2256
		}
2257
	}
2258
2259
	/**
2260
	 * Check for either json or serilized data. This is temporary while transitioning
2261
	 * all data to json.
2262
	 *
2263
	 * @since 4.02.03
2264
	 */
2265
	public static function unserialize_or_decode( &$value ) {
2266
		if ( is_array( $value ) ) {
2267
			return;
2268
		}
2269
2270
		if ( is_serialized( $value ) ) {
2271
			$value = maybe_unserialize( $value );
2272
		} else {
2273
			$value = self::maybe_json_decode( $value, false );
2274
		}
2275
	}
2276
2277
	/**
2278
	 * Decode a JSON string.
2279
	 * Do not switch shortcodes like [24] to array unless intentional ie XML values.
2280
	 */
2281
	public static function maybe_json_decode( $string, $single_to_array = true ) {
2282
		if ( is_array( $string ) ) {
2283
			return $string;
2284
		}
2285
2286
		$new_string = json_decode( $string, true );
2287
		if ( function_exists( 'json_last_error' ) ) {
2288
			// php 5.3+
2289
			$single_value = false;
2290
			if ( ! $single_to_array ) {
2291
				$single_value = is_array( $new_string ) && count( $new_string ) === 1 && isset( $new_string[0] );
2292
			}
2293
			if ( json_last_error() == JSON_ERROR_NONE && is_array( $new_string ) && ! $single_value ) {
2294
				$string = $new_string;
2295
			}
2296
		}
2297
2298
		return $string;
2299
	}
2300
2301
	/**
2302
	 * Reformat the json serialized array in name => value array.
2303
	 *
2304
	 * @since 4.02.03
2305
	 */
2306
	public static function format_form_data( &$form ) {
2307
		$formatted = array();
2308
2309
		foreach ( $form as $input ) {
2310
			if ( ! isset( $input['name'] ) ) {
2311
				continue;
2312
			}
2313
			$key = $input['name'];
2314
			if ( isset( $formatted[ $key ] ) ) {
2315
				if ( is_array( $formatted[ $key ] ) ) {
2316
					$formatted[ $key ][] = $input['value'];
2317
				} else {
2318
					$formatted[ $key ] = array( $formatted[ $key ], $input['value'] );
2319
				}
2320
			} else {
2321
				$formatted[ $key ] = $input['value'];
2322
			}
2323
		}
2324
2325
		parse_str( http_build_query( $formatted ), $form );
2326
	}
2327
2328
	/**
2329
	 * @since 4.02.03
2330
	 */
2331
	public static function maybe_json_encode( $value ) {
2332
		if ( is_array( $value ) ) {
2333
			$value = wp_json_encode( $value );
2334
		}
2335
		return $value;
2336
	}
2337
2338
	/**
2339
	 * @since 1.07.10
2340
	 *
2341
	 * @param string $post_type The name of the post type that may need to be highlighted
2342
	 * echo The javascript to open and highlight the Formidable menu
2343
	 */
2344
	public static function maybe_highlight_menu( $post_type ) {
2345
		global $post;
2346
2347
		if ( isset( $_REQUEST['post_type'] ) && $_REQUEST['post_type'] != $post_type ) {
2348
			return;
2349
		}
2350
2351
		if ( is_object( $post ) && $post->post_type != $post_type ) {
2352
			return;
2353
		}
2354
2355
		self::load_admin_wide_js();
2356
		echo '<script type="text/javascript">jQuery(document).ready(function(){frmSelectSubnav();});</script>';
2357
	}
2358
2359
	/**
2360
	 * Load the JS file on non-Formidable pages in the admin area
2361
	 *
2362
	 * @since 2.0
2363
	 */
2364
	public static function load_admin_wide_js( $load = true ) {
2365
		$version = self::plugin_version();
2366
		wp_register_script( 'formidable_admin_global', self::plugin_url() . '/js/formidable_admin_global.js', array( 'jquery' ), $version );
2367
2368
		$global_strings = array(
2369
			'updating_msg' => __( 'Please wait while your site updates.', 'formidable' ),
2370
			'deauthorize'  => __( 'Are you sure you want to deauthorize Formidable Forms on this site?', 'formidable' ),
2371
			'url'          => self::plugin_url(),
2372
			'app_url'      => 'https://formidableforms.com/',
2373
			'loading'      => __( 'Loading&hellip;', 'formidable' ),
2374
			'nonce'        => wp_create_nonce( 'frm_ajax' ),
2375
		);
2376
		wp_localize_script( 'formidable_admin_global', 'frmGlobal', $global_strings );
2377
2378
		if ( $load ) {
2379
			wp_enqueue_script( 'formidable_admin_global' );
2380
		}
2381
	}
2382
2383
	/**
2384
	 * @since 2.0.9
2385
	 */
2386
	public static function load_font_style() {
2387
		wp_enqueue_style( 'frm_fonts', self::plugin_url() . '/css/frm_fonts.css', array(), self::plugin_version() );
2388
	}
2389
2390
	/**
2391
	 * @param string $location
2392
	 */
2393
	public static function localize_script( $location ) {
2394
		global $wp_scripts;
2395
2396
		$ajax_url = admin_url( 'admin-ajax.php', is_ssl() ? 'admin' : 'http' );
2397
		$ajax_url = apply_filters( 'frm_ajax_url', $ajax_url );
2398
2399
		$script_strings = array(
2400
			'ajax_url'     => $ajax_url,
2401
			'images_url'   => self::plugin_url() . '/images',
2402
			'loading'      => __( 'Loading&hellip;', 'formidable' ),
2403
			'remove'       => __( 'Remove', 'formidable' ),
2404
			'offset'       => apply_filters( 'frm_scroll_offset', 4 ),
2405
			'nonce'        => wp_create_nonce( 'frm_ajax' ),
2406
			'id'           => __( 'ID', 'formidable' ),
2407
			'no_results'   => __( 'No results match', 'formidable' ),
2408
			'file_spam'    => __( 'That file looks like Spam.', 'formidable' ),
2409
			'calc_error'   => __( 'There is an error in the calculation in the field with key', 'formidable' ),
2410
			'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
2411
		);
2412
2413
		$data = $wp_scripts->get_data( 'formidable', 'data' );
2414
		if ( empty( $data ) ) {
2415
			wp_localize_script( 'formidable', 'frm_js', $script_strings );
2416
		}
2417
2418
		if ( $location == 'admin' ) {
2419
			$frm_settings         = self::get_settings();
2420
			$admin_script_strings = array(
2421
				'desc'              => __( '(Click to add description)', 'formidable' ),
2422
				'blank'             => __( '(Blank)', 'formidable' ),
2423
				'no_label'          => __( '(no label)', 'formidable' ),
2424
				'saving'            => esc_attr( __( 'Saving', 'formidable' ) ),
2425
				'saved'             => esc_attr( __( 'Saved', 'formidable' ) ),
2426
				'ok'                => __( 'OK', 'formidable' ),
2427
				'cancel'            => __( 'Cancel', 'formidable' ),
2428
				'default_label'     => __( 'Default', 'formidable' ),
2429
				'clear_default'     => __( 'Clear default value when typing', 'formidable' ),
2430
				'no_clear_default'  => __( 'Do not clear default value when typing', 'formidable' ),
2431
				'valid_default'     => __( 'Default value will pass form validation', 'formidable' ),
2432
				'no_valid_default'  => __( 'Default value will NOT pass form validation', 'formidable' ),
2433
				'caution'           => __( 'Heads up', 'formidable' ),
2434
				'confirm'           => __( 'Are you sure?', 'formidable' ),
2435
				'conf_delete'       => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
2436
				'conf_delete_sec'   => __( 'All fields inside this Section will be deleted along with their data. Are you sure you want to delete this group of fields?', 'formidable' ),
2437
				'conf_no_repeat'    => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
2438
				'default_unique'    => $frm_settings->unique_msg,
2439
				'default_conf'      => __( 'The entered values do not match', 'formidable' ),
2440
				'enter_email'       => __( 'Enter Email', 'formidable' ),
2441
				'confirm_email'     => __( 'Confirm Email', 'formidable' ),
2442
				'conditional_text'  => __( 'Conditional content here', 'formidable' ),
2443
				'new_option'        => __( 'New Option', 'formidable' ),
2444
				'css_invalid_size'  => __( 'In certain browsers (e.g. Firefox) text will not display correctly if the field height is too small relative to the field padding and text size. Please increase your field height or decrease your field padding.', 'formidable' ),
2445
				'enter_password'    => __( 'Enter Password', 'formidable' ),
2446
				'confirm_password'  => __( 'Confirm Password', 'formidable' ),
2447
				'import_complete'   => __( 'Import Complete', 'formidable' ),
2448
				'updating'          => __( 'Please wait while your site updates.', 'formidable' ),
2449
				'no_save_warning'   => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
2450
				'private_label'     => __( 'Private', 'formidable' ),
2451
				'jquery_ui_url'     => self::jquery_ui_base_url(),
2452
				'pro_url'           => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
2453
				'no_licenses'       => __( 'No new licenses were found', 'formidable' ),
2454
				'unmatched_parens'  => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
2455
				'view_shortcodes'   => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
2456
				'text_shortcodes'   => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
2457
				'only_one_action'   => __( 'This form action is limited to one per form. Please edit the existing form action.', 'formidable' ),
2458
				'unsafe_params'     => FrmFormsHelper::reserved_words(),
2459
				/* Translators: %s is the name of a Detail Page Slug that is a reserved word.*/
2460
				'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
2461
				/* Translators: %s is the name of a parameter that is a reserved word.  More than one word could be listed here, though that would not be common. */
2462
				'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
2463
				'reserved_words'    => __( 'See the list of reserved words in WordPress.', 'formidable' ),
2464
				'repeat_limit_min'  => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
2465
				'checkbox_limit'    => __( 'Please select a limit between 0 and 200.', 'formidable' ),
2466
				'install'           => __( 'Install', 'formidable' ),
2467
				'active'            => __( 'Active', 'formidable' ),
2468
				'select_a_field'    => __( 'Select a Field', 'formidable' ),
2469
				'no_items_found'    => __( 'No items found.', 'formidable' ),
2470
			);
2471
			$admin_script_strings = apply_filters( 'frm_admin_script_strings', $admin_script_strings );
2472
2473
			$data = $wp_scripts->get_data( 'formidable_admin', 'data' );
2474
			if ( empty( $data ) ) {
2475
				wp_localize_script( 'formidable_admin', 'frm_admin_js', $admin_script_strings );
2476
			}
2477
		}
2478
	}
2479
2480
	/**
2481
	 * Echo the message on the plugins listing page
2482
	 *
2483
	 * @since 1.07.10
2484
	 *
2485
	 * @param float $min_version The version the add-on requires
2486
	 */
2487
	public static function min_version_notice( $min_version ) {
2488
		$frm_version = self::plugin_version();
2489
2490
		// Check if Formidable meets minimum requirements.
2491
		if ( version_compare( $frm_version, $min_version, '>=' ) ) {
2492
			return;
2493
		}
2494
2495
		$wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
2496
		echo '<tr class="plugin-update-tr active"><th colspan="' . absint( $wp_list_table->get_column_count() ) . '" class="check-column plugin-update colspanchange"><div class="update-message">' .
2497
			esc_html__( 'You are running an outdated version of Formidable. This plugin may not work correctly if you do not update Formidable.', 'formidable' ) .
2498
			'</div></td></tr>';
2499
	}
2500
2501
	/**
2502
	 * If Pro is far outdated, show a message.
2503
	 *
2504
	 * @since 4.0.01
2505
	 */
2506
	public static function min_pro_version_notice( $min_version ) {
2507
		if ( ! self::is_formidable_admin() ) {
2508
			// Don't show admin-wide.
2509
			return;
2510
		}
2511
2512
		self::php_version_notice();
2513
2514
		$is_pro = self::pro_is_installed() && class_exists( 'FrmProDb' );
2515
		if ( ! $is_pro || self::meets_min_pro_version( $min_version ) ) {
2516
			return;
2517
		}
2518
2519
		$pro_version = FrmProDb::$plug_version;
0 ignored issues
show
Unused Code introduced by
$pro_version is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2520
		$expired = FrmAddonsController::is_license_expired();
2521
		?>
2522
		<div class="error frm_previous_install">
2523
			<?php
2524
			esc_html_e( 'You are running a version of Formidable Forms that may not be compatible with your version of Formidable Forms Pro.', 'formidable' );
2525
			if ( empty( $expired ) ) {
2526
				echo ' Please <a href="' . esc_url( admin_url( 'plugins.php?s=formidable%20forms%20pro' ) ) . '">update now</a>.';
2527
			} else {
2528
				echo '<br/>Please <a href="https://formidableforms.com/account/downloads/?utm_source=WordPress&utm_medium=outdated">renew now</a> to get the latest Pro version or <a href="https://downloads.wordpress.org/plugin/formidable.<?php echo esc_attr( $pro_version ); ?>.zip">download the previous Lite version</a> to revert.';
2529
			}
2530
			?>
2531
		</div>
2532
		<?php
2533
	}
2534
2535
	/**
2536
	 * If Pro is installed, check the version number.
2537
	 *
2538
	 * @since 4.0.01
2539
	 */
2540
	public static function meets_min_pro_version( $min_version ) {
2541
		return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
2542
	}
2543
2544
	/**
2545
	 * Show a message if the browser or PHP version is below the recommendations.
2546
	 *
2547
	 * @since 4.0.02
2548
	 */
2549
	private static function php_version_notice() {
2550
		$message = array();
2551
		if ( version_compare( phpversion(), '5.6', '<' ) ) {
2552
			$message[] = __( 'The version of PHP on your server is too low. If this is not corrected, you may see issues with Formidable Forms. Please contact your web host and ask to be updated to PHP 7.0+.', 'formidable' );
2553
		}
2554
2555
		$browser = self::get_server_value( 'HTTP_USER_AGENT' );
2556
		$is_ie   = strpos( $browser, 'MSIE' ) !== false;
2557
		if ( $is_ie ) {
2558
			$message[] = __( 'You are using an outdated browser that is not compatible with Formidable Forms. Please update to a more current browser (we recommend Chrome).', 'formidable' );
2559
		}
2560
2561
		foreach ( $message as $m ) {
2562
			?>
2563
			<div class="error frm_previous_install">
2564
				<?php echo esc_html( $m ); ?>
2565
			</div>
2566
			<?php
2567
		}
2568
	}
2569
2570
	public static function locales( $type = 'date' ) {
2571
		$locales = array(
2572
			'en'     => __( 'English', 'formidable' ),
2573
			'af'     => __( 'Afrikaans', 'formidable' ),
2574
			'sq'     => __( 'Albanian', 'formidable' ),
2575
			'ar'     => __( 'Arabic', 'formidable' ),
2576
			'hy'     => __( 'Armenian', 'formidable' ),
2577
			'az'     => __( 'Azerbaijani', 'formidable' ),
2578
			'eu'     => __( 'Basque', 'formidable' ),
2579
			'bs'     => __( 'Bosnian', 'formidable' ),
2580
			'bg'     => __( 'Bulgarian', 'formidable' ),
2581
			'ca'     => __( 'Catalan', 'formidable' ),
2582
			'zh-HK'  => __( 'Chinese Hong Kong', 'formidable' ),
2583
			'zh-CN'  => __( 'Chinese Simplified', 'formidable' ),
2584
			'zh-TW'  => __( 'Chinese Traditional', 'formidable' ),
2585
			'hr'     => __( 'Croatian', 'formidable' ),
2586
			'cs'     => __( 'Czech', 'formidable' ),
2587
			'da'     => __( 'Danish', 'formidable' ),
2588
			'nl'     => __( 'Dutch', 'formidable' ),
2589
			'en-GB'  => __( 'English/UK', 'formidable' ),
2590
			'eo'     => __( 'Esperanto', 'formidable' ),
2591
			'et'     => __( 'Estonian', 'formidable' ),
2592
			'fo'     => __( 'Faroese', 'formidable' ),
2593
			'fa'     => __( 'Farsi/Persian', 'formidable' ),
2594
			'fil'    => __( 'Filipino', 'formidable' ),
2595
			'fi'     => __( 'Finnish', 'formidable' ),
2596
			'fr'     => __( 'French', 'formidable' ),
2597
			'fr-CA'  => __( 'French/Canadian', 'formidable' ),
2598
			'fr-CH'  => __( 'French/Swiss', 'formidable' ),
2599
			'de'     => __( 'German', 'formidable' ),
2600
			'de-AT'  => __( 'German/Austria', 'formidable' ),
2601
			'de-CH'  => __( 'German/Switzerland', 'formidable' ),
2602
			'el'     => __( 'Greek', 'formidable' ),
2603
			'he'     => __( 'Hebrew', 'formidable' ),
2604
			'iw'     => __( 'Hebrew', 'formidable' ),
2605
			'hi'     => __( 'Hindi', 'formidable' ),
2606
			'hu'     => __( 'Hungarian', 'formidable' ),
2607
			'is'     => __( 'Icelandic', 'formidable' ),
2608
			'id'     => __( 'Indonesian', 'formidable' ),
2609
			'it'     => __( 'Italian', 'formidable' ),
2610
			'ja'     => __( 'Japanese', 'formidable' ),
2611
			'ko'     => __( 'Korean', 'formidable' ),
2612
			'lv'     => __( 'Latvian', 'formidable' ),
2613
			'lt'     => __( 'Lithuanian', 'formidable' ),
2614
			'ms'     => __( 'Malaysian', 'formidable' ),
2615
			'no'     => __( 'Norwegian', 'formidable' ),
2616
			'pl'     => __( 'Polish', 'formidable' ),
2617
			'pt'     => __( 'Portuguese', 'formidable' ),
2618
			'pt-BR'  => __( 'Portuguese/Brazilian', 'formidable' ),
2619
			'pt-PT'  => __( 'Portuguese/Portugal', 'formidable' ),
2620
			'ro'     => __( 'Romanian', 'formidable' ),
2621
			'ru'     => __( 'Russian', 'formidable' ),
2622
			'sr'     => __( 'Serbian', 'formidable' ),
2623
			'sr-SR'  => __( 'Serbian', 'formidable' ),
2624
			'sk'     => __( 'Slovak', 'formidable' ),
2625
			'sl'     => __( 'Slovenian', 'formidable' ),
2626
			'es'     => __( 'Spanish', 'formidable' ),
2627
			'es-419' => __( 'Spanish/Latin America', 'formidable' ),
2628
			'sv'     => __( 'Swedish', 'formidable' ),
2629
			'ta'     => __( 'Tamil', 'formidable' ),
2630
			'th'     => __( 'Thai', 'formidable' ),
2631
			'tu'     => __( 'Turkish', 'formidable' ),
2632
			'tr'     => __( 'Turkish', 'formidable' ),
2633
			'uk'     => __( 'Ukranian', 'formidable' ),
2634
			'vi'     => __( 'Vietnamese', 'formidable' ),
2635
		);
2636
2637
		if ( $type === 'captcha' ) {
2638
			// remove the languages unavailable for the captcha
2639
			$unset = array( 'af', 'sq', 'hy', 'az', 'eu', 'bs', 'zh-HK', 'eo', 'et', 'fo', 'fr-CH', 'he', 'is', 'ms', 'sr-SR', 'ta', 'tu' );
2640
		} else {
2641
			// remove the languages unavailable for the datepicker
2642
			$unset = array( 'fil', 'fr-CA', 'de-AT', 'de-CH', 'iw', 'hi', 'pt', 'pt-PT', 'es-419', 'tr' );
2643
		}
2644
2645
		$locales = array_diff_key( $locales, array_flip( $unset ) );
2646
		$locales = apply_filters( 'frm_locales', $locales );
2647
2648
		return $locales;
2649
	}
2650
2651
	/**
2652
	 * Output HTML containing reference text for accessibility
2653
	 */
2654
	public static function multiselect_accessibility() {
2655
		include_once self::plugin_path() . '/classes/views/frm-forms/multiselect-accessibility.php';
2656
	}
2657
2658
	/**
2659
	 * Use the WP 4.7 wp_doing_ajax function
2660
	 *
2661
	 * @since 2.05.07
2662
	 * @deprecated 4.04.04
2663
	 */
2664
	public static function wp_doing_ajax() {
2665
		_deprecated_function( __METHOD__, '4.04.04', 'wp_doing_ajax' );
2666
		return wp_doing_ajax();
2667
	}
2668
2669
	/**
2670
	 * @deprecated 4.0
2671
	 */
2672
	public static function insert_opt_html( $args ) {
2673
		_deprecated_function( __METHOD__, '4.0', 'FrmFormsHelper::insert_opt_html' );
2674
		FrmFormsHelper::insert_opt_html( $args );
2675
	}
2676
2677
	/**
2678
	 * Used to filter shortcode in text widgets
2679
	 *
2680
	 * @deprecated 2.5.4
2681
	 * @codeCoverageIgnore
2682
	 */
2683
	public static function widget_text_filter_callback( $matches ) {
2684
		return FrmDeprecated::widget_text_filter_callback( $matches );
2685
	}
2686
2687
	/**
2688
	 * @deprecated 3.01
2689
	 * @codeCoverageIgnore
2690
	 */
2691
	public static function sanitize_array( &$values ) {
2692
		FrmDeprecated::sanitize_array( $values );
2693
	}
2694
2695
	/**
2696
	 * @param array $settings
2697
	 * @param string $group
2698
	 *
2699
	 * @since 2.0.6
2700
	 * @deprecated 2.05.06
2701
	 * @codeCoverageIgnore
2702
	 */
2703
	public static function save_settings( $settings, $group ) {
2704
		return FrmDeprecated::save_settings( $settings, $group );
2705
	}
2706
2707
	/**
2708
	 * @since 2.0.4
2709
	 * @deprecated 2.05.06
2710
	 * @codeCoverageIgnore
2711
	 */
2712
	public static function save_json_post( $settings ) {
2713
		return FrmDeprecated::save_json_post( $settings );
2714
	}
2715
2716
	/**
2717
	 * @since 2.0
2718
	 * @deprecated 2.05.06
2719
	 * @codeCoverageIgnore
2720
	 *
2721
	 * @param string $cache_key The unique name for this cache
2722
	 * @param string $group The name of the cache group
2723
	 * @param string $query If blank, don't run a db call
2724
	 * @param string $type The wpdb function to use with this query
2725
	 *
2726
	 * @return mixed $results The cache or query results
2727
	 */
2728
	public static function check_cache( $cache_key, $group = '', $query = '', $type = 'get_var', $time = 300 ) {
2729
		return FrmDeprecated::check_cache( $cache_key, $group, $query, $type, $time );
2730
	}
2731
2732
	/**
2733
	 * @deprecated 2.05.06
2734
	 * @codeCoverageIgnore
2735
	 */
2736
	public static function set_cache( $cache_key, $results, $group = '', $time = 300 ) {
2737
		return FrmDeprecated::set_cache( $cache_key, $results, $group, $time );
2738
	}
2739
2740
	/**
2741
	 * @deprecated 2.05.06
2742
	 * @codeCoverageIgnore
2743
	 */
2744
	public static function add_key_to_group_cache( $key, $group ) {
2745
		FrmDeprecated::add_key_to_group_cache( $key, $group );
2746
	}
2747
2748
	/**
2749
	 * @deprecated 2.05.06
2750
	 * @codeCoverageIgnore
2751
	 */
2752
	public static function get_group_cached_keys( $group ) {
2753
		return FrmDeprecated::get_group_cached_keys( $group );
2754
	}
2755
2756
	/**
2757
	 * @since 2.0
2758
	 * @deprecated 2.05.06
2759
	 * @codeCoverageIgnore
2760
	 * @return mixed The cached value or false
2761
	 */
2762
	public static function check_cache_and_transient( $cache_key ) {
2763
		return FrmDeprecated::check_cache( $cache_key );
2764
	}
2765
2766
	/**
2767
	 * @since 2.0
2768
	 * @deprecated 2.05.06
2769
	 * @codeCoverageIgnore
2770
	 *
2771
	 * @param string $cache_key
2772
	 */
2773
	public static function delete_cache_and_transient( $cache_key, $group = 'default' ) {
2774
		FrmDeprecated::delete_cache_and_transient( $cache_key, $group );
2775
	}
2776
2777
	/**
2778
	 * @since 2.0
2779
	 * @deprecated 2.05.06
2780
	 * @codeCoverageIgnore
2781
	 *
2782
	 * @param string $group The name of the cache group
2783
	 */
2784
	public static function cache_delete_group( $group ) {
2785
		FrmDeprecated::cache_delete_group( $group );
2786
	}
2787
2788
	/**
2789
	 * @since 1.07.10
2790
	 * @deprecated 2.05.06
2791
	 * @codeCoverageIgnore
2792
	 *
2793
	 * @param string $term The value to escape
2794
	 *
2795
	 * @return string The escaped value
2796
	 */
2797
	public static function esc_like( $term ) {
2798
		return FrmDeprecated::esc_like( $term );
2799
	}
2800
2801
	/**
2802
	 * @param string $order_query
2803
	 *
2804
	 * @deprecated 2.05.06
2805
	 * @codeCoverageIgnore
2806
	 */
2807
	public static function esc_order( $order_query ) {
2808
		return FrmDeprecated::esc_order( $order_query );
2809
	}
2810
2811
	/**
2812
	 * @deprecated 2.05.06
2813
	 * @codeCoverageIgnore
2814
	 */
2815
	public static function esc_order_by( &$order_by ) {
2816
		FrmDeprecated::esc_order_by( $order_by );
2817
	}
2818
2819
	/**
2820
	 * @param string $limit
2821
	 *
2822
	 * @deprecated 2.05.06
2823
	 * @codeCoverageIgnore
2824
	 */
2825
	public static function esc_limit( $limit ) {
2826
		return FrmDeprecated::esc_limit( $limit );
2827
	}
2828
2829
	/**
2830
	 * @since 2.0
2831
	 * @deprecated 2.05.06
2832
	 * @codeCoverageIgnore
2833
	 */
2834
	public static function prepare_array_values( $array, $type = '%s' ) {
2835
		return FrmDeprecated::prepare_array_values( $array, $type );
2836
	}
2837
2838
	/**
2839
	 * @deprecated 2.05.06
2840
	 * @codeCoverageIgnore
2841
	 */
2842
	public static function prepend_and_or_where( $starts_with = ' WHERE ', $where = '' ) {
2843
		return FrmDeprecated::prepend_and_or_where( $starts_with, $where );
2844
	}
2845
}
2846