Completed
Push — master ( 6be7f8...c20a0c )
by Stephanie
02:19
created

FrmAppHelper::prepare_action_slashes()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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