PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.0.07
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.0.07
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / helpers / FrmAppHelper.php

FrmAppHelper.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 5.0.07, at classes/helpers/FrmAppHelper.php

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