Completed
Push — master ( 55c46a...94bd81 )
by Stephanie
15s queued 10s
created

FrmAppHelper::conditional_action_button()   B

Complexity

Conditions 9
Paths 6

Size

Total Lines 40

Duplication

Lines 8
Ratio 20 %

Importance

Changes 0
Metric Value
cc 9
nc 6
nop 4
dl 8
loc 40
rs 7.7244
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.08';
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
	 * Render a conditional action button for an add on
78
	 *
79
	 * @since 4.09
80
	 * @param array $addon
81
	 * @param string|false $license_type
82
	 * @param string $plan_required
83
	 * @param string $upgrade_link
84
	 */
85
	public static function conditional_action_button( $addon, $license_type, $plan_required, $upgrade_link ) {
86 View Code Duplication
		if ( ! $addon ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $addon of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
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...
87
			?>
88
			<a class="install-now button button-secondary frm-button-secondary" href="<?php echo esc_url( $upgrade_link ); ?>" target="_blank" rel="noopener" aria-label="<?php esc_attr_e( 'Upgrade Now', 'formidable' ); ?>">
89
				<?php esc_html_e( 'Upgrade Now', 'formidable' ); ?>
90
			</a>
91
			<?php
92
			return;
93
		}
94
95
		if ( $addon['status']['type'] === 'installed' ) {
96
			?>
97
			<a rel="<?php echo esc_attr( $addon['plugin'] ); ?>" class="button button-primary frm-button-primary frm-activate-addon <?php echo esc_attr( empty( $addon['activate_url'] ) ? 'frm_hidden' : '' ); ?>">
98
				<?php esc_html_e( 'Activate', 'formidable' ); ?>
99
			</a>
100
			<?php
101
		} elseif ( ! empty( $addon['url'] ) ) {
102
			?>
103
			<a class="frm-install-addon button button-primary frm-button-primary" rel="<?php echo esc_attr( $addon['url'] ); ?>" aria-label="<?php esc_attr_e( 'Install', 'formidable' ); ?>">
104
				<?php esc_html_e( 'Install', 'formidable' ); ?>
105
			</a>
106
			<?php
107
		} elseif ( $license_type && $license_type === strtolower( $plan_required ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $license_type of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

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