Completed
Push — master ( 48bf95...7ce117 )
by Stephanie
02:51 queued 11s
created

FrmAppHelper::remove_get_action()   A

Complexity

Conditions 6
Paths 13

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

Loading history...
441
		return self::get_simple_request(
442
			array(
443
				'type'     => 'post',
444
				'param'    => $param,
445
				'default'  => $default,
446
				'sanitize' => $sanitize,
447
				'serialized' => $serialized,
448
			)
449
		);
450
	}
451
452
	/**
453
	 * @since 2.0
454
	 *
455
	 * @param string $param
456
	 * @param string $sanitize
457
	 * @param string $default
458
	 *
459
	 * @return string|array
460
	 */
461 View Code Duplication
	public static function simple_get( $param, $sanitize = 'sanitize_text_field', $default = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
462
		return self::get_simple_request(
463
			array(
464
				'type'     => 'get',
465
				'param'    => $param,
466
				'default'  => $default,
467
				'sanitize' => $sanitize,
468
			)
469
		);
470
	}
471
472
	/**
473
	 * Get a GET/POST/REQUEST value and sanitize it
474
	 *
475
	 * @since 2.0.6
476
	 *
477
	 * @param array $args
478
	 *
479
	 * @return string|array
480
	 */
481
	public static function get_simple_request( $args ) {
482
		$defaults = array(
483
			'param'    => '',
484
			'default'  => '',
485
			'type'     => 'get',
486
			'sanitize' => 'sanitize_text_field',
487
			'serialized' => false,
488
		);
489
		$args     = wp_parse_args( $args, $defaults );
490
491
		$value = $args['default'];
492
		if ( $args['type'] == 'get' ) {
493 View Code Duplication
			if ( $_GET && isset( $_GET[ $args['param'] ] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
494
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
495
				$value = wp_unslash( $_GET[ $args['param'] ] );
496
			}
497
		} elseif ( $args['type'] == 'post' ) {
498
			if ( isset( $_POST[ $args['param'] ] ) ) {
499
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
500
				$value = wp_unslash( $_POST[ $args['param'] ] );
501
				if ( $args['serialized'] === true && is_serialized_string( $value ) && is_serialized( $value ) ) {
502
					self::unserialize_or_decode( $value );
503
				}
504
			}
505 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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