Completed
Push — master ( 6b21ff...339518 )
by Stephanie
15s queued 10s
created

FrmAppHelper::expiring_message()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

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