Completed
Push — master ( 47643c...e40a79 )
by Stephanie
03:06 queued 39s
created

FrmAppHelper::pro_is_installed()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
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.06.03';
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
	 * Get the Formidable settings
120
	 *
121
	 * @since 2.0
122
	 *
123
	 * @param array $args - May include the form id when values need translation.
124
	 * @return FrmSettings $frm_setings
125
	 */
126
	public static function get_settings( $args = array() ) {
127
		global $frm_settings;
128
		if ( empty( $frm_settings ) ) {
129
			$frm_settings = new FrmSettings( $args );
130
		} elseif ( isset( $args['current_form'] ) ) {
131
			// If the global has already been set, allow strings to be filtered.
132
			$frm_settings->maybe_filter_for_form( $args );
133
		}
134
135
		return $frm_settings;
136
	}
137
138
	public static function get_menu_name() {
139
		$frm_settings = self::get_settings();
140
141
		return $frm_settings->menu;
142
	}
143
144
	/**
145
	 * @since 3.05
146
	 */
147
	public static function svg_logo( $atts = array() ) {
148
		$defaults = array(
149
			'height' => 18,
150
			'width'  => 18,
151
			'fill'   => '#4d4d4d',
152
			'orange' => '#f05a24',
153
		);
154
		$atts     = array_merge( $defaults, $atts );
155
156
		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'] ) . '">
157
			<path fill="' . esc_attr( $atts['orange'] ) . '" d="M289.6 384h140v76h-140z"/>
158
			<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"/>
159
		</svg>';
160
	}
161
162
	/**
163
	 * @since 4.0
164
	 */
165
	public static function show_logo( $atts = array() ) {
166
		echo self::kses( self::svg_logo( $atts ), 'all' ); // WPCS: XSS ok.
167
	}
168
169
	/**
170
	 * @since 4.03.02
171
	 */
172
	public static function show_header_logo() {
173
		$icon = self::svg_logo(
174
			array(
175
				'height' => 35,
176
				'width'  => 35,
177
			)
178
		);
179
180
		$new_icon = apply_filters( 'frm_icon', $icon, true );
181
		if ( $new_icon !== $icon ) {
182
			if ( strpos( $new_icon, '<svg' ) === 0 ) {
183
				$icon = str_replace( 'viewBox="0 0 20', 'width="30" height="35" style="color:#929699" viewBox="0 0 20', $new_icon );
184
			} else {
185
				// Show nothing if it isn't an SVG.
186
				$icon = '<div style="height:39px"></div>';
187
			}
188
		}
189
		echo self::kses( $icon, 'all' ); // WPCS: XSS ok.
190
	}
191
192
	/**
193
	 * @since 2.02.04
194
	 */
195
	public static function ips_saved() {
196
		$frm_settings = self::get_settings();
197
198
		return ! $frm_settings->no_ips;
199
	}
200
201
	public static function pro_is_installed() {
202
		return apply_filters( 'frm_pro_installed', false );
203
	}
204
205
	/**
206
	 * @since 4.06.02
207
	 */
208
	public static function pro_is_connected() {
209
		global $frm_vars;
210
		return self::pro_is_installed() && $frm_vars['pro_is_authorized'];
211
	}
212
213
	/**
214
	 * @since 4.06
215
	 */
216
	public static function is_form_builder_page() {
217
		$action = self::simple_get( 'frm_action', 'sanitize_title' );
218
		return self::is_admin_page( 'formidable' ) && ( $action === 'edit' || $action === 'settings' || $action === 'duplicate' );
219
	}
220
221
	public static function is_formidable_admin() {
222
		$page          = self::simple_get( 'page', 'sanitize_title' );
223
		$is_formidable = strpos( $page, 'formidable' ) !== false;
224
		if ( empty( $page ) ) {
225
			$is_formidable = self::is_view_builder_page();
226
		}
227
228
		return $is_formidable;
229
	}
230
231
	/**
232
	 * Check for certain page in Formidable settings
233
	 *
234
	 * @since 2.0
235
	 *
236
	 * @param string $page The name of the page to check
237
	 *
238
	 * @return boolean
239
	 */
240
	public static function is_admin_page( $page = 'formidable' ) {
241
		global $pagenow;
242
		$get_page = self::simple_get( 'page', 'sanitize_title' );
243
		if ( $pagenow ) {
244
			// allow this to be true during ajax load i.e. ajax form builder loading
245
			$is_page = ( $pagenow == 'admin.php' || $pagenow == 'admin-ajax.php' ) && $get_page == $page;
246
			if ( $is_page ) {
247
				return true;
248
			}
249
		}
250
251
		return is_admin() && $get_page == $page;
252
	}
253
254
	/**
255
	 * If the current page is for editing or creating a view.
256
	 * Returns false for the views listing page.
257
	 *
258
	 * @since 4.0
259
	 */
260
	public static function is_view_builder_page() {
261
		global $pagenow;
262
263
		if ( $pagenow !== 'post.php' && $pagenow !== 'post-new.php' && $pagenow !== 'edit.php' ) {
264
			return false;
265
		}
266
267
		$post_type = self::simple_get( 'post_type', 'sanitize_title' );
268
269
		if ( empty( $post_type ) ) {
270
			$post_id = self::simple_get( 'post', 'absint' );
271
			$post    = get_post( $post_id );
272
			$post_type = $post ? $post->post_type : '';
273
		}
274
275
		return $post_type === 'frm_display';
276
	}
277
278
	/**
279
	 * Check for the form preview page
280
	 *
281
	 * @since 2.0
282
	 *
283
	 * @param None
284
	 *
285
	 * @return boolean
286
	 */
287
	public static function is_preview_page() {
288
		global $pagenow;
289
		$action = self::simple_get( 'action', 'sanitize_title' );
290
291
		return $pagenow && $pagenow == 'admin-ajax.php' && $action == 'frm_forms_preview';
292
	}
293
294
	/**
295
	 * Check for ajax except the form preview page
296
	 *
297
	 * @since 2.0
298
	 *
299
	 * @param None
300
	 *
301
	 * @return boolean
302
	 */
303
	public static function doing_ajax() {
304
		return wp_doing_ajax() && ! self::is_preview_page();
305
	}
306
307
	public static function js_suffix() {
308
		return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
309
	}
310
311
	/**
312
	 * @since 2.0.8
313
	 */
314
	public static function prevent_caching() {
315
		global $frm_vars;
316
317
		return isset( $frm_vars['prevent_caching'] ) && $frm_vars['prevent_caching'];
318
	}
319
320
	/**
321
	 * Check if on an admin page
322
	 *
323
	 * @since 2.0
324
	 *
325
	 * @param None
326
	 *
327
	 * @return boolean
328
	 */
329
	public static function is_admin() {
330
		return is_admin() && ! wp_doing_ajax();
331
	}
332
333
	/**
334
	 * Check if value contains blank value or empty array
335
	 *
336
	 * @since 2.0
337
	 *
338
	 * @param mixed $value - value to check
339
	 * @param string
340
	 *
341
	 * @return boolean
342
	 */
343
	public static function is_empty_value( $value, $empty = '' ) {
344
		return ( is_array( $value ) && empty( $value ) ) || $value === $empty;
345
	}
346
347
	public static function is_not_empty_value( $value, $empty = '' ) {
348
		return ! self::is_empty_value( $value, $empty );
349
	}
350
351
	/**
352
	 * Get any value from the $_SERVER
353
	 *
354
	 * @since 2.0
355
	 *
356
	 * @param string $value
357
	 *
358
	 * @return string
359
	 */
360
	public static function get_server_value( $value ) {
361
		return isset( $_SERVER[ $value ] ) ? wp_strip_all_tags( wp_unslash( $_SERVER[ $value ] ) ) : '';
362
	}
363
364
	/**
365
	 * Check for the IP address in several places
366
	 * Used by [ip] shortcode
367
	 *
368
	 * @return string The IP address of the current user
369
	 */
370
	public static function get_ip_address() {
371
		$ip_options = array(
372
			'HTTP_CLIENT_IP',
373
			'HTTP_CF_CONNECTING_IP',
374
			'HTTP_X_FORWARDED_FOR',
375
			'HTTP_X_FORWARDED',
376
			'HTTP_X_CLUSTER_CLIENT_IP',
377
			'HTTP_X_REAL_IP',
378
			'HTTP_FORWARDED_FOR',
379
			'HTTP_FORWARDED',
380
			'REMOTE_ADDR',
381
		);
382
		$ip = '';
383
		foreach ( $ip_options as $key ) {
384
			if ( ! isset( $_SERVER[ $key ] ) ) {
385
				continue;
386
			}
387
388
			$key = self::get_server_value( $key );
389
			foreach ( explode( ',', $key ) as $ip ) {
390
				$ip = trim( $ip ); // just to be safe.
391
392
				if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
393
					return sanitize_text_field( $ip );
394
				}
395
			}
396
		}
397
398
		return sanitize_text_field( $ip );
399
	}
400
401
	public static function get_param( $param, $default = '', $src = 'get', $sanitize = '' ) {
402
		if ( strpos( $param, '[' ) ) {
403
			$params = explode( '[', $param );
404
			$param  = $params[0];
405
		}
406
407
		if ( $src == 'get' ) {
408
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
409
			$value = isset( $_POST[ $param ] ) ? wp_unslash( $_POST[ $param ] ) : ( isset( $_GET[ $param ] ) ? wp_unslash( $_GET[ $param ] ) : $default );
410
			if ( ! isset( $_POST[ $param ] ) && isset( $_GET[ $param ] ) && ! is_array( $value ) ) {
411
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
412
				$value = htmlspecialchars_decode( wp_unslash( $_GET[ $param ] ) );
413
			}
414
			self::sanitize_value( $sanitize, $value );
415
		} else {
416
			$value = self::get_simple_request(
417
				array(
418
					'type'     => $src,
419
					'param'    => $param,
420
					'default'  => $default,
421
					'sanitize' => $sanitize,
422
				)
423
			);
424
		}
425
426
		if ( isset( $params ) && is_array( $value ) && ! empty( $value ) ) {
427
			foreach ( $params as $k => $p ) {
428
				if ( ! $k || ! is_array( $value ) ) {
429
					continue;
430
				}
431
432
				$p     = trim( $p, ']' );
433
				$value = isset( $value[ $p ] ) ? $value[ $p ] : $default;
434
			}
435
		}
436
437
		return $value;
438
	}
439
440 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...
441
		return self::get_simple_request(
442
			array(
443
				'type'     => 'post',
444
				'param'    => $param,
445
				'default'  => $default,
446
				'sanitize' => $sanitize,
447
				'serialized' => $serialized,
448
			)
449
		);
450
	}
451
452
	/**
453
	 * @since 2.0
454
	 *
455
	 * @param string $param
456
	 * @param string $sanitize
457
	 * @param string $default
458
	 *
459
	 * @return string|array
460
	 */
461 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...
462
		return self::get_simple_request(
463
			array(
464
				'type'     => 'get',
465
				'param'    => $param,
466
				'default'  => $default,
467
				'sanitize' => $sanitize,
468
			)
469
		);
470
	}
471
472
	/**
473
	 * Get a GET/POST/REQUEST value and sanitize it
474
	 *
475
	 * @since 2.0.6
476
	 *
477
	 * @param array $args
478
	 *
479
	 * @return string|array
480
	 */
481
	public static function get_simple_request( $args ) {
482
		$defaults = array(
483
			'param'    => '',
484
			'default'  => '',
485
			'type'     => 'get',
486
			'sanitize' => 'sanitize_text_field',
487
			'serialized' => false,
488
		);
489
		$args     = wp_parse_args( $args, $defaults );
490
491
		$value = $args['default'];
492
		if ( $args['type'] == 'get' ) {
493 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...
494
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
495
				$value = wp_unslash( $_GET[ $args['param'] ] );
496
			}
497
		} elseif ( $args['type'] == 'post' ) {
498
			if ( isset( $_POST[ $args['param'] ] ) ) {
499
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
500
				$value = wp_unslash( $_POST[ $args['param'] ] );
501
				if ( $args['serialized'] === true && is_serialized_string( $value ) && is_serialized( $value ) ) {
502
					self::unserialize_or_decode( $value );
503
				}
504
			}
505 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...
506
			if ( isset( $_REQUEST[ $args['param'] ] ) ) {
507
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
508
				$value = wp_unslash( $_REQUEST[ $args['param'] ] );
509
			}
510
		}
511
512
		self::sanitize_value( $args['sanitize'], $value );
513
514
		return $value;
515
	}
516
517
	/**
518
	 * Preserve backslashes in a value, but make sure value doesn't get compounding slashes
519
	 *
520
	 * @since 2.0.8
521
	 *
522
	 * @param string $value
523
	 *
524
	 * @return string $value
525
	 */
526
	public static function preserve_backslashes( $value ) {
527
		// If backslashes have already been added, don't add them again
528
		if ( strpos( $value, '\\\\' ) === false ) {
529
			$value = addslashes( $value );
530
		}
531
532
		return $value;
533
	}
534
535
	public static function sanitize_value( $sanitize, &$value ) {
536
		if ( ! empty( $sanitize ) ) {
537
			if ( is_array( $value ) ) {
538
				$temp_values = $value;
539
				foreach ( $temp_values as $k => $v ) {
540
					self::sanitize_value( $sanitize, $value[ $k ] );
541
				}
542
			} else {
543
				$value = call_user_func( $sanitize, $value );
544
			}
545
		}
546
	}
547
548
	public static function sanitize_request( $sanitize_method, &$values ) {
549
		$temp_values = $values;
550
		foreach ( $temp_values as $k => $val ) {
551
			if ( isset( $sanitize_method[ $k ] ) ) {
552
				$values[ $k ] = call_user_func( $sanitize_method[ $k ], $val );
553
			}
554
		}
555
	}
556
557
	/**
558
	 * @since 4.0.04
559
	 */
560
	public static function sanitize_with_html( &$value ) {
561
		self::sanitize_value( 'wp_kses_post', $value );
562
		self::decode_specialchars( $value );
563
	}
564
565
	/**
566
	 * Do wp_specialchars_decode to get back '&' that wp_kses_post might have turned to '&amp;'
567
	 * this MUST be done, else we'll be back to the '& entity' problem.
568
	 *
569
	 * @since 4.0.04
570
	 */
571
	public static function decode_specialchars( &$value ) {
572
		if ( is_array( $value ) ) {
573
			$temp_values = $value;
574
			foreach ( $temp_values as $k => $v ) {
575
				self::decode_specialchars( $value[ $k ] );
576
			}
577
		} else {
578
			self::decode_amp( $value );
579
		}
580
	}
581
582
	/**
583
	 * The wp_specialchars_decode function changes too much.
584
	 * This will leave HTML as is, but still convert &.
585
	 * Adapted from wp_specialchars_decode().
586
	 *
587
	 * @since 4.03.01
588
	 *
589
	 * @param string $string The string to prep.
590
	 */
591
	private static function decode_amp( &$string ) {
592
		// Don't bother if there are no entities - saves a lot of processing
593
		if ( empty( $string ) || strpos( $string, '&' ) === false ) {
594
			return;
595
		}
596
597
		$translation = array(
598
			'&quot;'  => '"',
599
			'&#034;'  => '"',
600
			'&#x22;'  => '"',
601
			'&lt; '   => '< ', // The space preserves the HTML.
602
			'&#060; ' => '< ', // The space preserves the HTML.
603
			'&gt;'    => '>',
604
			'&#062;'  => '>',
605
			'&amp;'   => '&',
606
			'&#038;'  => '&',
607
			'&#x26;'  => '&',
608
		);
609
610
		$translation_preg = array(
611
			'/&#0*34;/'   => '&#034;',
612
			'/&#x0*22;/i' => '&#x22;',
613
			'/&#0*60;/'   => '&#060;',
614
			'/&#0*62;/'   => '&#062;',
615
			'/&#0*38;/'   => '&#038;',
616
			'/&#x0*26;/i' => '&#x26;',
617
		);
618
619
		// Remove zero padding on numeric entities
620
		$string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string );
621
622
		// Replace characters according to translation table
623
		$string = strtr( $string, $translation );
624
	}
625
626
	/**
627
	 * Sanitize the value, and allow some HTML
628
	 *
629
	 * @since 2.0
630
	 *
631
	 * @param string $value
632
	 * @param array|string $allowed 'all' for everything included as defaults
633
	 *
634
	 * @return string
635
	 */
636
	public static function kses( $value, $allowed = array() ) {
637
		$allowed_html = self::allowed_html( $allowed );
638
639
		return wp_kses( $value, $allowed_html );
640
	}
641
642
	/**
643
	 * @since 2.05.03
644
	 */
645
	private static function allowed_html( $allowed ) {
646
		$html         = self::safe_html();
647
		$allowed_html = array();
648
		if ( $allowed == 'all' ) {
649
			$allowed_html = $html;
650
		} elseif ( ! empty( $allowed ) ) {
651
			foreach ( (array) $allowed as $a ) {
652
				$allowed_html[ $a ] = isset( $html[ $a ] ) ? $html[ $a ] : array();
653
			}
654
		}
655
656
		return apply_filters( 'frm_striphtml_allowed_tags', $allowed_html );
657
	}
658
659
	/**
660
	 * @since 2.05.03
661
	 */
662
	private static function safe_html() {
663
		$allow_class = array(
664
			'class' => true,
665
			'id'    => true,
666
		);
667
668
		return array(
669
			'a'          => array(
670
				'class'  => true,
671
				'href'   => true,
672
				'id'     => true,
673
				'rel'    => true,
674
				'target' => true,
675
				'title'  => true,
676
			),
677
			'abbr'       => array(
678
				'title' => true,
679
			),
680
			'aside'      => $allow_class,
681
			'b'          => array(),
682
			'blockquote' => array(
683
				'cite' => true,
684
			),
685
			'br'         => array(),
686
			'cite'       => array(
687
				'title' => true,
688
			),
689
			'code'       => array(),
690
			'defs'       => array(),
691
			'del'        => array(
692
				'datetime' => true,
693
				'title'    => true,
694
			),
695
			'dd'         => array(),
696
			'div'        => array(
697
				'class' => true,
698
				'id'    => true,
699
				'title' => true,
700
				'style' => true,
701
			),
702
			'dl'         => array(),
703
			'dt'         => array(),
704
			'em'         => array(),
705
			'h1'         => $allow_class,
706
			'h2'         => $allow_class,
707
			'h3'         => $allow_class,
708
			'h4'         => $allow_class,
709
			'h5'         => $allow_class,
710
			'h6'         => $allow_class,
711
			'i'          => array(
712
				'class' => true,
713
				'id'    => true,
714
				'icon'  => true,
715
				'style' => true,
716
			),
717
			'img'        => array(
718
				'alt'    => true,
719
				'class'  => true,
720
				'height' => true,
721
				'id'     => true,
722
				'src'    => true,
723
				'width'  => true,
724
			),
725
			'li'         => $allow_class,
726
			'ol'         => $allow_class,
727
			'p'          => $allow_class,
728
			'path'       => array(
729
				'd'    => true,
730
				'fill' => true,
731
			),
732
			'pre'        => array(),
733
			'q'          => array(
734
				'cite'  => true,
735
				'title' => true,
736
			),
737
			'rect'       => array(
738
				'class'  => true,
739
				'fill'   => true,
740
				'height' => true,
741
				'width'  => true,
742
				'x'      => true,
743
				'y'      => true,
744
				'rx'     => true,
745
				'stroke' => true,
746
				'stroke-opacity' => true,
747
				'stroke-width'   => true,
748
			),
749
			'section'    => $allow_class,
750
			'span'       => array(
751
				'class' => true,
752
				'id'    => true,
753
				'title' => true,
754
				'style' => true,
755
			),
756
			'strike'     => array(),
757
			'strong'     => array(),
758
			'symbol'     => array(
759
				'class'   => true,
760
				'id'      => true,
761
				'viewbox' => true,
762
			),
763
			'svg'        => array(
764
				'class'   => true,
765
				'id'      => true,
766
				'xmlns'   => true,
767
				'viewbox' => true,
768
				'width'   => true,
769
				'height'  => true,
770
				'style'   => true,
771
				'fill'    => true,
772
			),
773
			'use'        => array(
774
				'href'   => true,
775
				'xlink:href' => true,
776
			),
777
			'ul'         => $allow_class,
778
		);
779
	}
780
781
	/**
782
	 * Used when switching the action for a bulk action
783
	 *
784
	 * @since 2.0
785
	 */
786
	public static function remove_get_action() {
787
		if ( ! isset( $_GET ) ) {
788
			return;
789
		}
790
791
		$action_name = isset( $_GET['action'] ) ? 'action' : ( isset( $_GET['action2'] ) ? 'action2' : '' );
792
		if ( empty( $action_name ) ) {
793
			return;
794
		}
795
796
		$new_action = self::get_param( $action_name, '', 'get', 'sanitize_text_field' );
797
		if ( ! empty( $new_action ) ) {
798
			$_SERVER['REQUEST_URI'] = str_replace( '&action=' . $new_action, '', self::get_server_value( 'REQUEST_URI' ) );
799
		}
800
	}
801
802
	/**
803
	 * Check the WP query for a parameter
804
	 *
805
	 * @since 2.0
806
	 * @return string|array
807
	 */
808
	public static function get_query_var( $value, $param ) {
809
		if ( $value != '' ) {
810
			return $value;
811
		}
812
813
		global $wp_query;
814
		if ( isset( $wp_query->query_vars[ $param ] ) ) {
815
			$value = $wp_query->query_vars[ $param ];
816
		}
817
818
		return $value;
819
	}
820
821
	/**
822
	 * Try to show the SVG if possible. Otherwise, use the font icon.
823
	 *
824
	 * @since 4.0.02
825
	 * @param string $class
826
	 * @param array  $atts
827
	 */
828
	public static function icon_by_class( $class, $atts = array() ) {
829
		$echo = ! isset( $atts['echo'] ) || $atts['echo'];
830
		if ( isset( $atts['echo'] ) ) {
831
			unset( $atts['echo'] );
832
		}
833
834
		$html_atts = self::array_to_html_params( $atts );
835
836
		$icon = trim( str_replace( array( 'frm_icon_font', 'frmfont ' ), '', $class ) );
837
		if ( $icon === $class ) {
838
			$icon = '<i class="' . esc_attr( $class ) . '"' . $html_atts . '></i>';
839
		} else {
840
			$class = strpos( $icon, ' ' ) === false ? '' : ' ' . $icon;
841
			if ( strpos( $icon, ' ' ) ) {
842
				$icon = explode( ' ', $icon );
843
				$icon = reset( $icon );
844
			}
845
			$icon  = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '>
846
				<use xlink:href="#' . esc_attr( $icon ) . '" />
847
			</svg>';
848
		}
849
850
		if ( $echo ) {
851
			echo $icon; // WPCS: XSS ok.
852
		} else {
853
			return $icon;
854
		}
855
	}
856
857
	/**
858
	 * Include svg images.
859
	 *
860
	 * @since 4.0.02
861
	 */
862
	public static function include_svg() {
863
		include_once( self::plugin_path() . '/images/icons.svg' );
864
	}
865
866
	/**
867
	 * Convert an associative array to HTML values.
868
	 *
869
	 * @since 4.0.02
870
	 * @param array $atts
871
	 * @return string
872
	 */
873
	public static function array_to_html_params( $atts ) {
874
		$html = '';
875
		if ( ! empty( $atts ) ) {
876
			foreach ( $atts as $key => $value ) {
877
				$html .= ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
878
			}
879
		}
880
		return $html;
881
	}
882
883
	/**
884
	 * @since 3.0
885
	 */
886
	public static function get_admin_header( $atts ) {
887
		$has_nav = ( isset( $atts['form'] ) && ! empty( $atts['form'] ) && ( ! isset( $atts['is_template'] ) || ! $atts['is_template'] ) );
888
		if ( ! isset( $atts['close'] ) || empty( $atts['close'] ) ) {
889
			$atts['close'] = admin_url( 'admin.php?page=formidable' );
890
		}
891
		if ( ! isset( $atts['import_link'] ) ) {
892
			$atts['import_link'] = false;
893
		}
894
895
		include( self::plugin_path() . '/classes/views/shared/admin-header.php' );
896
	}
897
898
	/**
899
	 * @since 3.0
900
	 */
901
	public static function add_new_item_link( $atts ) {
902
		if ( isset( $atts['new_link'] ) && ! empty( $atts['new_link'] ) ) { ?>
903
			<a href="<?php echo esc_url( $atts['new_link'] ); ?>" class="button button-primary frm-button-primary frm-with-plus">
904
				<?php self::icon_by_class( 'frmfont frm_plus_icon frm_svg15' ); ?>
905
				<?php esc_html_e( 'Add New', 'formidable' ); ?>
906
			</a>
907
			<?php
908
		} elseif ( isset( $atts['link_hook'] ) ) {
909
			do_action( $atts['link_hook']['hook'], $atts['link_hook']['param'] );
910
		}
911
	}
912
913
	/**
914
	 * @since 3.06
915
	 */
916
	public static function show_search_box( $atts ) {
917
		$defaults = array(
918
			'placeholder' => '',
919
			'tosearch'    => '',
920
			'text'        => __( 'Search', 'formidable' ),
921
			'input_id'    => '',
922
		);
923
		$atts = array_merge( $defaults, $atts );
924
925
		if ( $atts['input_id'] === 'template' && empty( $atts['tosearch'] ) ) {
926
			$atts['tosearch'] = 'frm-card';
927
		}
928
929
		$class = 'frm-search-input';
930
		if ( ! empty( $atts['tosearch'] ) ) {
931
			$class .= ' frm-auto-search';
932
		}
933
934
		$input_id = $atts['input_id'] . '-search-input';
935
936
		?>
937
		<p class="frm-search">
938
			<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
939
				<?php echo esc_html( $atts['text'] ); ?>:
940
			</label>
941
			<span class="frmfont frm_search_icon"></span>
942
			<input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s"
943
				value="<?php _admin_search_query(); ?>" placeholder="<?php echo esc_attr( $atts['placeholder'] ); ?>"
944
				class="<?php echo esc_attr( $class ); ?>" data-tosearch="<?php echo esc_attr( $atts['tosearch'] ); ?>"
945
				<?php if ( ! empty( $atts['tosearch'] ) ) { ?>
946
				autocomplete="off"
947
				<?php } ?>
948
				/>
949
			<?php
950
			if ( empty( $atts['tosearch'] ) ) {
951
				submit_button( $atts['text'], 'button-secondary', '', false, array( 'id' => 'search-submit' ) );
952
			}
953
			?>
954
		</p>
955
		<?php
956
	}
957
958
	/**
959
	 * @param string $type
960
	 */
961
	public static function trigger_hook_load( $type, $object = null ) {
962
		// Only load the form hooks once.
963
		$hooks_loaded = apply_filters( 'frm_' . $type . '_hooks_loaded', false, $object );
964
		if ( ! $hooks_loaded ) {
965
			do_action( 'frm_load_' . $type . '_hooks' );
966
		}
967
	}
968
969
	/**
970
	 * Save all front-end js scripts into a single file
971
	 *
972
	 * @since 3.0
973
	 */
974
	public static function save_combined_js() {
975
		$file_atts = apply_filters(
976
			'frm_js_location',
977
			array(
978
				'file_name'     => 'frm.min.js',
979
				'new_file_path' => self::plugin_path() . '/js',
980
			)
981
		);
982
		$new_file  = new FrmCreateFile( $file_atts );
983
984
		$files = array(
985
			self::plugin_path() . '/js/jquery/jquery.placeholder.min.js',
986
			self::plugin_path() . '/js/formidable.min.js',
987
		);
988
		$files = apply_filters( 'frm_combined_js_files', $files );
989
		$new_file->combine_files( $files );
990
	}
991
992
	/**
993
	 * Check a value from a shortcode to see if true or false.
994
	 * True when value is 1, true, 'true', 'yes'
995
	 *
996
	 * @since 1.07.10
997
	 *
998
	 * @param string $value The value to compare
999
	 *
1000
	 * @return boolean True or False
1001
	 */
1002
	public static function is_true( $value ) {
1003
		return ( true === $value || 1 == $value || 'true' == $value || 'yes' == $value );
1004
	}
1005
1006
	public static function get_pages() {
1007
		$query = array(
1008
			'post_type'   => 'page',
1009
			'post_status' => array( 'publish', 'private' ),
1010
			'numberposts' => - 1,
1011
			'orderby'     => 'title',
1012
			'order'       => 'ASC',
1013
		);
1014
1015
		return get_posts( $query );
1016
	}
1017
1018
	/**
1019
	 * Renders an autocomplete page selection or a regular dropdown depending on
1020
	 * the total page count
1021
	 *
1022
	 * @since 4.03.06
1023
	 */
1024
	public static function maybe_autocomplete_pages_options( $args ) {
1025
		$args = self::preformat_selection_args( $args );
1026
1027
		$pages_count = wp_count_posts( 'page' );
1028
1029
		if ( $pages_count->publish <= 50 ) {
1030
			self::wp_pages_dropdown( $args );
1031
			return;
1032
		}
1033
1034
		wp_enqueue_script( 'jquery-ui-autocomplete' );
1035
1036
		$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...
1037
		$title = '';
1038
1039
		if ( $selected ) {
1040
			$title = get_the_title( $selected );
1041
		}
1042
1043
		?>
1044
		<input type="text" class="frm-page-search"
1045
			placeholder="<?php esc_html_e( 'Select a Page', 'formidable' ); ?>"
1046
			value="<?php echo esc_attr( $title ); ?>" />
1047
		<input type="hidden" name="<?php echo esc_attr( $args['field_name'] ); ?>"
1048
			value="<?php echo esc_attr( $selected ); ?>" />
1049
		<?php
1050
	}
1051
1052
	/**
1053
	 * @param array   $args
1054
	 * @param string  $page_id Deprecated.
1055
	 * @param boolean $truncate Deprecated.
1056
	 */
1057
	public static function wp_pages_dropdown( $args = array(), $page_id = '', $truncate = false ) {
1058
		self::prep_page_dropdown_params( $page_id, $truncate, $args );
1059
1060
		$pages    = self::get_pages();
1061
		$selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1062
1063
		?>
1064
		<select name="<?php echo esc_attr( $args['field_name'] ); ?>" id="<?php echo esc_attr( $args['field_name'] ); ?>" class="frm-pages-dropdown">
1065
			<option value=""><?php echo esc_html( $args['placeholder'] ); ?></option>
1066
			<?php foreach ( $pages as $page ) { ?>
1067
				<option value="<?php echo esc_attr( $page->ID ); ?>" <?php selected( $selected, $page->ID ); ?>>
1068
					<?php echo esc_html( $args['truncate'] ? self::truncate( $page->post_title, $args['truncate'] ) : $page->post_title ); ?>
1069
				</option>
1070
			<?php } ?>
1071
		</select>
1072
		<?php
1073
	}
1074
1075
	/**
1076
	 * Fill in missing parameters passed to wp_pages_dropdown().
1077
	 * This is for reverse compatibility with switching 3 params to 1.
1078
	 *
1079
	 * @since 4.03.06
1080
	 */
1081
	private static function prep_page_dropdown_params( $page_id, $truncate, &$args ) {
1082
		if ( ! is_array( $args ) ) {
1083
			$args = array(
1084
				'field_name' => $args,
1085
				'page_id'    => $page_id,
1086
				'truncate'   => $truncate,
1087
			);
1088
		}
1089
1090
		$args = self::preformat_selection_args( $args );
1091
	}
1092
1093
	/**
1094
	 * Filter to format args for page dropdown or autocomplete
1095
	 *
1096
	 * @since 4.03.06
1097
	 */
1098
	private static function preformat_selection_args( $args ) {
1099
		$defaults = array(
1100
			'truncate'    => false,
1101
			'placeholder' => ' ',
1102
			'field_name'  => '',
1103
			'page_id'     => '',
1104
		);
1105
1106
		return array_merge( $defaults, $args );
1107
	}
1108
1109
	public static function post_edit_link( $post_id ) {
1110
		$post = get_post( $post_id );
1111
		if ( $post ) {
1112
			$post_url = admin_url( 'post.php?post=' . $post_id . '&action=edit' );
1113
			$post_url = self::maybe_full_screen_link( $post_url );
1114
1115
			return '<a href="' . esc_url( $post_url ) . '">' . self::truncate( $post->post_title, 50 ) . '</a>';
1116
		}
1117
1118
		return '';
1119
	}
1120
1121
	/**
1122
	 * Hide the WordPress menus on some pages.
1123
	 *
1124
	 * @since 4.0
1125
	 */
1126
	public static function is_full_screen() {
1127
		$full_builder = self::is_form_builder_page();
1128
		$styler       = self::is_admin_page( 'formidable-styles' ) || self::is_admin_page( 'formidable-styles2' );
1129
		$full_entries = self::simple_get( 'frm-full', 'absint' );
1130
1131
		return $full_builder || $full_entries || $styler || self::is_view_builder_page();
1132
	}
1133
1134
	/**
1135
	 * @since 4.0
1136
	 */
1137
	public static function maybe_full_screen_link( $link ) {
1138
		$is_full = self::simple_get( 'frm-full', 'absint' );
1139
		if ( $is_full && ! empty( $link ) && $link !== '#' ) {
1140
			$link .= '&frm-full=1';
1141
		}
1142
		return $link;
1143
	}
1144
1145
	/**
1146
	 * @param string        $field_name
1147
	 * @param string|array  $capability
1148
	 * @param string        $multiple 'single' and 'multiple'
1149
	 */
1150
	public static function wp_roles_dropdown( $field_name, $capability, $multiple = 'single' ) {
1151
		?>
1152
		<select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $field_name ); ?>"
1153
			<?php echo ( 'multiple' === $multiple ) ? 'multiple="multiple"' : ''; ?>
1154
			class="frm_multiselect">
1155
			<?php self::roles_options( $capability ); ?>
1156
		</select>
1157
		<?php
1158
	}
1159
1160
	/**
1161
	 * @param array|string $selected $selected
1162
	 * @param string $current
1163
	 */
1164
	private static function selected( $selected, $current ) {
1165
		if ( is_callable( 'FrmProAppHelper::selected' ) ) {
1166
			FrmProAppHelper::selected( $selected, $current );
1167
		} else {
1168
			selected( in_array( $current, (array) $selected, true ) );
1169
		}
1170
	}
1171
1172
	/**
1173
	 * @param string|array $capability
1174
	 */
1175
	public static function roles_options( $capability ) {
1176
		global $frm_vars;
1177
		if ( isset( $frm_vars['editable_roles'] ) ) {
1178
			$editable_roles = $frm_vars['editable_roles'];
1179
		} else {
1180
			$editable_roles             = get_editable_roles();
1181
			$frm_vars['editable_roles'] = $editable_roles;
1182
		}
1183
1184
		foreach ( $editable_roles as $role => $details ) {
1185
			$name = translate_user_role( $details['name'] );
1186
			?>
1187
			<option value="<?php echo esc_attr( $role ); ?>" <?php self::selected( $capability, $role ); ?>><?php echo esc_attr( $name ); ?> </option>
1188
			<?php
1189
			unset( $role, $details );
1190
		}
1191
	}
1192
1193
	public static function frm_capabilities( $type = 'auto' ) {
1194
		$cap = array(
1195
			'frm_view_forms'      => __( 'View Forms', 'formidable' ),
1196
			'frm_edit_forms'      => __( 'Add and Edit Forms', 'formidable' ),
1197
			'frm_delete_forms'    => __( 'Delete Forms', 'formidable' ),
1198
			'frm_change_settings' => __( 'Access this Settings Page', 'formidable' ),
1199
			'frm_view_entries'    => __( 'View Entries from Admin Area', 'formidable' ),
1200
			'frm_delete_entries'  => __( 'Delete Entries from Admin Area', 'formidable' ),
1201
		);
1202
1203
		if ( ! self::pro_is_installed() && 'pro' != $type ) {
1204
			return $cap;
1205
		}
1206
1207
		$cap['frm_create_entries'] = __( 'Add Entries from Admin Area', 'formidable' );
1208
		$cap['frm_edit_entries']   = __( 'Edit Entries from Admin Area', 'formidable' );
1209
		$cap['frm_view_reports']   = __( 'View Reports', 'formidable' );
1210
		$cap['frm_edit_displays']  = __( 'Add/Edit Views', 'formidable' );
1211
1212
		return $cap;
1213
	}
1214
1215
	/**
1216
	 * Call the WordPress current_user_can but also validate empty strings as true for any logged in user
1217
	 *
1218
	 * @since 4.06.03
1219
	 *
1220
	 * @param string $role
1221
	 *
1222
	 * @return bool
1223
	 */
1224
	public static function current_user_can( $role ) {
1225
		if ( $role === '-1' ) {
1226
			return false;
1227
		}
1228
1229
		if ( $role === 'loggedout' ) {
1230
			return ! is_user_logged_in();
1231
		}
1232
1233
		if ( $role === 'loggedin' || ! $role ) {
1234
			return is_user_logged_in();
1235
		}
1236
1237
		if ( $role == 1 ) {
1238
			$role = 'administrator';
1239
		}
1240
1241
		if ( ! is_user_logged_in() ) {
1242
			return false;
1243
		}
1244
1245
		return current_user_can( $role );
1246
	}
1247
1248
	/**
1249
	 * @param string|array $needed_role
1250
	 * @return bool
1251
	 */
1252
	public static function user_has_permission( $needed_role ) {
1253
		if ( is_array( $needed_role ) ) {
1254
			foreach ( $needed_role as $role ) {
1255
				if ( self::current_user_can( $role ) ) {
1256
					return true;
1257
				}
1258
			}
1259
1260
			return false;
1261
		}
1262
1263
		$can = self::current_user_can( $needed_role );
1264
1265
		if ( $can || in_array( $needed_role, array( '-1', 'loggedout' ) ) ) {
1266
			return $can;
1267
		}
1268
1269
		$roles = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' );
1270
		foreach ( $roles as $role ) {
1271
			if ( current_user_can( $role ) ) {
1272
				return true;
1273
			}
1274
			if ( $role == $needed_role ) {
1275
				break;
1276
			}
1277
		}
1278
1279
		return false;
1280
	}
1281
1282
	/**
1283
	 * Make sure administrators can see Formidable menu
1284
	 *
1285
	 * @since 2.0
1286
	 */
1287
	public static function maybe_add_permissions() {
1288
		self::force_capability( 'frm_view_entries' );
1289
1290
		if ( ! current_user_can( 'administrator' ) || current_user_can( 'frm_view_forms' ) ) {
1291
			return;
1292
		}
1293
1294
		$user_id   = get_current_user_id();
1295
		$user      = new WP_User( $user_id );
1296
		$frm_roles = self::frm_capabilities();
1297
		foreach ( $frm_roles as $frm_role => $frm_role_description ) {
1298
			$user->add_cap( $frm_role );
1299
			unset( $frm_role, $frm_role_description );
1300
		}
1301
	}
1302
1303
	/**
1304
	 * Make sure admins have permission to see the menu items
1305
	 *
1306
	 * @since 2.0.6
1307
	 */
1308
	public static function force_capability( $cap = 'frm_change_settings' ) {
1309
		if ( current_user_can( 'administrator' ) && ! current_user_can( $cap ) ) {
1310
			$role      = get_role( 'administrator' );
1311
			$frm_roles = self::frm_capabilities();
1312
			foreach ( $frm_roles as $frm_role => $frm_role_description ) {
1313
				$role->add_cap( $frm_role );
1314
			}
1315
		}
1316
	}
1317
1318
	/**
1319
	 * Check if the user has permision for action.
1320
	 * Return permission message and stop the action if no permission
1321
	 *
1322
	 * @since 2.0
1323
	 *
1324
	 * @param string $permission
1325
	 */
1326
	public static function permission_check( $permission, $show_message = 'show' ) {
1327
		$permission_error = self::permission_nonce_error( $permission );
1328
		if ( $permission_error !== false ) {
1329
			if ( 'hide' == $show_message ) {
1330
				$permission_error = '';
1331
			}
1332
			wp_die( esc_html( $permission_error ) );
1333
		}
1334
	}
1335
1336
	/**
1337
	 * Check user permission and nonce
1338
	 *
1339
	 * @since 2.0
1340
	 *
1341
	 * @param string $permission
1342
	 *
1343
	 * @return false|string The permission message or false if allowed
1344
	 */
1345
	public static function permission_nonce_error( $permission, $nonce_name = '', $nonce = '' ) {
1346
		if ( ! empty( $permission ) && ! current_user_can( $permission ) && ! current_user_can( 'administrator' ) ) {
1347
			$frm_settings = self::get_settings();
1348
1349
			return $frm_settings->admin_permission;
1350
		}
1351
1352
		$error = false;
1353
		if ( empty( $nonce_name ) ) {
1354
			return $error;
1355
		}
1356
1357
		$nonce_value = ( $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
1358
		if ( $_REQUEST && ( ! isset( $_REQUEST[ $nonce_name ] ) || ! wp_verify_nonce( $nonce_value, $nonce ) ) ) {
1359
			$frm_settings = self::get_settings();
1360
			$error        = $frm_settings->admin_permission;
1361
		}
1362
1363
		return $error;
1364
	}
1365
1366
	public static function checked( $values, $current ) {
1367
		if ( self::check_selected( $values, $current ) ) {
1368
			echo ' checked="checked"';
1369
		}
1370
	}
1371
1372
	public static function check_selected( $values, $current ) {
1373
		$values  = self::recursive_function_map( $values, 'trim' );
1374
		$values  = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1375
		$current = htmlspecialchars_decode( trim( $current ) );
1376
1377
		return ( is_array( $values ) && in_array( $current, $values ) ) || ( ! is_array( $values ) && $values == $current );
1378
	}
1379
1380
	public static function recursive_function_map( $value, $function ) {
1381
		if ( is_array( $value ) ) {
1382
			$original_function = $function;
1383
			if ( count( $value ) ) {
1384
				$function = explode( ', ', FrmDb::prepare_array_values( $value, $function ) );
1385
			} else {
1386
				$function = array( $function );
1387
			}
1388
			if ( ! self::is_assoc( $value ) ) {
1389
				$value = array_map( array( 'FrmAppHelper', 'recursive_function_map' ), $value, $function );
1390
			} else {
1391
				foreach ( $value as $k => $v ) {
1392
					if ( ! is_array( $v ) ) {
1393
						$value[ $k ] = call_user_func( $original_function, $v );
1394
					}
1395
				}
1396
			}
1397
		} else {
1398
			$value = call_user_func( $function, $value );
1399
		}
1400
1401
		return $value;
1402
	}
1403
1404
	public static function is_assoc( $array ) {
1405
		return (bool) count( array_filter( array_keys( $array ), 'is_string' ) );
1406
	}
1407
1408
	/**
1409
	 * Flatten a multi-dimensional array
1410
	 */
1411
	public static function array_flatten( $array, $keys = 'keep' ) {
1412
		$return = array();
1413
		foreach ( $array as $key => $value ) {
1414
			if ( is_array( $value ) ) {
1415
				$return = array_merge( $return, self::array_flatten( $value, $keys ) );
1416
			} else {
1417
				if ( $keys == 'keep' ) {
1418
					$return[ $key ] = $value;
1419
				} else {
1420
					$return[] = $value;
1421
				}
1422
			}
1423
		}
1424
1425
		return $return;
1426
	}
1427
1428
	public static function esc_textarea( $text, $is_rich_text = false ) {
1429
		$safe_text = str_replace( '&quot;', '"', $text );
1430
		if ( ! $is_rich_text ) {
1431
			$safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
1432
		}
1433
		$safe_text = str_replace( '&amp; ', '& ', $safe_text );
1434
1435
		return apply_filters( 'esc_textarea', $safe_text, $text );
1436
	}
1437
1438
	/**
1439
	 * Add auto paragraphs to text areas
1440
	 *
1441
	 * @since 2.0
1442
	 */
1443
	public static function use_wpautop( $content ) {
1444
		if ( apply_filters( 'frm_use_wpautop', true ) && ! is_array( $content ) ) {
1445
			$content = wpautop( str_replace( '<br>', '<br />', $content ) );
1446
		}
1447
1448
		return $content;
1449
	}
1450
1451
	public static function replace_quotes( $val ) {
1452
		// Replace double quotes.
1453
		$val = str_replace( array( '&#8220;', '&#8221;', '&#8243;' ), '"', $val );
1454
1455
		// Replace single quotes.
1456
		$val = str_replace( array( '&#8216;', '&#8217;', '&#8242;', '&prime;', '&rsquo;', '&lsquo;' ), "'", $val );
1457
1458
		return $val;
1459
	}
1460
1461
	/**
1462
	 * @since 2.0
1463
	 * @return string The base Google APIS url for the current version of jQuery UI
1464
	 */
1465
	public static function jquery_ui_base_url() {
1466
		$url = 'http' . ( is_ssl() ? 's' : '' ) . '://ajax.googleapis.com/ajax/libs/jqueryui/' . self::script_version( 'jquery-ui-core', '1.11.4' );
1467
		$url = apply_filters( 'frm_jquery_ui_base_url', $url );
1468
1469
		return $url;
1470
	}
1471
1472
	/**
1473
	 * @param string $handle
1474
	 */
1475
	public static function script_version( $handle, $default = 0 ) {
1476
		global $wp_scripts;
1477
		if ( ! $wp_scripts ) {
1478
			return $default;
1479
		}
1480
1481
		$ver = $default;
1482
		if ( ! isset( $wp_scripts->registered[ $handle ] ) ) {
1483
			return $ver;
1484
		}
1485
1486
		$query = $wp_scripts->registered[ $handle ];
1487
		if ( is_object( $query ) && ! empty( $query->ver ) ) {
1488
			$ver = $query->ver;
1489
		}
1490
1491
		return $ver;
1492
	}
1493
1494
	public static function js_redirect( $url ) {
1495
		return '<script type="text/javascript">window.location="' . esc_url_raw( $url ) . '"</script>';
1496
	}
1497
1498
	public static function get_user_id_param( $user_id ) {
1499
		if ( ! $user_id || empty( $user_id ) || is_numeric( $user_id ) ) {
1500
			return $user_id;
1501
		}
1502
1503
		$user_id = sanitize_text_field( $user_id );
1504
		if ( $user_id == 'current' ) {
1505
			$user_id = get_current_user_id();
1506
		} else {
1507
			if ( is_email( $user_id ) ) {
1508
				$user = get_user_by( 'email', $user_id );
1509
			} else {
1510
				$user = get_user_by( 'login', $user_id );
1511
			}
1512
1513
			if ( $user ) {
1514
				$user_id = $user->ID;
1515
			}
1516
			unset( $user );
1517
		}
1518
1519
		return $user_id;
1520
	}
1521
1522
	public static function get_file_contents( $filename, $atts = array() ) {
1523
		if ( ! is_file( $filename ) ) {
1524
			return false;
1525
		}
1526
1527
		extract( $atts );
1528
		ob_start();
1529
		include( $filename );
1530
		$contents = ob_get_contents();
1531
		ob_end_clean();
1532
1533
		return $contents;
1534
	}
1535
1536
	/**
1537
	 * @param string $table_name
1538
	 * @param string $column
1539
	 * @param int $id
1540
	 * @param int $num_chars
1541
	 */
1542
	public static function get_unique_key( $name = '', $table_name, $column, $id = 0, $num_chars = 5 ) {
1543
		$key = '';
1544
1545
		if ( ! empty( $name ) ) {
1546
			$key = sanitize_key( $name );
1547
		}
1548
1549
		if ( empty( $key ) ) {
1550
			$max_slug_value = pow( 36, $num_chars );
1551
			$min_slug_value = 37; // we want to have at least 2 characters in the slug
1552
			$key            = base_convert( rand( $min_slug_value, $max_slug_value ), 10, 36 );
1553
		}
1554
1555
		$not_allowed = array(
1556
			'id',
1557
			'key',
1558
			'created-at',
1559
			'detaillink',
1560
			'editlink',
1561
			'siteurl',
1562
			'evenodd',
1563
		);
1564
1565
		if ( is_numeric( $key ) || in_array( $key, $not_allowed ) ) {
1566
			$key = $key . 'a';
1567
		}
1568
1569
		$key_check = FrmDb::get_var(
1570
			$table_name,
1571
			array(
1572
				$column => $key,
1573
				'ID !'  => $id,
1574
			),
1575
			$column
1576
		);
1577
1578
		if ( $key_check || is_numeric( $key_check ) ) {
1579
			// Create a unique field id if it has already been used.
1580
			$key = $key . substr( md5( microtime() . rand() ), 0, 10 );
1581
		}
1582
1583
		return $key;
1584
	}
1585
1586
	/**
1587
	 * Editing a Form or Entry
1588
	 *
1589
	 * @param string $table
1590
	 *
1591
	 * @return bool|array
1592
	 */
1593
	public static function setup_edit_vars( $record, $table, $fields = '', $default = false, $post_values = array(), $args = array() ) {
1594
		if ( ! $record ) {
1595
			return false;
1596
		}
1597
1598
		if ( empty( $post_values ) ) {
1599
			$post_values = wp_unslash( $_POST );
1600
		}
1601
1602
		$values = array(
1603
			'id'     => $record->id,
1604
			'fields' => array(),
1605
		);
1606
1607
		foreach ( array( 'name', 'description' ) as $var ) {
1608
			$default_val    = isset( $record->{$var} ) ? $record->{$var} : '';
1609
			$values[ $var ] = self::get_param( $var, $default_val, 'get', 'wp_kses_post' );
1610
			unset( $var, $default_val );
1611
		}
1612
1613
		$values['description'] = self::use_wpautop( $values['description'] );
1614
1615
		self::fill_form_opts( $record, $table, $post_values, $values );
1616
1617
		self::prepare_field_arrays( $fields, $record, $values, array_merge( $args, compact( 'default', 'post_values' ) ) );
1618
1619
		if ( $table == 'entries' ) {
1620
			$values = FrmEntriesHelper::setup_edit_vars( $values, $record );
1621
		} elseif ( $table == 'forms' ) {
1622
			$values = FrmFormsHelper::setup_edit_vars( $values, $record, $post_values );
1623
		}
1624
1625
		return $values;
1626
	}
1627
1628
	private static function prepare_field_arrays( $fields, $record, array &$values, $args ) {
1629
		if ( ! empty( $fields ) ) {
1630
			foreach ( (array) $fields as $field ) {
1631
				if ( ! self::is_admin_page() ) {
1632
					// Don't prep default values on the form settings page.
1633
					$field->default_value = apply_filters( 'frm_get_default_value', $field->default_value, $field, true );
1634
				}
1635
				$args['parent_form_id'] = isset( $args['parent_form_id'] ) ? $args['parent_form_id'] : $field->form_id;
1636
				self::fill_field_defaults( $field, $record, $values, $args );
1637
			}
1638
		}
1639
	}
1640
1641
	private static function fill_field_defaults( $field, $record, array &$values, $args ) {
1642
		$post_values = $args['post_values'];
1643
1644
		if ( $args['default'] ) {
1645
			$meta_value = $field->default_value;
1646
		} else {
1647
			if ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
1648
				if ( ! isset( $field->field_options['custom_field'] ) ) {
1649
					$field->field_options['custom_field'] = '';
1650
				}
1651
				$meta_value = FrmProEntryMetaHelper::get_post_value(
1652
					$record->post_id,
1653
					$field->field_options['post_field'],
1654
					$field->field_options['custom_field'],
1655
					array(
1656
						'truncate' => false,
1657
						'type'     => $field->type,
1658
						'form_id'  => $field->form_id,
1659
						'field'    => $field,
1660
					)
1661
				);
1662
			} else {
1663
				$meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
1664
			}
1665
		}
1666
1667
		$field_type = isset( $post_values['field_options'][ 'type_' . $field->id ] ) ? $post_values['field_options'][ 'type_' . $field->id ] : $field->type;
1668
		if ( isset( $post_values['item_meta'][ $field->id ] ) ) {
1669
			$new_value = $post_values['item_meta'][ $field->id ];
1670
			self::unserialize_or_decode( $new_value );
1671
		} else {
1672
			$new_value = $meta_value;
1673
		}
1674
1675
		$field_array                   = self::start_field_array( $field );
1676
		$field_array['value']          = $new_value;
1677
		$field_array['type']           = apply_filters( 'frm_field_type', $field_type, $field, $new_value );
1678
		$field_array['parent_form_id'] = $args['parent_form_id'];
1679
1680
		$args['field_type'] = $field_type;
1681
1682
		FrmFieldsHelper::prepare_edit_front_field( $field_array, $field, $values['id'], $args );
1683
1684
		if ( ! isset( $field_array['unique'] ) || ! $field_array['unique'] ) {
1685
			$field_array['unique_msg'] = '';
1686
		}
1687
1688
		$field_array = array_merge( (array) $field->field_options, $field_array );
1689
1690
		$values['fields'][ $field->id ] = $field_array;
1691
	}
1692
1693
	/**
1694
	 * @since 3.0
1695
	 *
1696
	 * @param object $field
1697
	 *
1698
	 * @return array
1699
	 */
1700
	public static function start_field_array( $field ) {
1701
		return array(
1702
			'id'            => $field->id,
1703
			'default_value' => $field->default_value,
1704
			'name'          => $field->name,
1705
			'description'   => $field->description,
1706
			'options'       => $field->options,
1707
			'required'      => $field->required,
1708
			'field_key'     => $field->field_key,
1709
			'field_order'   => $field->field_order,
1710
			'form_id'       => $field->form_id,
1711
		);
1712
	}
1713
1714
	/**
1715
	 * @param string $table
1716
	 */
1717
	private static function fill_form_opts( $record, $table, $post_values, array &$values ) {
1718
		if ( $table == 'entries' ) {
1719
			$form = $record->form_id;
1720
			FrmForm::maybe_get_form( $form );
1721
		} else {
1722
			$form = $record;
1723
		}
1724
1725
		if ( ! $form ) {
1726
			return;
1727
		}
1728
1729
		$values['form_name']      = isset( $record->form_id ) ? $form->name : '';
1730
		$values['parent_form_id'] = isset( $record->form_id ) ? $form->parent_form_id : 0;
1731
1732
		if ( ! is_array( $form->options ) ) {
1733
			return;
1734
		}
1735
1736
		foreach ( $form->options as $opt => $value ) {
1737
			if ( isset( $post_values[ $opt ] ) ) {
1738
				$values[ $opt ] = $post_values[ $opt ];
1739
				self::unserialize_or_decode( $values[ $opt ] );
1740
			} else {
1741
				$values[ $opt ] = $value;
1742
			}
1743
		}
1744
1745
		self::fill_form_defaults( $post_values, $values );
1746
	}
1747
1748
	/**
1749
	 * Set to POST value or default
1750
	 */
1751
	private static function fill_form_defaults( $post_values, array &$values ) {
1752
		$form_defaults = FrmFormsHelper::get_default_opts();
1753
1754
		foreach ( $form_defaults as $opt => $default ) {
1755
			if ( ! isset( $values[ $opt ] ) || $values[ $opt ] == '' ) {
1756
				$values[ $opt ] = ( $post_values && isset( $post_values['options'][ $opt ] ) ) ? $post_values['options'][ $opt ] : $default;
1757
			}
1758
1759
			unset( $opt, $default );
1760
		}
1761
1762
		if ( ! isset( $values['custom_style'] ) ) {
1763
			$values['custom_style'] = self::custom_style_value( $post_values );
1764
		}
1765
1766
		foreach ( array( 'before', 'after', 'submit' ) as $h ) {
1767
			if ( ! isset( $values[ $h . '_html' ] ) ) {
1768
				$values[ $h . '_html' ] = ( isset( $post_values['options'][ $h . '_html' ] ) ? $post_values['options'][ $h . '_html' ] : FrmFormsHelper::get_default_html( $h ) );
1769
			}
1770
			unset( $h );
1771
		}
1772
	}
1773
1774
	/**
1775
	 * @since 2.2.10
1776
	 *
1777
	 * @param array $post_values
1778
	 *
1779
	 * @return boolean|int
1780
	 */
1781
	public static function custom_style_value( $post_values ) {
1782
		if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
1783
			$custom_style = absint( $post_values['options']['custom_style'] );
1784
		} else {
1785
			$frm_settings = self::get_settings();
1786
			$custom_style = ( $frm_settings->load_style != 'none' );
1787
		}
1788
1789
		return $custom_style;
1790
	}
1791
1792
	public static function truncate( $str, $length, $minword = 3, $continue = '...' ) {
1793
		if ( is_array( $str ) ) {
1794
			return '';
1795
		}
1796
1797
		$length       = (int) $length;
1798
		$str          = wp_strip_all_tags( $str );
1799
		$original_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $str ) );
1800
1801
		if ( $length == 0 ) {
1802
			return '';
1803
		} elseif ( $length <= 10 ) {
1804
			$sub = self::mb_function( array( 'mb_substr', 'substr' ), array( $str, 0, $length ) );
1805
1806
			return $sub . ( ( $length < $original_len ) ? $continue : '' );
1807
		}
1808
1809
		$sub = '';
1810
		$len = 0;
1811
1812
		$words = self::mb_function( array( 'mb_split', 'explode' ), array( ' ', $str ) );
1813
1814
		foreach ( $words as $word ) {
1815
			$part      = ( ( $sub != '' ) ? ' ' : '' ) . $word;
1816
			$total_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $sub . $part ) );
1817
			if ( $total_len > $length && substr_count( $sub, ' ' ) ) {
1818
				break;
1819
			}
1820
1821
			$sub .= $part;
1822
			$len += self::mb_function( array( 'mb_strlen', 'strlen' ), array( $part ) );
1823
1824
			if ( substr_count( $sub, ' ' ) > $minword && $total_len >= $length ) {
1825
				break;
1826
			}
1827
1828
			unset( $total_len, $word );
1829
		}
1830
1831
		return $sub . ( ( $len < $original_len ) ? $continue : '' );
1832
	}
1833
1834
	public static function mb_function( $function_names, $args ) {
1835
		$mb_function_name = $function_names[0];
1836
		$function_name    = $function_names[1];
1837
		if ( function_exists( $mb_function_name ) ) {
1838
			$function_name = $mb_function_name;
1839
		}
1840
1841
		return call_user_func_array( $function_name, $args );
1842
	}
1843
1844
	public static function get_formatted_time( $date, $date_format = '', $time_format = '' ) {
1845
		if ( empty( $date ) ) {
1846
			return $date;
1847
		}
1848
1849
		if ( empty( $date_format ) ) {
1850
			$date_format = get_option( 'date_format' );
1851
		}
1852
1853
		if ( preg_match( '/^\d{1-2}\/\d{1-2}\/\d{4}$/', $date ) && self::pro_is_installed() ) {
1854
			$frmpro_settings = new FrmProSettings();
1855
			$date            = FrmProAppHelper::convert_date( $date, $frmpro_settings->date_format, 'Y-m-d' );
1856
		}
1857
1858
		$formatted = self::get_localized_date( $date_format, $date );
1859
1860
		$do_time = ( gmdate( 'H:i:s', strtotime( $date ) ) != '00:00:00' );
1861
		if ( $do_time ) {
1862
			$formatted .= self::add_time_to_date( $time_format, $date );
1863
		}
1864
1865
		return $formatted;
1866
	}
1867
1868
	private static function add_time_to_date( $time_format, $date ) {
1869
		if ( empty( $time_format ) ) {
1870
			$time_format = get_option( 'time_format' );
1871
		}
1872
1873
		$trimmed_format = trim( $time_format );
1874
		$time           = '';
1875
		if ( $time_format && ! empty( $trimmed_format ) ) {
1876
			$time = ' ' . __( 'at', 'formidable' ) . ' ' . self::get_localized_date( $time_format, $date );
1877
		}
1878
1879
		return $time;
1880
	}
1881
1882
	/**
1883
	 * @since 2.0.8
1884
	 */
1885
	public static function get_localized_date( $date_format, $date ) {
1886
		$date = get_date_from_gmt( $date );
1887
1888
		return date_i18n( $date_format, strtotime( $date ) );
1889
	}
1890
1891
	/**
1892
	 * Gets the time ago in words
1893
	 *
1894
	 * @param int $from in seconds
1895
	 * @param int|string $to in seconds
1896
	 *
1897
	 * @return string $time_ago
1898
	 */
1899
	public static function human_time_diff( $from, $to = '', $levels = 1 ) {
1900
		if ( empty( $to ) ) {
1901
			$now = new DateTime();
1902
		} else {
1903
			$now = new DateTime( '@' . $to );
1904
		}
1905
		$ago = new DateTime( '@' . $from );
1906
1907
		// Get the time difference
1908
		$diff_object = $now->diff( $ago );
1909
		$diff        = get_object_vars( $diff_object );
1910
1911
		// Add week amount and update day amount
1912
		$diff['w'] = floor( $diff['d'] / 7 );
1913
		$diff['d'] -= $diff['w'] * 7;
1914
1915
		$time_strings = self::get_time_strings();
1916
1917
		if ( ! is_numeric( $levels ) ) {
1918
			// Show time in specified unit.
1919
			$levels = self::get_unit( $levels );
1920
			if ( isset( $time_strings[ $levels ] ) ) {
1921
				$diff = array(
1922
					$levels => self::time_format( $levels, $diff ),
1923
				);
1924
				$time_strings = array(
1925
					$levels => $time_strings[ $levels ],
1926
				);
1927
			}
1928
			$levels = 1;
1929
		}
1930
1931
		foreach ( $time_strings as $k => $v ) {
1932
			if ( isset( $diff[ $k ] ) && $diff[ $k ] ) {
1933
				$time_strings[ $k ] = $diff[ $k ] . ' ' . ( $diff[ $k ] > 1 ? $v[1] : $v[0] );
1934
			} elseif ( isset( $diff[ $k ] ) && count( $time_strings ) === 1 ) {
1935
				// Account for 0.
1936
				$time_strings[ $k ] = $diff[ $k ] . ' ' . $v[1];
1937
			} else {
1938
				unset( $time_strings[ $k ] );
1939
			}
1940
		}
1941
1942
		$levels_deep     = apply_filters( 'frm_time_ago_levels', $levels, compact( 'time_strings', 'from', 'to' ) );
1943
		$time_strings    = array_slice( $time_strings, 0, absint( $levels_deep ) );
1944
		$time_ago_string = implode( ' ', $time_strings );
1945
1946
		return $time_ago_string;
1947
	}
1948
1949
	/**
1950
	 * @since 4.05.01
1951
	 */
1952
	private static function time_format( $unit, $diff ) {
1953
		$return = array(
1954
			'y' => 'y',
1955
			'd' => 'days',
1956
		);
1957
		if ( isset( $return[ $unit ] ) ) {
1958
			return $diff[ $return[ $unit ] ];
1959
		}
1960
1961
		$total = $diff['days'] * self::convert_time( 'd', $unit );
1962
1963
		$times = array( 'h', 'i', 's' );
1964
1965
		foreach ( $times as $time ) {
1966
			if ( ! isset( $diff[ $time ] ) ) {
1967
				continue;
1968
			}
1969
1970
			$total += $diff[ $time ] * self::convert_time( $time, $unit );
1971
		}
1972
1973
		return floor( $total );
1974
	}
1975
1976
	/**
1977
	 * @since 4.05.01
1978
	 */
1979
	private static function convert_time( $from, $to ) {
1980
		$convert = array(
1981
			's' => 1,
1982
			'i' => MINUTE_IN_SECONDS,
1983
			'h' => HOUR_IN_SECONDS,
1984
			'd' => DAY_IN_SECONDS,
1985
			'w' => WEEK_IN_SECONDS,
1986
			'm' => DAY_IN_SECONDS * 30.42,
1987
			'y' => DAY_IN_SECONDS * 365.25,
1988
		);
1989
1990
		return $convert[ $from ] / $convert[ $to ];
1991
	}
1992
1993
	/**
1994
	 * @since 4.05.01
1995
	 */
1996
	private static function get_unit( $unit ) {
1997
		$units = self::get_time_strings();
1998
		if ( isset( $units[ $unit ] ) || is_numeric( $unit ) ) {
1999
			return $unit;
2000
		}
2001
2002
		foreach ( $units as $u => $strings ) {
2003
			if ( in_array( $unit, $strings ) ) {
2004
				return $u;
2005
			}
2006
		}
2007
		return 1;
2008
	}
2009
2010
	/**
2011
	 * Get the translatable time strings. The untranslated version is a failsafe
2012
	 * in case langauges are changing for the unit set in the shortcode.
2013
	 *
2014
	 * @since 2.0.20
2015
	 * @return array
2016
	 */
2017
	private static function get_time_strings() {
2018
		return array(
2019
			'y' => array(
2020
				__( 'year', 'formidable' ),
2021
				__( 'years', 'formidable' ),
2022
				'year',
2023
			),
2024
			'm' => array(
2025
				__( 'month', 'formidable' ),
2026
				__( 'months', 'formidable' ),
2027
				'month',
2028
			),
2029
			'w' => array(
2030
				__( 'week', 'formidable' ),
2031
				__( 'weeks', 'formidable' ),
2032
				'week',
2033
			),
2034
			'd' => array(
2035
				__( 'day', 'formidable' ),
2036
				__( 'days', 'formidable' ),
2037
				'day',
2038
			),
2039
			'h' => array(
2040
				__( 'hour', 'formidable' ),
2041
				__( 'hours', 'formidable' ),
2042
				'hour',
2043
			),
2044
			'i' => array(
2045
				__( 'minute', 'formidable' ),
2046
				__( 'minutes', 'formidable' ),
2047
				'minute',
2048
			),
2049
			's' => array(
2050
				__( 'second', 'formidable' ),
2051
				__( 'seconds', 'formidable' ),
2052
				'second',
2053
			),
2054
		);
2055
	}
2056
2057
	// Pagination Methods.
2058
2059
	/**
2060
	 * @param integer $current_p
2061
	 */
2062
	public static function get_last_record_num( $r_count, $current_p, $p_size ) {
2063
		return ( ( $r_count < ( $current_p * $p_size ) ) ? $r_count : ( $current_p * $p_size ) );
2064
	}
2065
2066
	/**
2067
	 * @param integer $current_p
2068
	 */
2069
	public static function get_first_record_num( $r_count, $current_p, $p_size ) {
2070
		if ( $current_p == 1 ) {
2071
			return 1;
2072
		} else {
2073
			return ( self::get_last_record_num( $r_count, ( $current_p - 1 ), $p_size ) + 1 );
2074
		}
2075
	}
2076
2077
	/**
2078
	 * @return array
2079
	 */
2080
	public static function json_to_array( $json_vars ) {
2081
		$vars = array();
2082
		foreach ( $json_vars as $jv ) {
2083
			$jv_name = explode( '[', $jv['name'] );
2084
			$last    = count( $jv_name ) - 1;
2085
			foreach ( $jv_name as $p => $n ) {
2086
				$name = trim( $n, ']' );
2087
				if ( ! isset( $l1 ) ) {
2088
					$l1 = $name;
2089
				}
2090
2091
				if ( ! isset( $l2 ) ) {
2092
					$l2 = $name;
2093
				}
2094
2095
				if ( ! isset( $l3 ) ) {
2096
					$l3 = $name;
2097
				}
2098
2099
				$this_val = ( $p == $last ) ? $jv['value'] : array();
2100
2101
				switch ( $p ) {
2102
					case 0:
2103
						$l1 = $name;
2104
						self::add_value_to_array( $name, $l1, $this_val, $vars );
2105
						break;
2106
2107
					case 1:
2108
						$l2 = $name;
2109
						self::add_value_to_array( $name, $l2, $this_val, $vars[ $l1 ] );
2110
						break;
2111
2112 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...
2113
						$l3 = $name;
2114
						self::add_value_to_array( $name, $l3, $this_val, $vars[ $l1 ][ $l2 ] );
2115
						break;
2116
2117 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...
2118
						$l4 = $name;
2119
						self::add_value_to_array( $name, $l4, $this_val, $vars[ $l1 ][ $l2 ][ $l3 ] );
2120
				}
2121
2122
				unset( $this_val, $n );
2123
			}
2124
2125
			unset( $last, $jv );
2126
		}
2127
2128
		return $vars;
2129
	}
2130
2131
	/**
2132
	 * @param string $name
2133
	 * @param string $l1
2134
	 */
2135
	public static function add_value_to_array( $name, $l1, $val, &$vars ) {
2136
		if ( $name == '' ) {
2137
			$vars[] = $val;
2138
		} elseif ( ! isset( $vars[ $l1 ] ) ) {
2139
			$vars[ $l1 ] = $val;
2140
		}
2141
	}
2142
2143
	public static function maybe_add_tooltip( $name, $class = 'closed', $form_name = '' ) {
2144
		$tooltips = array(
2145
			'action_title'  => __( 'Give this action a label for easy reference.', 'formidable' ),
2146
			'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' ),
2147
			'cc'            => __( 'Add CC addresses separated by a ",".  FORMAT: Name <[email protected]> or [email protected].', 'formidable' ),
2148
			'bcc'           => __( 'Add BCC addresses separated by a ",".  FORMAT: Name <[email protected]> or [email protected].', 'formidable' ),
2149
			'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' ),
2150
			'from'          => __( 'Enter the name and/or email address of the sender. FORMAT: John Bates <[email protected]> or [email protected].', 'formidable' ),
2151
			/* translators: %1$s: Form name, %2$s: Date */
2152
			'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() ) ),
2153
		);
2154
2155
		if ( ! isset( $tooltips[ $name ] ) ) {
2156
			return;
2157
		}
2158
2159
		if ( 'open' == $class ) {
2160
			echo ' frm_help"';
2161
		} else {
2162
			echo ' class="frm_help"';
2163
		}
2164
2165
		echo ' title="' . esc_attr( $tooltips[ $name ] );
2166
2167
		if ( 'open' != $class ) {
2168
			echo '"';
2169
		}
2170
	}
2171
2172
	/**
2173
	 * Add the current_page class to that page in the form nav
2174
	 */
2175
	public static function select_current_page( $page, $current_page, $action = array() ) {
2176
		if ( $current_page != $page ) {
2177
			return;
2178
		}
2179
2180
		$frm_action = self::simple_get( 'frm_action', 'sanitize_title' );
2181
		if ( empty( $action ) || ( ! empty( $frm_action ) && in_array( $frm_action, $action ) ) ) {
2182
			echo ' class="current_page"';
2183
		}
2184
	}
2185
2186
	/**
2187
	 * Prepare and json_encode post content
2188
	 *
2189
	 * @since 2.0
2190
	 *
2191
	 * @param array $post_content
2192
	 *
2193
	 * @return string $post_content ( json encoded array )
2194
	 */
2195
	public static function prepare_and_encode( $post_content ) {
2196
		// Loop through array to strip slashes and add only the needed ones.
2197
		foreach ( $post_content as $key => $val ) {
2198
			// Replace problematic characters (like &quot;)
2199
			$val = str_replace( '&quot;', '"', $val );
2200
2201
			self::prepare_action_slashes( $val, $key, $post_content );
2202
			unset( $key, $val );
2203
		}
2204
2205
		// json_encode the array.
2206
		$post_content = json_encode( $post_content );
2207
2208
		// Add extra slashes for \r\n since WP strips them.
2209
		$post_content = str_replace( array( '\\r', '\\n', '\\u', '\\t' ), array( '\\\\r', '\\\\n', '\\\\u', '\\\\t' ), $post_content );
2210
2211
		// allow for &quot
2212
		$post_content = str_replace( '&quot;', '\\"', $post_content );
2213
2214
		return $post_content;
2215
	}
2216
2217
	private static function prepare_action_slashes( $val, $key, &$post_content ) {
2218
		if ( ! isset( $post_content[ $key ] ) ) {
2219
			return;
2220
		}
2221
2222
		if ( is_array( $val ) ) {
2223
			foreach ( $val as $k1 => $v1 ) {
2224
				self::prepare_action_slashes( $v1, $k1, $post_content[ $key ] );
2225
				unset( $k1, $v1 );
2226
			}
2227
		} else {
2228
			// Strip all slashes so everything is the same, no matter where the value is coming from
2229
			$val = stripslashes( $val );
2230
2231
			// Add backslashes before double quotes and forward slashes only
2232
			$post_content[ $key ] = addcslashes( $val, '"\\/' );
2233
		}
2234
	}
2235
2236
	/**
2237
	 * Check for either json or serilized data. This is temporary while transitioning
2238
	 * all data to json.
2239
	 *
2240
	 * @since 4.02.03
2241
	 */
2242
	public static function unserialize_or_decode( &$value ) {
2243
		if ( is_array( $value ) ) {
2244
			return;
2245
		}
2246
2247
		if ( is_serialized( $value ) ) {
2248
			$value = maybe_unserialize( $value );
2249
		} else {
2250
			$value = self::maybe_json_decode( $value, false );
2251
		}
2252
	}
2253
2254
	/**
2255
	 * Decode a JSON string.
2256
	 * Do not switch shortcodes like [24] to array unless intentional ie XML values.
2257
	 */
2258
	public static function maybe_json_decode( $string, $single_to_array = true ) {
2259
		if ( is_array( $string ) ) {
2260
			return $string;
2261
		}
2262
2263
		$new_string = json_decode( $string, true );
2264
		if ( function_exists( 'json_last_error' ) ) {
2265
			// php 5.3+
2266
			$single_value = false;
2267
			if ( ! $single_to_array ) {
2268
				$single_value = is_array( $new_string ) && count( $new_string ) === 1 && isset( $new_string[0] );
2269
			}
2270
			if ( json_last_error() == JSON_ERROR_NONE && is_array( $new_string ) && ! $single_value ) {
2271
				$string = $new_string;
2272
			}
2273
		}
2274
2275
		return $string;
2276
	}
2277
2278
	/**
2279
	 * Reformat the json serialized array in name => value array.
2280
	 *
2281
	 * @since 4.02.03
2282
	 */
2283
	public static function format_form_data( &$form ) {
2284
		$formatted = array();
2285
2286
		foreach ( $form as $input ) {
2287
			if ( ! isset( $input['name'] ) ) {
2288
				continue;
2289
			}
2290
			$key = $input['name'];
2291
			if ( isset( $formatted[ $key ] ) ) {
2292
				if ( is_array( $formatted[ $key ] ) ) {
2293
					$formatted[ $key ][] = $input['value'];
2294
				} else {
2295
					$formatted[ $key ] = array( $formatted[ $key ], $input['value'] );
2296
				}
2297
			} else {
2298
				$formatted[ $key ] = $input['value'];
2299
			}
2300
		}
2301
2302
		parse_str( http_build_query( $formatted ), $form );
2303
	}
2304
2305
	/**
2306
	 * @since 4.02.03
2307
	 */
2308
	public static function maybe_json_encode( $value ) {
2309
		if ( is_array( $value ) ) {
2310
			$value = wp_json_encode( $value );
2311
		}
2312
		return $value;
2313
	}
2314
2315
	/**
2316
	 * @since 1.07.10
2317
	 *
2318
	 * @param string $post_type The name of the post type that may need to be highlighted
2319
	 * echo The javascript to open and highlight the Formidable menu
2320
	 */
2321
	public static function maybe_highlight_menu( $post_type ) {
2322
		global $post;
2323
2324
		if ( isset( $_REQUEST['post_type'] ) && $_REQUEST['post_type'] != $post_type ) {
2325
			return;
2326
		}
2327
2328
		if ( is_object( $post ) && $post->post_type != $post_type ) {
2329
			return;
2330
		}
2331
2332
		self::load_admin_wide_js();
2333
		echo '<script type="text/javascript">jQuery(document).ready(function(){frmSelectSubnav();});</script>';
2334
	}
2335
2336
	/**
2337
	 * Load the JS file on non-Formidable pages in the admin area
2338
	 *
2339
	 * @since 2.0
2340
	 */
2341
	public static function load_admin_wide_js( $load = true ) {
2342
		$version = self::plugin_version();
2343
		wp_register_script( 'formidable_admin_global', self::plugin_url() . '/js/formidable_admin_global.js', array( 'jquery' ), $version );
2344
2345
		$global_strings = array(
2346
			'updating_msg' => __( 'Please wait while your site updates.', 'formidable' ),
2347
			'deauthorize'  => __( 'Are you sure you want to deauthorize Formidable Forms on this site?', 'formidable' ),
2348
			'url'          => self::plugin_url(),
2349
			'app_url'      => 'https://formidableforms.com/',
2350
			'loading'      => __( 'Loading&hellip;', 'formidable' ),
2351
			'nonce'        => wp_create_nonce( 'frm_ajax' ),
2352
		);
2353
		wp_localize_script( 'formidable_admin_global', 'frmGlobal', $global_strings );
2354
2355
		if ( $load ) {
2356
			wp_enqueue_script( 'formidable_admin_global' );
2357
		}
2358
	}
2359
2360
	/**
2361
	 * @since 2.0.9
2362
	 */
2363
	public static function load_font_style() {
2364
		wp_enqueue_style( 'frm_fonts', self::plugin_url() . '/css/frm_fonts.css', array(), self::plugin_version() );
2365
	}
2366
2367
	/**
2368
	 * @param string $location
2369
	 */
2370
	public static function localize_script( $location ) {
2371
		global $wp_scripts;
2372
2373
		$ajax_url = admin_url( 'admin-ajax.php', is_ssl() ? 'admin' : 'http' );
2374
		$ajax_url = apply_filters( 'frm_ajax_url', $ajax_url );
2375
2376
		$script_strings = array(
2377
			'ajax_url'     => $ajax_url,
2378
			'images_url'   => self::plugin_url() . '/images',
2379
			'loading'      => __( 'Loading&hellip;', 'formidable' ),
2380
			'remove'       => __( 'Remove', 'formidable' ),
2381
			'offset'       => apply_filters( 'frm_scroll_offset', 4 ),
2382
			'nonce'        => wp_create_nonce( 'frm_ajax' ),
2383
			'id'           => __( 'ID', 'formidable' ),
2384
			'no_results'   => __( 'No results match', 'formidable' ),
2385
			'file_spam'    => __( 'That file looks like Spam.', 'formidable' ),
2386
			'calc_error'   => __( 'There is an error in the calculation in the field with key', 'formidable' ),
2387
			'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
2388
		);
2389
2390
		$data = $wp_scripts->get_data( 'formidable', 'data' );
2391
		if ( empty( $data ) ) {
2392
			wp_localize_script( 'formidable', 'frm_js', $script_strings );
2393
		}
2394
2395
		if ( $location == 'admin' ) {
2396
			$frm_settings         = self::get_settings();
2397
			$admin_script_strings = array(
2398
				'desc'              => __( '(Click to add description)', 'formidable' ),
2399
				'blank'             => __( '(Blank)', 'formidable' ),
2400
				'no_label'          => __( '(no label)', 'formidable' ),
2401
				'saving'            => esc_attr( __( 'Saving', 'formidable' ) ),
2402
				'saved'             => esc_attr( __( 'Saved', 'formidable' ) ),
2403
				'ok'                => __( 'OK', 'formidable' ),
2404
				'cancel'            => __( 'Cancel', 'formidable' ),
2405
				'default_label'     => __( 'Default', 'formidable' ),
2406
				'clear_default'     => __( 'Clear default value when typing', 'formidable' ),
2407
				'no_clear_default'  => __( 'Do not clear default value when typing', 'formidable' ),
2408
				'valid_default'     => __( 'Default value will pass form validation', 'formidable' ),
2409
				'no_valid_default'  => __( 'Default value will NOT pass form validation', 'formidable' ),
2410
				'caution'           => __( 'Heads up', 'formidable' ),
2411
				'confirm'           => __( 'Are you sure?', 'formidable' ),
2412
				'conf_delete'       => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
2413
				'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' ),
2414
				'conf_no_repeat'    => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
2415
				'default_unique'    => $frm_settings->unique_msg,
2416
				'default_conf'      => __( 'The entered values do not match', 'formidable' ),
2417
				'enter_email'       => __( 'Enter Email', 'formidable' ),
2418
				'confirm_email'     => __( 'Confirm Email', 'formidable' ),
2419
				'conditional_text'  => __( 'Conditional content here', 'formidable' ),
2420
				'new_option'        => __( 'New Option', 'formidable' ),
2421
				'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' ),
2422
				'enter_password'    => __( 'Enter Password', 'formidable' ),
2423
				'confirm_password'  => __( 'Confirm Password', 'formidable' ),
2424
				'import_complete'   => __( 'Import Complete', 'formidable' ),
2425
				'updating'          => __( 'Please wait while your site updates.', 'formidable' ),
2426
				'no_save_warning'   => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
2427
				'private_label'     => __( 'Private', 'formidable' ),
2428
				'jquery_ui_url'     => self::jquery_ui_base_url(),
2429
				'pro_url'           => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
2430
				'no_licenses'       => __( 'No new licenses were found', 'formidable' ),
2431
				'unmatched_parens'  => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
2432
				'view_shortcodes'   => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
2433
				'text_shortcodes'   => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
2434
				'only_one_action'   => __( 'This form action is limited to one per form. Please edit the existing form action.', 'formidable' ),
2435
				'unsafe_params'     => FrmFormsHelper::reserved_words(),
2436
				/* Translators: %s is the name of a Detail Page Slug that is a reserved word.*/
2437
				'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
2438
				/* 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. */
2439
				'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
2440
				'reserved_words'    => __( 'See the list of reserved words in WordPress.', 'formidable' ),
2441
				'repeat_limit_min'  => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
2442
				'checkbox_limit'    => __( 'Please select a limit between 0 and 200.', 'formidable' ),
2443
				'install'           => __( 'Install', 'formidable' ),
2444
				'active'            => __( 'Active', 'formidable' ),
2445
				'select_a_field'    => __( 'Select a Field', 'formidable' ),
2446
				'no_items_found'    => __( 'No items found.', 'formidable' ),
2447
			);
2448
			$admin_script_strings = apply_filters( 'frm_admin_script_strings', $admin_script_strings );
2449
2450
			$data = $wp_scripts->get_data( 'formidable_admin', 'data' );
2451
			if ( empty( $data ) ) {
2452
				wp_localize_script( 'formidable_admin', 'frm_admin_js', $admin_script_strings );
2453
			}
2454
		}
2455
	}
2456
2457
	/**
2458
	 * Echo the message on the plugins listing page
2459
	 *
2460
	 * @since 1.07.10
2461
	 *
2462
	 * @param float $min_version The version the add-on requires
2463
	 */
2464
	public static function min_version_notice( $min_version ) {
2465
		$frm_version = self::plugin_version();
2466
2467
		// Check if Formidable meets minimum requirements.
2468
		if ( version_compare( $frm_version, $min_version, '>=' ) ) {
2469
			return;
2470
		}
2471
2472
		$wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
2473
		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">' .
2474
			esc_html__( 'You are running an outdated version of Formidable. This plugin may not work correctly if you do not update Formidable.', 'formidable' ) .
2475
			'</div></td></tr>';
2476
	}
2477
2478
	/**
2479
	 * If Pro is far outdated, show a message.
2480
	 *
2481
	 * @since 4.0.01
2482
	 */
2483
	public static function min_pro_version_notice( $min_version ) {
2484
		if ( ! self::is_formidable_admin() ) {
2485
			// Don't show admin-wide.
2486
			return;
2487
		}
2488
2489
		self::php_version_notice();
2490
2491
		$is_pro = self::pro_is_installed() && class_exists( 'FrmProDb' );
2492
		if ( ! $is_pro || self::meets_min_pro_version( $min_version ) ) {
2493
			return;
2494
		}
2495
2496
		$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...
2497
		$expired = FrmAddonsController::is_license_expired();
2498
		?>
2499
		<div class="error frm_previous_install">
2500
			<?php
2501
			esc_html_e( 'You are running a version of Formidable Forms that may not be compatible with your version of Formidable Forms Pro.', 'formidable' );
2502
			if ( empty( $expired ) ) {
2503
				echo ' Please <a href="' . esc_url( admin_url( 'plugins.php?s=formidable%20forms%20pro' ) ) . '">update now</a>.';
2504
			} else {
2505
				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.';
2506
			}
2507
			?>
2508
		</div>
2509
		<?php
2510
	}
2511
2512
	/**
2513
	 * If Pro is installed, check the version number.
2514
	 *
2515
	 * @since 4.0.01
2516
	 */
2517
	public static function meets_min_pro_version( $min_version ) {
2518
		return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
2519
	}
2520
2521
	/**
2522
	 * Show a message if the browser or PHP version is below the recommendations.
2523
	 *
2524
	 * @since 4.0.02
2525
	 */
2526
	private static function php_version_notice() {
2527
		$message = array();
2528
		if ( version_compare( phpversion(), '5.6', '<' ) ) {
2529
			$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' );
2530
		}
2531
2532
		$browser = self::get_server_value( 'HTTP_USER_AGENT' );
2533
		$is_ie   = strpos( $browser, 'MSIE' ) !== false;
2534
		if ( $is_ie ) {
2535
			$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' );
2536
		}
2537
2538
		foreach ( $message as $m ) {
2539
			?>
2540
			<div class="error frm_previous_install">
2541
				<?php echo esc_html( $m ); ?>
2542
			</div>
2543
			<?php
2544
		}
2545
	}
2546
2547
	public static function locales( $type = 'date' ) {
2548
		$locales = array(
2549
			'en'     => __( 'English', 'formidable' ),
2550
			'af'     => __( 'Afrikaans', 'formidable' ),
2551
			'sq'     => __( 'Albanian', 'formidable' ),
2552
			'ar'     => __( 'Arabic', 'formidable' ),
2553
			'hy'     => __( 'Armenian', 'formidable' ),
2554
			'az'     => __( 'Azerbaijani', 'formidable' ),
2555
			'eu'     => __( 'Basque', 'formidable' ),
2556
			'bs'     => __( 'Bosnian', 'formidable' ),
2557
			'bg'     => __( 'Bulgarian', 'formidable' ),
2558
			'ca'     => __( 'Catalan', 'formidable' ),
2559
			'zh-HK'  => __( 'Chinese Hong Kong', 'formidable' ),
2560
			'zh-CN'  => __( 'Chinese Simplified', 'formidable' ),
2561
			'zh-TW'  => __( 'Chinese Traditional', 'formidable' ),
2562
			'hr'     => __( 'Croatian', 'formidable' ),
2563
			'cs'     => __( 'Czech', 'formidable' ),
2564
			'da'     => __( 'Danish', 'formidable' ),
2565
			'nl'     => __( 'Dutch', 'formidable' ),
2566
			'en-GB'  => __( 'English/UK', 'formidable' ),
2567
			'eo'     => __( 'Esperanto', 'formidable' ),
2568
			'et'     => __( 'Estonian', 'formidable' ),
2569
			'fo'     => __( 'Faroese', 'formidable' ),
2570
			'fa'     => __( 'Farsi/Persian', 'formidable' ),
2571
			'fil'    => __( 'Filipino', 'formidable' ),
2572
			'fi'     => __( 'Finnish', 'formidable' ),
2573
			'fr'     => __( 'French', 'formidable' ),
2574
			'fr-CA'  => __( 'French/Canadian', 'formidable' ),
2575
			'fr-CH'  => __( 'French/Swiss', 'formidable' ),
2576
			'de'     => __( 'German', 'formidable' ),
2577
			'de-AT'  => __( 'German/Austria', 'formidable' ),
2578
			'de-CH'  => __( 'German/Switzerland', 'formidable' ),
2579
			'el'     => __( 'Greek', 'formidable' ),
2580
			'he'     => __( 'Hebrew', 'formidable' ),
2581
			'iw'     => __( 'Hebrew', 'formidable' ),
2582
			'hi'     => __( 'Hindi', 'formidable' ),
2583
			'hu'     => __( 'Hungarian', 'formidable' ),
2584
			'is'     => __( 'Icelandic', 'formidable' ),
2585
			'id'     => __( 'Indonesian', 'formidable' ),
2586
			'it'     => __( 'Italian', 'formidable' ),
2587
			'ja'     => __( 'Japanese', 'formidable' ),
2588
			'ko'     => __( 'Korean', 'formidable' ),
2589
			'lv'     => __( 'Latvian', 'formidable' ),
2590
			'lt'     => __( 'Lithuanian', 'formidable' ),
2591
			'ms'     => __( 'Malaysian', 'formidable' ),
2592
			'no'     => __( 'Norwegian', 'formidable' ),
2593
			'pl'     => __( 'Polish', 'formidable' ),
2594
			'pt'     => __( 'Portuguese', 'formidable' ),
2595
			'pt-BR'  => __( 'Portuguese/Brazilian', 'formidable' ),
2596
			'pt-PT'  => __( 'Portuguese/Portugal', 'formidable' ),
2597
			'ro'     => __( 'Romanian', 'formidable' ),
2598
			'ru'     => __( 'Russian', 'formidable' ),
2599
			'sr'     => __( 'Serbian', 'formidable' ),
2600
			'sr-SR'  => __( 'Serbian', 'formidable' ),
2601
			'sk'     => __( 'Slovak', 'formidable' ),
2602
			'sl'     => __( 'Slovenian', 'formidable' ),
2603
			'es'     => __( 'Spanish', 'formidable' ),
2604
			'es-419' => __( 'Spanish/Latin America', 'formidable' ),
2605
			'sv'     => __( 'Swedish', 'formidable' ),
2606
			'ta'     => __( 'Tamil', 'formidable' ),
2607
			'th'     => __( 'Thai', 'formidable' ),
2608
			'tu'     => __( 'Turkish', 'formidable' ),
2609
			'tr'     => __( 'Turkish', 'formidable' ),
2610
			'uk'     => __( 'Ukranian', 'formidable' ),
2611
			'vi'     => __( 'Vietnamese', 'formidable' ),
2612
		);
2613
2614
		if ( $type === 'captcha' ) {
2615
			// remove the languages unavailable for the captcha
2616
			$unset = array( 'af', 'sq', 'hy', 'az', 'eu', 'bs', 'zh-HK', 'eo', 'et', 'fo', 'fr-CH', 'he', 'is', 'ms', 'sr-SR', 'ta', 'tu' );
2617
		} else {
2618
			// remove the languages unavailable for the datepicker
2619
			$unset = array( 'fil', 'fr-CA', 'de-AT', 'de-CH', 'iw', 'hi', 'pt', 'pt-PT', 'es-419', 'tr' );
2620
		}
2621
2622
		$locales = array_diff_key( $locales, array_flip( $unset ) );
2623
		$locales = apply_filters( 'frm_locales', $locales );
2624
2625
		return $locales;
2626
	}
2627
2628
	/**
2629
	 * Use the WP 4.7 wp_doing_ajax function
2630
	 *
2631
	 * @since 2.05.07
2632
	 * @deprecated 4.04.04
2633
	 */
2634
	public static function wp_doing_ajax() {
2635
		_deprecated_function( __METHOD__, '4.04.04', 'wp_doing_ajax' );
2636
		return wp_doing_ajax();
2637
	}
2638
2639
	/**
2640
	 * @deprecated 4.0
2641
	 */
2642
	public static function insert_opt_html( $args ) {
2643
		_deprecated_function( __METHOD__, '4.0', 'FrmFormsHelper::insert_opt_html' );
2644
		FrmFormsHelper::insert_opt_html( $args );
2645
	}
2646
2647
	/**
2648
	 * Used to filter shortcode in text widgets
2649
	 *
2650
	 * @deprecated 2.5.4
2651
	 * @codeCoverageIgnore
2652
	 */
2653
	public static function widget_text_filter_callback( $matches ) {
2654
		return FrmDeprecated::widget_text_filter_callback( $matches );
2655
	}
2656
2657
	/**
2658
	 * @deprecated 3.01
2659
	 * @codeCoverageIgnore
2660
	 */
2661
	public static function sanitize_array( &$values ) {
2662
		FrmDeprecated::sanitize_array( $values );
2663
	}
2664
2665
	/**
2666
	 * @param array $settings
2667
	 * @param string $group
2668
	 *
2669
	 * @since 2.0.6
2670
	 * @deprecated 2.05.06
2671
	 * @codeCoverageIgnore
2672
	 */
2673
	public static function save_settings( $settings, $group ) {
2674
		return FrmDeprecated::save_settings( $settings, $group );
2675
	}
2676
2677
	/**
2678
	 * @since 2.0.4
2679
	 * @deprecated 2.05.06
2680
	 * @codeCoverageIgnore
2681
	 */
2682
	public static function save_json_post( $settings ) {
2683
		return FrmDeprecated::save_json_post( $settings );
2684
	}
2685
2686
	/**
2687
	 * @since 2.0
2688
	 * @deprecated 2.05.06
2689
	 * @codeCoverageIgnore
2690
	 *
2691
	 * @param string $cache_key The unique name for this cache
2692
	 * @param string $group The name of the cache group
2693
	 * @param string $query If blank, don't run a db call
2694
	 * @param string $type The wpdb function to use with this query
2695
	 *
2696
	 * @return mixed $results The cache or query results
2697
	 */
2698
	public static function check_cache( $cache_key, $group = '', $query = '', $type = 'get_var', $time = 300 ) {
2699
		return FrmDeprecated::check_cache( $cache_key, $group, $query, $type, $time );
2700
	}
2701
2702
	/**
2703
	 * @deprecated 2.05.06
2704
	 * @codeCoverageIgnore
2705
	 */
2706
	public static function set_cache( $cache_key, $results, $group = '', $time = 300 ) {
2707
		return FrmDeprecated::set_cache( $cache_key, $results, $group, $time );
2708
	}
2709
2710
	/**
2711
	 * @deprecated 2.05.06
2712
	 * @codeCoverageIgnore
2713
	 */
2714
	public static function add_key_to_group_cache( $key, $group ) {
2715
		FrmDeprecated::add_key_to_group_cache( $key, $group );
2716
	}
2717
2718
	/**
2719
	 * @deprecated 2.05.06
2720
	 * @codeCoverageIgnore
2721
	 */
2722
	public static function get_group_cached_keys( $group ) {
2723
		return FrmDeprecated::get_group_cached_keys( $group );
2724
	}
2725
2726
	/**
2727
	 * @since 2.0
2728
	 * @deprecated 2.05.06
2729
	 * @codeCoverageIgnore
2730
	 * @return mixed The cached value or false
2731
	 */
2732
	public static function check_cache_and_transient( $cache_key ) {
2733
		return FrmDeprecated::check_cache( $cache_key );
2734
	}
2735
2736
	/**
2737
	 * @since 2.0
2738
	 * @deprecated 2.05.06
2739
	 * @codeCoverageIgnore
2740
	 *
2741
	 * @param string $cache_key
2742
	 */
2743
	public static function delete_cache_and_transient( $cache_key, $group = 'default' ) {
2744
		FrmDeprecated::delete_cache_and_transient( $cache_key, $group );
2745
	}
2746
2747
	/**
2748
	 * @since 2.0
2749
	 * @deprecated 2.05.06
2750
	 * @codeCoverageIgnore
2751
	 *
2752
	 * @param string $group The name of the cache group
2753
	 */
2754
	public static function cache_delete_group( $group ) {
2755
		FrmDeprecated::cache_delete_group( $group );
2756
	}
2757
2758
	/**
2759
	 * @since 1.07.10
2760
	 * @deprecated 2.05.06
2761
	 * @codeCoverageIgnore
2762
	 *
2763
	 * @param string $term The value to escape
2764
	 *
2765
	 * @return string The escaped value
2766
	 */
2767
	public static function esc_like( $term ) {
2768
		return FrmDeprecated::esc_like( $term );
2769
	}
2770
2771
	/**
2772
	 * @param string $order_query
2773
	 *
2774
	 * @deprecated 2.05.06
2775
	 * @codeCoverageIgnore
2776
	 */
2777
	public static function esc_order( $order_query ) {
2778
		return FrmDeprecated::esc_order( $order_query );
2779
	}
2780
2781
	/**
2782
	 * @deprecated 2.05.06
2783
	 * @codeCoverageIgnore
2784
	 */
2785
	public static function esc_order_by( &$order_by ) {
2786
		FrmDeprecated::esc_order_by( $order_by );
2787
	}
2788
2789
	/**
2790
	 * @param string $limit
2791
	 *
2792
	 * @deprecated 2.05.06
2793
	 * @codeCoverageIgnore
2794
	 */
2795
	public static function esc_limit( $limit ) {
2796
		return FrmDeprecated::esc_limit( $limit );
2797
	}
2798
2799
	/**
2800
	 * @since 2.0
2801
	 * @deprecated 2.05.06
2802
	 * @codeCoverageIgnore
2803
	 */
2804
	public static function prepare_array_values( $array, $type = '%s' ) {
2805
		return FrmDeprecated::prepare_array_values( $array, $type );
2806
	}
2807
2808
	/**
2809
	 * @deprecated 2.05.06
2810
	 * @codeCoverageIgnore
2811
	 */
2812
	public static function prepend_and_or_where( $starts_with = ' WHERE ', $where = '' ) {
2813
		return FrmDeprecated::prepend_and_or_where( $starts_with, $where );
2814
	}
2815
}
2816