PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
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 / FrmFormsHelper.php

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

2,209 lines 62.0 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 FrmFormsHelper {
7
8 /**
9 * Store and re-use field type data for the insert_opt_html function (to avoid multiple calls to FrmField::all_field_selection).
10 *
11 * @since 6.10
12 *
13 * @var array|null
14 */
15 private static $field_type_data_for_insert_opt_html;
16
17 /**
18 * @since 2.2.10
19 *
20 * @return string
21 */
22 public static function form_error_class() {
23 return apply_filters( 'frm_form_error_class', 'frm_error_style' );
24 }
25
26 /**
27 * @param string $key
28 * @param false|object $form
29 *
30 * @return string
31 */
32 public static function get_direct_link( $key, $form = false ) {
33 $target_url = esc_url( admin_url( 'admin-ajax.php?action=frm_forms_preview&form=' . $key ) );
34 return apply_filters( 'frm_direct_link', $target_url, $key, $form );
35 }
36
37 /**
38 * @param string $field_name
39 * @param int|string $field_value
40 * @param array $args
41 *
42 * @return void
43 */
44 public static function forms_dropdown( $field_name, $field_value = '', $args = array() ) {
45 $defaults = array(
46 'blank' => true,
47 'field_id' => false,
48 'onchange' => false,
49 'exclude' => false,
50 'class' => '',
51 'inc_children' => 'exclude',
52 );
53 $args = wp_parse_args( $args, $defaults );
54
55 if ( ! $args['field_id'] ) {
56 $args['field_id'] = $field_name;
57 }
58
59 $query = array();
60
61 if ( $args['exclude'] ) {
62 $query['id !'] = $args['exclude'];
63 }
64
65 $where = apply_filters( 'frm_forms_dropdown', $query, $field_name );
66 $forms = FrmForm::get_published_forms( $where, 999, $args['inc_children'] );
67 $add_html = array();
68 self::add_html_attr( $args['onchange'], 'onchange', $add_html );
69 self::add_html_attr( $args['class'], 'class', $add_html );
70
71 // phpcs:disable Generic.WhiteSpace.ScopeIndent
72 ?>
73 <select name="<?php echo esc_attr( $field_name ); ?>"
74 id="<?php echo esc_attr( $args['field_id'] ); ?>"
75 <?php echo wp_strip_all_tags( implode( ' ', $add_html ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
76 <?php if ( $args['blank'] ) { ?>
77 <option value=""><?php echo $args['blank'] == 1 ? ' ' : '- ' . esc_attr( $args['blank'] ) . ' -'; // phpcs:ignore Universal.Operators.StrictComparisons ?></option>
78 <?php } ?>
79 <?php foreach ( $forms as $form ) { ?>
80 <option value="<?php echo esc_attr( $form->id ); ?>" <?php selected( $field_value, $form->id ); ?>>
81 <?php echo esc_html( '' === $form->name ? self::get_no_title_text() : FrmAppHelper::truncate( $form->name, 50 ) . ( $form->parent_form_id ? __( ' (child)', 'formidable' ) : '' ) ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong ?>
82 </option>
83 <?php } ?>
84 </select>
85 <?php
86 // phpcs:enable Generic.WhiteSpace.ScopeIndent
87 }
88
89 /**
90 * @since 2.0.6
91 *
92 * @param string $class
93 * @param string $param
94 * @param array $add_html
95 *
96 * @return void
97 */
98 public static function add_html_attr( $class, $param, &$add_html ) {
99 if ( $class ) {
100 $add_html[ $param ] = sanitize_title( $param ) . '="' . esc_attr( sanitize_text_field( $class ) ) . '"';
101 }
102 }
103
104 /**
105 * @param false|object|string $selected - The label for the placeholder, or the form object.
106 *
107 * @return void
108 */
109 public static function form_switcher( $selected = false ) { // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh, Generic.Metrics.CyclomaticComplexity.MaxExceeded, SlevomatCodingStandard.Files.LineLength.LineTooLong
110 $where = apply_filters( 'frm_forms_dropdown', array(), '' );
111 $forms = FrmForm::get_published_forms( $where );
112
113 $args = array(
114 'id' => 0,
115 'form' => 0,
116 );
117
118 if ( isset( $_GET['id'] ) && ! isset( $_GET['form'] ) ) {
119 unset( $args['form'] );
120 } elseif ( isset( $_GET['form'] ) && ! isset( $_GET['id'] ) ) {
121 unset( $args['id'] );
122 }
123
124 $frm_action = FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
125
126 if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) && in_array( $frm_action, array( 'edit', 'show', 'destroy', 'destroy_all' ), true ) ) {
127 $args['frm_action'] = 'list';
128 $args['form'] = 0;
129 } elseif ( FrmAppHelper::is_admin_page( 'formidable' ) && in_array( $frm_action, array( 'new', 'duplicate' ), true ) ) {
130 $args['frm_action'] = 'edit';
131 } elseif ( FrmAppHelper::is_style_editor_page() ) {
132 // Avoid passing style into form switcher on style page.
133 unset( $args['id'] );
134 $query_args = array(
135 'page' => 'formidable-styles',
136 );
137
138 if ( $frm_action ) {
139 $query_args['frm_action'] = $frm_action;
140 }
141
142 $base = add_query_arg( $query_args, admin_url( 'admin.php' ) );
143 } elseif ( isset( $_GET['post'] ) ) {
144 $args['form'] = 0;
145 $base = admin_url( 'edit.php?post_type=frm_display' );
146 }//end if
147
148 $form_id = 0;
149
150 if ( is_object( $selected ) ) {
151 $form_id = $selected->id;
152 $selected = $selected->name;
153 }
154
155 $name = $selected === false ? __( 'Switch Form', 'formidable' ) : $selected;
156 $name = '' === $name || is_null( $name ) ? self::get_no_title_text() : strip_tags( $name );
157 $truncated_name = FrmAppHelper::truncate( $name, 25 );
158
159 // phpcs:disable Generic.WhiteSpace.ScopeIndent
160 if ( count( $forms ) < 2 ) {
161 ?>
162 <div id="frm_bs_dropdown">
163 <h1>
164 <span class="frm_bstooltip" title="<?php echo esc_attr( $truncated_name === $name ? '' : $name ); ?>" data-placement="right">
165 <?php echo esc_html( $name ); ?>
166 </span>
167 </h1>
168 </div>
169 <?php
170 return;
171 }
172 ?>
173 <div id="frm_bs_dropdown" class="dropdown <?php echo esc_attr( is_rtl() ? 'dropdown-menu-right' : 'dropdown-menu-left' ); ?>">
174 <a href="#" id="frm-navbarDrop" class="frm-dropdown-toggle" data-toggle="dropdown">
175 <h1>
176 <span class="frm_bstooltip" title="<?php echo esc_attr( $truncated_name === $name ? '' : $name ); ?>" data-placement="right">
177 <?php echo esc_html( $name ); ?>
178 </span>
179 <?php FrmAppHelper::icon_by_class( 'frmfont frm_arrowdown6_icon', array( 'aria-hidden' => 'true' ) ); ?>
180 </h1>
181 </a>
182 <ul class="frm-dropdown-menu frm-on-top frm-inline-modal frm_code_list frm-full-hover" role="menu" aria-labelledby="frm-navbarDrop">
183 <?php if ( count( $forms ) > 8 ) { ?>
184 <li class="frm-with-search">
185 <?php
186 FrmAppHelper::show_search_box(
187 array(
188 'input_id' => 'dropform',
189 'placeholder' => __( 'Search Forms', 'formidable' ),
190 'tosearch' => 'frm-dropdown-form',
191 // Specify a value to avoid the $_REQUEST['s'] default value.
192 'value' => '',
193 )
194 );
195 ?>
196 </li>
197 <?php } ?>
198 <?php
199 foreach ( $forms as $form ) {
200 if ( $form->id === $form_id ) {
201 // Don't include the selected form in the switcher since it does nothing.
202 continue;
203 }
204
205 if ( isset( $args['id'] ) ) {
206 $args['id'] = $form->id;
207 }
208
209 if ( isset( $args['form'] ) ) {
210 $args['form'] = $form->id;
211 }
212
213 $url = isset( $base ) ? add_query_arg( $args, $base ) : add_query_arg( $args );
214 $form_name = ! empty( $form->name ) ? $form->name : self::get_no_title_text();
215 ?>
216 <li class="frm-dropdown-form">
217 <a href="<?php echo esc_url( $url ); ?>" tabindex="-1" class="frm-justify-between">
218 <?php echo esc_html( $form_name ); ?>
219 <span>
220 <?php
221 printf(
222 /* translators: %d: Form ID */
223 esc_html__( '(ID %d)', 'formidable' ),
224 esc_attr( $form->id )
225 );
226 ?>
227 </span>
228 <span class="frm_hidden"><?php echo esc_html( $form->form_key ); ?></span>
229 </a>
230 </li>
231 <?php
232 unset( $form );
233 }//end foreach
234 ?>
235 </ul>
236 </div>
237 <?php
238 // phpcs:enable Generic.WhiteSpace.ScopeIndent
239 }
240
241 /**
242 * @param string $col
243 * @param string $sort_col
244 * @param string $sort_dir
245 *
246 * @return void
247 */
248 public static function get_sortable_classes( $col, $sort_col, $sort_dir ) {
249 echo $sort_col == $col ? 'sorted' : 'sortable'; // phpcs:ignore Universal.Operators.StrictComparisons
250 echo $sort_col == $col && $sort_dir === 'desc' ? ' asc' : ' desc'; // phpcs:ignore Universal.Operators.StrictComparisons
251 }
252
253 /**
254 * @since 3.0
255 *
256 * @param array|string $field_type
257 *
258 * @return string
259 */
260 public static function get_field_link_name( $field_type ) {
261 return is_array( $field_type ) ? $field_type['name'] : $field_type;
262 }
263
264 /**
265 * @since 3.0
266 *
267 * @param array|string $field_type
268 *
269 * @return string
270 */
271 public static function get_field_link_icon( $field_type ) {
272 return is_array( $field_type ) && isset( $field_type['icon'] ) ? $field_type['icon'] : 'frmfont frm_pencil_icon';
273 }
274
275 /**
276 * Get the invalid form error message
277 *
278 * @since 2.02.07
279 *
280 * @param array $args
281 *
282 * @return string
283 */
284 public static function get_invalid_error_message( $args ) {
285 $settings_args = $args;
286
287 if ( isset( $args['form'] ) ) {
288 $settings_args['current_form'] = $args['form']->id;
289 }
290
291 $frm_settings = FrmAppHelper::get_settings( $settings_args );
292 $invalid_msg = do_shortcode( $frm_settings->invalid_msg );
293 return apply_filters( 'frm_invalid_error_message', $invalid_msg, $args );
294 }
295
296 /**
297 * @param array $atts {
298 * The success message details.
299 *
300 * @type string $message
301 * @type stdClass $form
302 * @type int $entry_id
303 * @type string $class
304 * }
305 *
306 * @return string
307 */
308 public static function get_success_message( $atts ) {
309 $message = apply_filters( 'frm_content', $atts['message'], $atts['form'], $atts['entry_id'] );
310
311 // Only autop if the message includes line breaks.
312 $autop = str_contains( $message, "\n" );
313
314 /**
315 * Filters whether to autop the success message.
316 * This is false by default if the message does not include line breaks.
317 *
318 * @since 6.23
319 *
320 * @param bool $autop
321 * @param string $message
322 * @param object $form
323 */
324 $autop = (bool) apply_filters( 'frm_wpautop_success_message', $autop, $message, $atts['form'] );
325
326 if ( $autop ) {
327 $message = FrmAppHelper::use_wpautop( $message );
328 }
329
330 $message = do_shortcode( $message );
331 return '<div class="' . esc_attr( $atts['class'] ) . '" role="status">' . $message . '</div>';
332 }
333
334 /**
335 * Used when a form is created
336 *
337 * @param array $values
338 *
339 * @return array
340 */
341 public static function setup_new_vars( $values = array() ) {
342 global $wpdb;
343
344 if ( $values ) {
345 $post_values = $values;
346 } else {
347 $values = array();
348 $post_values = ! empty( $_POST ) ? $_POST : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing
349 }
350
351 $defaults = array(
352 'name' => '',
353 'description' => '',
354 );
355
356 foreach ( $defaults as $var => $default ) {
357 if ( ! isset( $values[ $var ] ) ) {
358 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
359 }
360 }
361
362 $values['description'] = FrmAppHelper::use_wpautop( $values['description'] );
363
364 $defaults = array(
365 'form_id' => '',
366 'logged_in' => '',
367 'editable' => '',
368 'is_template' => 0,
369 'status' => 'published',
370 'parent_form_id' => 0,
371 );
372
373 foreach ( $defaults as $var => $default ) {
374 if ( ! isset( $values[ $var ] ) ) {
375 $values[ $var ] = FrmAppHelper::get_param( $var, $default, 'get', 'sanitize_text_field' );
376 }
377 }
378 unset( $defaults );
379
380 if ( ! isset( $values['form_key'] ) ) {
381 $values['form_key'] = $post_values && isset( $post_values['form_key'] ) ? $post_values['form_key'] : FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_forms', 'form_key' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
382 }
383
384 $values = self::fill_default_opts( $values, false, $post_values );
385 $values['custom_style'] = FrmAppHelper::custom_style_value( $post_values );
386
387 return apply_filters( 'frm_setup_new_form_vars', $values );
388 }
389
390 /**
391 * Used when editing a form
392 *
393 * @param array $values
394 * @param object $record
395 * @param array $post_values
396 *
397 * @return array
398 */
399 public static function setup_edit_vars( $values, $record, $post_values = array() ) {
400 if ( ! $post_values ) {
401 $post_values = wp_unslash( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
402 }
403
404 $values['form_key'] = $post_values['form_key'] ?? $record->form_key;
405 $values['is_template'] = $post_values['is_template'] ?? $record->is_template;
406 $values['status'] = $record->status;
407
408 $values = self::fill_default_opts( $values, $record, $post_values );
409
410 return apply_filters( 'frm_setup_edit_form_vars', $values );
411 }
412
413 /**
414 * @param array $values
415 * @param false|object $record
416 * @param array|false $post_values
417 *
418 * @return array
419 */
420 public static function fill_default_opts( $values, $record, $post_values ) { // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh
421
422 foreach ( self::get_default_opts() as $var => $default ) {
423 if ( is_array( $default ) ) {
424 if ( ! isset( $values[ $var ] ) ) {
425 $values[ $var ] = $record && isset( $record->options[ $var ] ) ? $record->options[ $var ] : array();
426 }
427
428 foreach ( $default as $k => $v ) {
429 $values[ $var ][ $k ] = $post_values && isset( $post_values[ $var ][ $k ] ) ? $post_values[ $var ][ $k ] : ( $record && isset( $record->options[ $var ] ) && isset( $record->options[ $var ][ $k ] ) ? $record->options[ $var ][ $k ] : $v ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
430
431 if ( is_array( $v ) ) {
432 foreach ( $v as $k1 => $v1 ) {
433 $values[ $var ][ $k ][ $k1 ] = $post_values && isset( $post_values[ $var ][ $k ][ $k1 ] ) ? $post_values[ $var ][ $k ][ $k1 ] : ( $record && isset( $record->options[ $var ] ) && isset( $record->options[ $var ][ $k ] ) && isset( $record->options[ $var ][ $k ][ $k1 ] ) ? $record->options[ $var ][ $k ][ $k1 ] : $v1 ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
434 unset( $k1, $v1 );
435 }
436 }
437
438 unset( $k, $v );
439 }
440 } else {
441 $values[ $var ] = $post_values && isset( $post_values['options'][ $var ] ) ? $post_values['options'][ $var ] : ( $record && isset( $record->options[ $var ] ) ? $record->options[ $var ] : $default ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
442 }
443
444 unset( $var, $default );
445 }//end foreach
446
447 return $values;
448 }
449
450 /**
451 * @return array
452 */
453 public static function get_default_opts() {
454 $frm_settings = FrmAppHelper::get_settings();
455
456 return array(
457 'submit_value' => $frm_settings->submit_value,
458 'success_action' => 'message',
459 'success_msg' => $frm_settings->success_msg,
460 'show_form' => 0,
461 'akismet' => '',
462 'stopforumspam' => 0,
463 'antispam' => 0,
464 'no_save' => 0,
465 'ajax_load' => 0,
466 'js_validate' => 0,
467 'form_class' => '',
468 'custom_style' => 1,
469 'before_html' => self::get_default_html( 'before' ),
470 'after_html' => '',
471 'submit_html' => self::get_default_html( 'submit' ),
472 'show_title' => 0,
473 'show_description' => 0,
474 'ajax_submit' => 0,
475 );
476 }
477
478 /**
479 * @since 2.0.6
480 *
481 * @param array $options
482 * @param array $values
483 *
484 * @return void
485 */
486 public static function fill_form_options( &$options, $values ) {
487 foreach ( self::get_default_opts() as $var => $default ) {
488 $options[ $var ] = $values['options'][ $var ] ?? $default;
489 unset( $var, $default );
490 }
491 }
492
493 /**
494 * @param string $loc
495 *
496 * @return string
497 */
498 public static function get_default_html( $loc ) {
499 if ( $loc === 'submit' ) {
500 $draft_link = self::get_draft_link();
501 $start_over = self::get_start_over_shortcode();
502 $default_html = <<<SUBMIT_HTML
503 <div class="frm_submit frm_flex">
504 <button class="frm_button_submit" type="submit" [button_action]>[button_label]</button>
505 [if back_button]<button type="submit" name="frm_prev_page" formnovalidate="formnovalidate" class="frm_prev_page" [back_hook]>[back_label]</button>[/if back_button]
506 $draft_link
507 $start_over
508 </div>
509 SUBMIT_HTML;
510 } elseif ( $loc === 'before' ) {
511 $default_html = <<<BEFORE_HTML
512 <legend class="frm_screen_reader">[form_name]</legend>
513 [if form_name]<h3 class="frm_form_title">[form_name]</h3>[/if form_name]
514 [if form_description]<div class="frm_description">[form_description]</div>[/if form_description]
515 BEFORE_HTML;
516 } else {
517 $default_html = '';
518 }
519
520 return $default_html;
521 }
522
523 /**
524 * @return string
525 */
526 public static function get_draft_link() {
527 return '[if save_draft]<button class="frm_save_draft" [draft_hook]>[draft_label]</button>[/if save_draft]';
528 }
529
530 /**
531 * Gets start over button shortcode.
532 *
533 * @since 5.4
534 *
535 * @return string
536 */
537 public static function get_start_over_shortcode() {
538 return '[if start_over]<a href="#" tabindex="0" class="frm_start_over" [start_over_hook]>[start_over_label]</a>[/if start_over]';
539 }
540
541 /**
542 * @param string $html
543 * @param object $form
544 * @param string $submit
545 * @param object|null $form_action
546 * @param array $values
547 *
548 * @return void
549 */
550 public static function get_custom_submit( $html, $form, $submit, $form_action, $values ) {
551 $button = self::replace_shortcodes( $html, $form, $submit, $form_action, $values );
552
553 if ( ! str_contains( $button, '[button_action]' ) ) {
554 echo FrmAppHelper::maybe_kses( $button ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
555 return;
556 }
557
558 /**
559 * @since 5.0.06
560 */
561 $button = apply_filters( 'frm_submit_button_html', $button, compact( 'form' ) );
562
563 if ( FrmAppHelper::should_never_allow_unfiltered_html() ) {
564 $button = FrmAppHelper::kses_submit_button( $button );
565 }
566
567 $button_parts = explode( '[button_action]', $button );
568 $classes = apply_filters( 'frm_submit_button_class', array(), $form );
569
570 if ( $classes ) {
571 $classes = implode( ' ', $classes );
572 $button_class = 'frm_button_submit';
573
574 if ( preg_match( '/\bclass="[^"]*?\b' . preg_quote( $button_class, '/' ) . '\b[^"]*?"/', $button_parts[0] ) ) {
575 $button_parts[0] = str_replace( $button_class, $button_class . ' ' . esc_attr( $classes ), $button_parts[0] );
576 } else {
577 $button_parts[0] .= ' class="' . esc_attr( $classes ) . '"';
578 }
579 }
580
581 echo $button_parts[0]; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
582 do_action( 'frm_submit_button_action', $form, $form_action );
583 echo $button_parts[1]; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
584 }
585
586 /**
587 * @since 4.0
588 *
589 * @return array
590 */
591 public static function html_shortcodes() {
592 $codes = array(
593 'id' => array(
594 'label' => __( 'Field ID', 'formidable' ),
595 'class' => 'show_field_custom_html',
596 ),
597 'key' => array(
598 'label' => __( 'Field Key', 'formidable' ),
599 'class' => 'show_field_custom_html',
600 ),
601 'field_name' => array(
602 'label' => __( 'Field Name', 'formidable' ),
603 'class' => 'show_field_custom_html',
604 ),
605 'description' => array(
606 'label' => __( 'Field Description', 'formidable' ),
607 'class' => 'show_field_custom_html',
608 ),
609 'label_position' => array(
610 'label' => __( 'Label Position', 'formidable' ),
611 'class' => 'show_field_custom_html',
612 ),
613 'required_label' => array(
614 'label' => __( 'Required Label', 'formidable' ),
615 'class' => 'show_field_custom_html',
616 ),
617 'input' => array(
618 'label' => __( 'Input Field', 'formidable' ),
619 'class' => 'show_field_custom_html',
620 ),
621 'input opt=1' => array(
622 'label' => __( 'Single Option', 'formidable' ),
623 'title' => __( 'Show a single radio or checkbox option by replacing 1 with the order of the option', 'formidable' ),
624 'class' => 'show_field_custom_html',
625 ),
626 'input label=0' => array(
627 'label' => __( 'Hide Option Label', 'formidable' ),
628 'class' => 'show_field_custom_html',
629 ),
630 'required_class' => array(
631 'label' => __( 'Required Class', 'formidable' ),
632 'title' => __( 'Add class name if field is required', 'formidable' ),
633 'class' => 'show_field_custom_html',
634 ),
635 'error_class' => array(
636 'label' => __( 'Error Class', 'formidable' ),
637 'title' => __( 'Add class name if field has an error on form submit', 'formidable' ),
638 'class' => 'show_field_custom_html',
639 ),
640
641 'form_name' => array(
642 'label' => __( 'Form Name', 'formidable' ),
643 'class' => 'show_before_html show_after_html',
644 ),
645 'form_description' => array(
646 'label' => __( 'Form Description', 'formidable' ),
647 'class' => 'show_before_html show_after_html',
648 ),
649 'form_key' => array(
650 'label' => __( 'Form Key', 'formidable' ),
651 'class' => 'show_before_html show_after_html',
652 ),
653 'deletelink' => array(
654 'label' => __( 'Delete Entry Link', 'formidable' ),
655 'class' => 'show_before_html show_after_html',
656 ),
657
658 'button_label' => array(
659 'label' => __( 'Button Label', 'formidable' ),
660 'class' => 'show_submit_html',
661 ),
662 'button_action' => array(
663 'label' => __( 'Button Hook', 'formidable' ),
664 'class' => 'show_submit_html',
665 ),
666 );
667
668 /**
669 * @since 4.0
670 */
671 return apply_filters( 'frm_html_codes', $codes );
672 }
673
674 /**
675 * @since 4.0
676 *
677 * @param array $args Includes 'id', 'key', 'name', 'type' and 'class'. Optionally 'id_label'
678 * and 'key_label' to show something other than the id or key, and
679 * 'name_suffix'/'key_suffix' for text appended after the name or key is
680 * truncated, so a shortcode option like ' show=first' survives the truncation.
681 *
682 * @return void
683 */
684 public static function insert_opt_html( $args ) {
685 $class = $args['class'] ?? '';
686 $fields = self::get_field_type_data_for_insert_opt_html();
687 $field = $fields[ $args['type'] ] ?? array();
688
689 self::prepare_field_type( $field );
690
691 if ( ! isset( $field['icon'] ) ) {
692 $field['icon'] = 'frmfont frm_pencil_icon';
693 }
694
695 $possible_email_field = FrmFieldFactory::field_has_property( $args['type'], 'holds_email_values' );
696
697 if ( $possible_email_field ) {
698 $class .= ' show_frm_not_email_to';
699 }
700
701 if ( 'url' === $args['type'] ) {
702 $class .= ' frm_insert_url';
703 }
704
705 $full_name = $args['name'] . ( $args['name_suffix'] ?? '' );
706 $truncated_name = FrmAppHelper::truncate( $args['name'], 60 ) . ( $args['name_suffix'] ?? '' );
707
708 // phpcs:disable Generic.WhiteSpace.ScopeIndent
709 ?>
710 <li class="<?php echo esc_attr( $class ); ?>">
711 <a href="javascript:void(0)" class="frmids frm_insert_code" data-code="<?php echo esc_attr( $args['id'] ); ?>">
712 <?php
713 if ( isset( $field['icon'] ) ) {
714 FrmAppHelper::icon_by_class( $field['icon'], array( 'aria-hidden' => 'true' ) );
715 }
716
717 printf(
718 '<span title="%s">%s</span>',
719 esc_attr( $full_name ),
720 esc_html( $truncated_name )
721 );
722 ?>
723 <span>[<?php echo esc_html( $args['id_label'] ?? $args['id'] ); ?>]</span>
724 </a>
725 <a href="javascript:void(0)" class="frmkeys frm_insert_code frm_hidden" data-code="<?php echo esc_attr( $args['key'] ); ?>">
726 <?php
727 if ( isset( $field['icon'] ) ) {
728 FrmAppHelper::icon_by_class( $field['icon'], array( 'aria-hidden' => 'true' ) );
729 }
730
731 printf(
732 '<span title="%s">%s</span>',
733 esc_attr( $full_name ),
734 esc_html( $truncated_name )
735 );
736 ?>
737 <span>[<?php echo esc_html( FrmAppHelper::truncate( $args['key_label'] ?? $args['key'], 7 ) . ( $args['key_suffix'] ?? '' ) ); ?>]</span>
738 </a>
739 </li>
740 <?php
741 // phpcs:enable Generic.WhiteSpace.ScopeIndent
742 }
743
744 /**
745 * Store and re-use field selection data for use when outputting shortcodes options in shortcode pop up.
746 * This significantly improves performance by avoiding repeat calls to FrmField::all_field_selection.
747 *
748 * @since 6.10
749 *
750 * @return array
751 */
752 private static function get_field_type_data_for_insert_opt_html() {
753 if ( ! isset( self::$field_type_data_for_insert_opt_html ) ) {
754 self::$field_type_data_for_insert_opt_html = FrmField::all_field_selection();
755 }
756 return self::$field_type_data_for_insert_opt_html;
757 }
758
759 /**
760 * @since 4.0
761 *
762 * @param array $args
763 *
764 * @return void
765 */
766 public static function insert_code_html( $args ) {
767 $defaults = array(
768 'class' => '',
769 'code' => '',
770 'label' => '',
771 'title' => '',
772 );
773
774 $args = array_merge( $defaults, $args );
775 $has_tooltip = ! empty( $args['title'] );
776
777 // phpcs:disable Generic.WhiteSpace.ScopeIndent
778 ?>
779 <li class="<?php echo esc_attr( $args['class'] ); ?>">
780 <a href="javascript:void(0)" class="frm_insert_code <?php echo $has_tooltip ? 'frm_help' : ''; ?>"
781 <?php echo $has_tooltip ? 'title="' . esc_attr( $args['title'] ) . '"' : ''; ?>
782 data-code="<?php echo esc_attr( $args['code'] ); ?>">
783 <?php echo esc_html( FrmAppHelper::truncate( $args['label'], 60 ) ); ?>
784 <span>
785 [<?php echo esc_html( FrmAppHelper::truncate( $args['code'], 10 ) ); ?>]
786 </span>
787 </a>
788 </li>
789 <?php
790 // phpcs:enable Generic.WhiteSpace.ScopeIndent
791 }
792
793 /**
794 * Some field types in add-ons may have been added with only
795 * a field type and name.
796 *
797 * @since 4.0
798 *
799 * @param array|string $field
800 *
801 * @return void
802 */
803 public static function prepare_field_type( &$field ) {
804 if ( ! is_array( $field ) ) {
805 $field = array(
806 'name' => $field,
807 'icon' => 'frmfont frm_pencil_icon',
808 );
809 }
810 }
811
812 /**
813 * Automatically add end section fields if they don't exist (2.0 migration)
814 *
815 * @since 2.0
816 *
817 * @param object $form
818 * @param array $fields
819 * @param bool $reset_fields
820 *
821 * @return void
822 */
823 public static function auto_add_end_section_fields( $form, $fields, &$reset_fields ) {
824 if ( ! $fields ) {
825 return;
826 }
827
828 $end_section_values = apply_filters( 'frm_before_field_created', FrmFieldsHelper::setup_new_vars( 'end_divider', $form->id ) );
829 $open = false;
830 $prev_order = false;
831 $add_order = 0;
832 $last_field = false;
833
834 foreach ( $fields as $field ) {
835 if ( $prev_order === $field->field_order ) {
836 ++$add_order;
837 }
838
839 if ( $add_order ) {
840 $reset_fields = true;
841 $field->field_order = $field->field_order + $add_order;
842 FrmField::update( $field->id, array( 'field_order' => $field->field_order ) );
843 }
844
845 switch ( $field->type ) {
846 case 'divider':
847 // Create an end section if open.
848 self::maybe_create_end_section( $open, $reset_fields, $add_order, $end_section_values, $field, 'move' );
849
850 // Mark it open for the next end section.
851 $open = true;
852 break;
853 case 'break':
854 self::maybe_create_end_section( $open, $reset_fields, $add_order, $end_section_values, $field, 'move' );
855 break;
856 case 'end_divider':
857 if ( ! $open ) {
858 // The section isn't open, so this is an extra field that needs to be removed.
859 FrmField::destroy( $field->id );
860 $reset_fields = true;
861 }
862
863 // There is already an end section here, so there is no need to create one.
864 $open = false;
865 }//end switch
866 $prev_order = $field->field_order;
867
868 $last_field = $field;
869 unset( $field );
870 }//end foreach
871
872 self::maybe_create_end_section( $open, $reset_fields, $add_order, $end_section_values, $last_field );
873 }
874
875 /**
876 * Create end section field if it doesn't exist. This is for migration from < 2.0
877 * Fix any ordering that may be messed up
878 *
879 * @param bool $open
880 * @param bool $reset_fields
881 * @param int $add_order
882 * @param array $end_section_values
883 * @param object $field
884 * @param string $move
885 *
886 * @return void
887 */
888 public static function maybe_create_end_section( &$open, &$reset_fields, &$add_order, $end_section_values, $field, $move = 'no' ) {
889 if ( ! $open ) {
890 return;
891 }
892
893 $end_section_values['field_order'] = $field->field_order + 1;
894
895 FrmField::create( $end_section_values );
896
897 if ( $move === 'move' ) {
898 // Bump the order of current field unless we're at the end of the form
899 FrmField::update( $field->id, array( 'field_order' => $field->field_order + 2 ) );
900 }
901
902 $add_order += 2;
903 $open = false;
904 $reset_fields = true;
905 }
906
907 /**
908 * @param string $html
909 * @param object $form
910 * @param bool $title
911 * @param bool $description
912 * @param array $values
913 *
914 * @return string
915 */
916 public static function replace_shortcodes( $html, $form, $title = false, $description = false, $values = array() ) {
917 $codes = array(
918 'form_name' => $title,
919 'form_description' => $description,
920 'entry_key' => true,
921 );
922
923 foreach ( $codes as $code => $show ) {
924 if ( $code === 'form_name' ) {
925 $replace_with = $form->name;
926 } elseif ( $code === 'form_description' ) {
927 $replace_with = FrmAppHelper::use_wpautop( $form->description );
928 } elseif ( $code === 'entry_key' && ! empty( $_GET ) && isset( $_GET['entry'] ) ) {
929 $replace_with = FrmAppHelper::simple_get( 'entry', 'sanitize_title' );
930 } else {
931 $replace_with = '';
932 }
933
934 FrmShortcodeHelper::remove_inline_conditions( FrmAppHelper::is_true( $show ) && $replace_with != '', $code, $replace_with, $html ); // phpcs:ignore Universal.Operators.StrictComparisons, SlevomatCodingStandard.Files.LineLength.LineTooLong
935 }
936
937 // Replace [form_key].
938 $html = str_replace( '[form_key]', $form->form_key, $html );
939
940 // Replace [frmurl].
941 $html = str_replace( '[frmurl]', FrmFieldsHelper::dynamic_default_values( 'frmurl' ), $html );
942
943 if ( str_contains( $html, '[button_label]' ) ) {
944 add_filter( 'frm_submit_button', 'FrmFormsHelper::submit_button_label', 1 );
945 $submit_label = apply_filters( 'frm_submit_button', $title, $form );
946 $submit_label = esc_attr( do_shortcode( $submit_label ) );
947 $html = str_replace( '[button_label]', $submit_label, $html );
948 }
949
950 $html = apply_filters( 'frm_form_replace_shortcodes', $html, $form, $values );
951
952 if ( str_contains( $html, '[if back_button]' ) ) {
953 $html = preg_replace( '/(\[if\s+back_button\])(.*?)(\[\/if\s+back_button\])/mis', '', $html );
954 }
955
956 if ( str_contains( $html, '[if save_draft]' ) ) {
957 $html = preg_replace( '/(\[if\s+save_draft\])(.*?)(\[\/if\s+save_draft\])/mis', '', $html );
958 }
959
960 if ( str_contains( $html, '[if start_over]' ) ) {
961 $html = preg_replace( '/(\[if\s+start_over\])(.*?)(\[\/if\s+start_over\])/mis', '', $html );
962 }
963
964 if ( apply_filters( 'frm_do_html_shortcodes', true ) ) {
965 return do_shortcode( $html );
966 }
967
968 return $html;
969 }
970
971 /**
972 * @param string $submit
973 *
974 * @return string
975 */
976 public static function submit_button_label( $submit ) {
977 if ( ! $submit ) {
978 $frm_settings = FrmAppHelper::get_settings();
979 $submit = $frm_settings->submit_value;
980 }
981
982 return $submit;
983 }
984
985 /**
986 * If the Formidable styling isn't being loaded,
987 * use inline styling to hide the element
988 *
989 * @since 2.03.05
990 *
991 * @return void
992 */
993 public static function maybe_hide_inline() {
994 $frm_settings = FrmAppHelper::get_settings();
995
996 if ( $frm_settings->load_style === 'none' ) {
997 echo ' style="display:none;"';
998 } elseif ( $frm_settings->load_style === 'dynamic' ) {
999 FrmStylesController::enqueue_style();
1000 }
1001 }
1002
1003 /**
1004 * @param array|bool|int|object|string $form
1005 *
1006 * @return string|null
1007 */
1008 public static function get_form_style_class( $form = false ) {
1009 $style = self::get_form_style( $form );
1010 $class = ' with_frm_style';
1011
1012 if ( ! $style ) {
1013 return FrmAppHelper::is_admin_page( 'formidable-entries' ) ? $class : null;
1014 }
1015
1016 // If submit button needs to be inline or centered.
1017 if ( is_object( $form ) ) {
1018 $form = $form->options;
1019 }
1020
1021 if ( ! empty( $form['submit_align'] ) ) {
1022 $submit_align = $form['submit_align'];
1023 } elseif ( self::form_should_be_inline_and_missing_class( $form ) ) {
1024 $submit_align = 'inline';
1025 } else {
1026 $submit_align = '';
1027 }
1028
1029 if ( 'inline' === $submit_align ) {
1030 $class .= ' frm_inline_form';
1031 $class .= self::maybe_align_fields_top( $form );
1032 } elseif ( 'center' === $submit_align ) {
1033 $class .= ' frm_center_submit';
1034 }
1035
1036 return apply_filters( 'frm_add_form_style_class', $class, $style, compact( 'form' ) );
1037 }
1038
1039 /**
1040 * In order for frm_inline_submit to inline the submit button the form must also have the frm_inline_form that adds the grid-column style rules required for it to work.
1041 *
1042 * @since 5.0.12
1043 *
1044 * @param array $form
1045 *
1046 * @return bool
1047 */
1048 private static function form_should_be_inline_and_missing_class( $form ) {
1049 if ( isset( $form['form_class'] ) && str_contains( ' ' . $form['form_class'] . ' ', ' frm_inline_form ' ) ) {
1050 // Not missing class, avoid adding it twice.
1051 return false;
1052 }
1053 return ! empty( $form['submit_html'] ) && str_contains( $form['submit_html'], 'frm_inline_submit' );
1054 }
1055
1056 /**
1057 * Returns appropriate class if form has top labels
1058 *
1059 * @param array $form
1060 *
1061 * @return string
1062 */
1063 private static function maybe_align_fields_top( $form ) {
1064 return self::form_has_top_labels( $form ) ? ' frm_inline_top' : '';
1065 }
1066
1067 /**
1068 * Determine if a form has fields with top labels so submit button can be aligned properly
1069 *
1070 * @param array $form
1071 *
1072 * @return bool
1073 */
1074 private static function form_has_top_labels( $form ) {
1075 if ( ! isset( $form['fields'] ) ) {
1076 return false;
1077 }
1078
1079 $fields = $form['fields'];
1080
1081 if ( count( $fields ) <= 0 ) {
1082 return false;
1083 }
1084
1085 // Start from the fields closest to the submit button.
1086 $fields = array_reverse( $fields );
1087
1088 foreach ( $fields as $field ) {
1089 $type = $field['original_type'] ?? $field['type'];
1090 $has_input = FrmFieldFactory::field_has_property( $type, 'has_input' );
1091
1092 if ( $has_input ) {
1093 return self::field_has_top_label( $field, $form );
1094 }
1095 }
1096
1097 return false;
1098 }
1099
1100 /**
1101 * Check if a field's label position is set to "top"
1102 *
1103 * @param array $field
1104 * @param bool|object|string $form
1105 *
1106 * @return bool
1107 */
1108 private static function field_has_top_label( $field, $form ) {
1109 $label_position = FrmFieldsHelper::label_position( $field['label'], $field, $form );
1110 return in_array( $label_position, array( 'top', 'inside', 'hidden' ), true );
1111 }
1112
1113 /**
1114 * @param array|bool|int|object|string $form
1115 *
1116 * @return int|string
1117 */
1118 public static function get_form_style( $form ) {
1119 $style = 1;
1120
1121 if ( ! $form || 'default' === $form ) {
1122 return $style;
1123 }
1124
1125 if ( is_object( $form ) && $form->parent_form_id ) {
1126 // Get the parent form if this is a child
1127 $form = $form->parent_form_id;
1128 } elseif ( is_array( $form ) && ! empty( $form['parent_form_id'] ) ) {
1129 $form = $form['parent_form_id'];
1130 } elseif ( is_array( $form ) && isset( $form['custom_style'] ) ) {
1131 $style = $form['custom_style'];
1132 }
1133
1134 if ( $form && ( is_string( $form ) || is_int( $form ) ) ) {
1135 $form = FrmForm::getOne( $form );
1136 }
1137
1138 return $form && is_object( $form ) && isset( $form->options['custom_style'] ) ? $form->options['custom_style'] : $style;
1139 }
1140
1141 /**
1142 * Display the validation error messages when an entry is submitted
1143 *
1144 * @since 2.0.6
1145 *
1146 * @param array $args Includes img, errors.
1147 *
1148 * @return void
1149 */
1150 public static function show_errors( $args ) {
1151 $invalid_msg = self::get_invalid_error_message( $args );
1152
1153 if ( $invalid_msg ) {
1154 echo wp_kses_post( $invalid_msg );
1155 $show_img = true;
1156 } else {
1157 $show_img = false;
1158 }
1159
1160 self::show_error(
1161 array(
1162 'img' => $args['img'],
1163 'errors' => $args['errors'],
1164 'show_img' => $show_img,
1165 )
1166 );
1167 }
1168
1169 /**
1170 * Display the error message in the front-end along with the image if set
1171 * The image was removed from the styling settings, but it may still be set with a hook
1172 * If the message in the global settings is empty, show every validation message in the error box
1173 *
1174 * @since 2.0.6
1175 *
1176 * @param array $args Includes img, errors, and show_img.
1177 *
1178 * @return void
1179 */
1180 public static function show_error( $args ) {
1181 // Remove any blank messages
1182 $args['errors'] = array_filter( (array) $args['errors'] );
1183
1184 $line_break_first = $args['show_img'];
1185
1186 foreach ( $args['errors'] as $error_key => $error ) {
1187 if ( $line_break_first && ! is_numeric( $error_key ) && ( $error_key === 'cptch_number' || str_starts_with( $error_key, 'field' ) ) ) {
1188 continue;
1189 }
1190
1191 $id = str_replace( 'field', 'field_', $error_key );
1192 echo '<div id="' . esc_attr( $id ) . '_error">';
1193
1194 if ( $args['show_img'] && ! empty( $args['img'] ) ) {
1195 echo '<img src="' . esc_url( $args['img'] ) . '" alt="" />';
1196 } else {
1197 $args['show_img'] = true;
1198 }
1199
1200 echo wp_kses_post( $error );
1201
1202 echo '</div>';
1203 }
1204 }
1205
1206 /**
1207 * @param int|string $id
1208 *
1209 * @return void
1210 */
1211 public static function maybe_get_scroll_js( $id ) {
1212 $offset = apply_filters( 'frm_scroll_offset', 4, array( 'form_id' => $id ) );
1213
1214 // phpcs:ignore Universal.Operators.StrictComparisons
1215 if ( $offset != - 1 ) {
1216 self::get_scroll_js( $id );
1217 }
1218 }
1219
1220 /**
1221 * @param int|string $form_id
1222 *
1223 * @return void
1224 */
1225 public static function get_scroll_js( $form_id ) {
1226 echo '<script type="text/javascript">document.addEventListener(\'DOMContentLoaded\',function(){frmFrontForm.scrollMsg(' . (int) $form_id . ');})</script>';
1227 }
1228
1229 /**
1230 * @since 3.0
1231 *
1232 * @param int|object|string $form_id
1233 * @param mixed $form
1234 *
1235 * @return array
1236 */
1237 public static function get_action_links( $form_id, $form ) {
1238 if ( ! is_object( $form ) ) {
1239 $form = FrmForm::getOne( $form_id );
1240 }
1241
1242 $actions = array();
1243 $trash_links = self::delete_trash_links( $form_id );
1244
1245 if ( 'trash' === $form->status ) {
1246 $actions['restore'] = $trash_links['restore'];
1247
1248 if ( current_user_can( 'frm_delete_forms' ) ) {
1249 $actions['trash'] = $trash_links['delete'];
1250 }
1251 } elseif ( current_user_can( 'frm_edit_forms' ) ) {
1252 $duplicate_link = '?page=formidable&frm_action=duplicate&id=' . $form_id;
1253
1254 if ( $form->is_template ) {
1255 $actions['frm_duplicate'] = array(
1256 'url' => wp_nonce_url( $duplicate_link ),
1257 'label' => __( 'Create Form from Template', 'formidable' ),
1258 'icon' => 'frmfont frm_clone_icon',
1259 );
1260 } else {
1261 $actions['duplicate'] = array(
1262 'url' => wp_nonce_url( $duplicate_link ),
1263 'label' => __( 'Duplicate', 'formidable' ),
1264 'icon' => 'frmfont frm_clone_icon',
1265 );
1266 }
1267
1268 $actions['trash'] = self::delete_trash_info( $form_id, $form->status );
1269 }//end if
1270
1271 return $actions;
1272 }
1273
1274 /**
1275 * @param int|object|string $data
1276 *
1277 * @return string
1278 */
1279 public static function edit_form_link( $data ) {
1280 $form_id = self::get_form_id_from_data( $data );
1281
1282 if ( ! $form_id ) {
1283 return '';
1284 }
1285
1286 $label = self::edit_form_link_label( $data );
1287 return '<a href="' . esc_url( FrmForm::get_edit_link( $form_id ) ) . '">' . esc_html( $label ) . '</a>';
1288 }
1289
1290 /**
1291 * Returns a text used when no title is set.
1292 *
1293 * @since 6.16.1
1294 *
1295 * @return string
1296 */
1297 public static function get_no_title_text() {
1298 return __( '(no title)', 'formidable' );
1299 }
1300
1301 /**
1302 * @param int|object|string $data
1303 *
1304 * @return string
1305 */
1306 public static function edit_form_link_label( $data ) {
1307 $name = self::get_form_name_from_data( $data );
1308
1309 if ( ! $name ) {
1310 return self::get_no_title_text();
1311 }
1312
1313 return FrmAppHelper::truncate( $name, 40 );
1314 }
1315
1316 /**
1317 * @param int|object|string $data
1318 *
1319 * @return int|string
1320 */
1321 private static function get_form_id_from_data( $data ) {
1322 return is_object( $data ) ? $data->id : $data;
1323 }
1324
1325 /**
1326 * @param mixed $data
1327 *
1328 * @return string
1329 */
1330 private static function get_form_name_from_data( $data ) {
1331 if ( is_object( $data ) ) {
1332 return $data->name;
1333 }
1334
1335 $form_id = $data;
1336 return FrmForm::getName( $form_id );
1337 }
1338
1339 /**
1340 * @param int $id
1341 * @param string $status
1342 * @param string $length
1343 *
1344 * @return string
1345 */
1346 public static function delete_trash_link( $id, $status, $length = 'label' ) {
1347 $link_details = self::delete_trash_info( $id, $status );
1348 return self::format_link_html( $link_details, $length );
1349 }
1350
1351 /**
1352 * @since 3.0
1353 *
1354 * @param array $link_details
1355 * @param string $length
1356 *
1357 * @return string
1358 */
1359 public static function format_link_html( $link_details, $length = 'label' ) {
1360 $link = '';
1361
1362 if ( ! $link_details ) {
1363 return $link;
1364 }
1365
1366 $link = '<a href="' . esc_url( $link_details['url'] ) . '" class="frm-trash-link"';
1367
1368 if ( isset( $link_details['data'] ) ) {
1369 foreach ( $link_details['data'] as $data => $value ) {
1370 $link .= ' data-' . esc_attr( $data ) . '="' . esc_attr( $value ) . '"';
1371 }
1372 } elseif ( isset( $link_details['confirm'] ) ) {
1373 $link .= ' onclick="return confirm(\'' . esc_attr( $link_details['confirm'] ) . '\')"';
1374 }
1375
1376 $label = $link_details[ $length ] ?? $link_details['label'];
1377
1378 if ( $length === 'icon' && isset( $link_details[ $length ] ) ) {
1379 $label = '<span class="' . $label . '" title="' . esc_attr( $link_details['label'] ) . '" aria-hidden="true"></span>';
1380 $link .= ' aria-label="' . esc_attr( $link_details['label'] ) . '"';
1381 }
1382
1383 return $link . ( '>' . $label . '</a>' );
1384 }
1385
1386 /**
1387 * @since 3.0
1388 *
1389 * @param int $id
1390 * @param string $status
1391 *
1392 * @return array
1393 */
1394 public static function delete_trash_info( $id, $status ) {
1395 $labels = self::delete_trash_links( $id );
1396
1397 if ( 'trash' === $status ) {
1398 $info = $labels['restore'];
1399 } elseif ( current_user_can( 'frm_delete_forms' ) ) {
1400 $info = EMPTY_TRASH_DAYS ? $labels['trash'] : $labels['delete'];
1401 } else {
1402 $info = array();
1403 }
1404
1405 return $info;
1406 }
1407
1408 /**
1409 * @since 3.0
1410 *
1411 * @param int $id
1412 *
1413 * @return array
1414 */
1415 public static function delete_trash_links( $id ) {
1416 $current_page = FrmAppHelper::get_simple_request( array( 'param' => 'form_type' ) );
1417 $base_url = '?page=formidable&form_type=' . $current_page . '&id=' . $id;
1418
1419 return array(
1420 'restore' => array(
1421 'label' => __( 'Restore from Trash', 'formidable' ),
1422 'short' => __( 'Restore', 'formidable' ),
1423 'url' => wp_nonce_url( $base_url . '&frm_action=untrash', 'untrash_form_' . absint( $id ) ),
1424 ),
1425 'trash' => array(
1426 'label' => __( 'Move Form to Trash', 'formidable' ),
1427 'short' => __( 'Trash', 'formidable' ),
1428 'url' => wp_nonce_url( $base_url . '&frm_action=trash', 'trash_form_' . absint( $id ) ),
1429 'icon' => 'frmfont frm_delete_icon',
1430 'data' => array(
1431 'frmverify' => __( 'Do you want to move this form to the trash?', 'formidable' ),
1432 'frmverify-btn' => 'frm-button-red',
1433 ),
1434 ),
1435 'delete' => array(
1436 'label' => __( 'Delete Permanently', 'formidable' ),
1437 'short' => __( 'Delete', 'formidable' ),
1438 'url' => wp_nonce_url( $base_url . '&frm_action=destroy', 'destroy_form_' . absint( $id ) ),
1439 'confirm' => __( 'Are you sure you want to delete this form and all its entries?', 'formidable' ),
1440 'icon' => 'frmfont frm_delete_icon',
1441 'data' => array(
1442 'frmverify' => __( 'This will permanently delete the form and all its entries. This is irreversible. Are you sure you want to continue?', 'formidable' ),
1443 'frmverify-btn' => 'frm-button-red',
1444 ),
1445 ),
1446 );
1447 }
1448
1449 /**
1450 * @since 3.0
1451 *
1452 * @return array
1453 */
1454 public static function css_classes() {
1455 $classes = array(
1456 'frm_total' => array(
1457 'label' => __( 'Total', 'formidable' ),
1458 'title' => __( 'Add this to a read-only field to display the text in bold without a border or background.', 'formidable' ),
1459 ),
1460 'frm_total_big' => array(
1461 'label' => __( 'Big Total', 'formidable' ),
1462 'title' => __( 'Add this to a read-only field to display the text in large, bold text without a border or background.', 'formidable' ),
1463 ),
1464 'frm_scroll_box' => array(
1465 'label' => __( 'Scroll Box', 'formidable' ),
1466 'title' => __( 'If you have many checkbox or radio button options, you may add this class to allow your user to easily scroll through the options. Or add a scrolling area around content in an HTML field.', 'formidable' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
1467 ),
1468 'frm_first' => array(
1469 'label' => __( 'First', 'formidable' ),
1470 'title' => __( 'Add this to the first field in each row along with a width. ie frm_first frm4', 'formidable' ),
1471 ),
1472 'frm_alignright' => __( 'Right', 'formidable' ),
1473 'frm_grid_first' => __( 'First Grid Row', 'formidable' ),
1474 'frm_grid' => __( 'Even Grid Row', 'formidable' ),
1475 'frm_grid_odd' => __( 'Odd Grid Row', 'formidable' ),
1476 'frm_color_block' => array(
1477 'label' => __( 'Color Block', 'formidable' ),
1478 'title' => __( 'Add a background color to the field or section.', 'formidable' ),
1479 ),
1480 'frm_capitalize' => array(
1481 'label' => __( 'Capitalize', 'formidable' ),
1482 'title' => __( 'Automatically capitalize the first letter in each word.', 'formidable' ),
1483 ),
1484 );
1485
1486 return apply_filters( 'frm_layout_classes', $classes );
1487 }
1488
1489 /**
1490 * @return array
1491 */
1492 public static function grid_classes() {
1493 return array(
1494 'frm_half' => '1/2',
1495 'frm_third' => '1/3',
1496 'frm_two_thirds' => '2/3',
1497 'frm_fourth' => '1/4',
1498 'frm_three_fourths' => '3/4',
1499 'frm_sixth' => '1/6',
1500 'frm10' => '5/6',
1501 'frm12' => '100%',
1502 );
1503 }
1504
1505 /**
1506 * @since 3.0
1507 *
1508 * @param mixed $style
1509 * @param string $class
1510 *
1511 * @return string
1512 */
1513 public static function style_class_label( $style, $class ) {
1514 $label = '';
1515
1516 if ( ! $style ) {
1517 $label = $class;
1518 } elseif ( ! is_array( $style ) ) {
1519 $label = $style;
1520 } elseif ( isset( $style['label'] ) ) {
1521 $label = $style['label'];
1522 }
1523
1524 return $label;
1525 }
1526
1527 /**
1528 * @param string $status
1529 *
1530 * @return string
1531 */
1532 public static function status_nice_name( $status ) {
1533 $nice_names = array(
1534 'draft' => __( 'Draft', 'formidable' ),
1535 'trash' => __( 'Trash', 'formidable' ),
1536 'publish' => __( 'Published', 'formidable' ),
1537 );
1538
1539 if ( ! array_key_exists( $status, $nice_names ) ) {
1540 $status = 'publish';
1541 }
1542
1543 return $nice_names[ $status ];
1544 }
1545
1546 /**
1547 * Renders a template icon based on the given categories.
1548 *
1549 * @param array $categories The categories to render the icon for.
1550 * @param array $atts {
1551 * Optional. An array of attributes for rendering.
1552 *
1553 * @type string $html 'span' or 'div'. Default 'span'.
1554 * @type bool $bg Whether to add a background color or not. Default false.
1555 * }
1556 *
1557 * @return void
1558 */
1559 public static function template_icon( $categories, $atts = array() ) {
1560 // Define defaults.
1561 $defaults = array(
1562 'bg' => true,
1563 );
1564 $atts = array_merge( $defaults, $atts );
1565
1566 // Filter out ignored categories.
1567 $ignore = self::get_license_types();
1568 $categories = array_diff( $categories, $ignore );
1569
1570 // Define icons mapping.
1571 $icons = array(
1572 'WooCommerce' => array( 'woocommerce', 'var(--purple)' ),
1573 'Post' => array( 'wordpress', 'rgb(0,160,210)' ),
1574 'User Registration' => array( 'register', 'var(--pink)' ),
1575 'Registration and Signup' => array( 'register', 'var(--pink)' ),
1576 'PayPal' => array( 'paypal' ),
1577 'Stripe' => array( 'credit_card', 'var(--green)' ),
1578 'Twilio' => array( 'sms' ),
1579 'Payment' => array( 'credit_card' ),
1580 'Order Form' => array( 'product' ),
1581 'Finance' => array( 'total' ),
1582 'Health and Wellness' => array( 'heart', 'var(--pink)' ),
1583 'Event Planning' => array( 'calendar', 'var(--orange)' ),
1584 'Real Estate' => array( 'house' ),
1585 'Nonprofit' => array( 'heart_solid' ),
1586 'Calculator' => array( 'calculator', 'var(--purple)' ),
1587 'Quiz' => array( 'percent' ),
1588 'Registrations' => array( 'address_card' ),
1589 'Customer Service' => array( 'users_solid' ),
1590 'Education' => array( 'pencil' ),
1591 'Marketing' => array( 'eye' ),
1592 'Feedback' => array( 'smile' ),
1593 'Business Operations' => array( 'case' ),
1594 'Contact Form' => array( 'email' ),
1595 'Conversational Forms' => array( 'chat_forms' ),
1596 'Survey' => array( 'chat_forms', 'var(--orange)' ),
1597 'Application' => array( 'align_right' ),
1598 'Signature' => array( 'signature' ),
1599 '' => array( 'align_right' ),
1600 );
1601
1602 // Determine the icon to be used.
1603 $icon = $icons[''];
1604
1605 if ( count( $categories ) === 1 ) {
1606 $category = reset( $categories );
1607 $icon = $icons[ $category ] ?? $icon;
1608 } elseif ( $categories ) {
1609 $icons = array_intersect_key( $icons, array_flip( $categories ) );
1610 $icon = reset( $icons );
1611 }
1612
1613 // Prepare variables for output.
1614 $icon_name = $icon[0];
1615 $bg_color = $icon[1] ?? '';
1616
1617 // Render the icon.
1618 echo '<span class="frm-category-icon frm-icon-wrapper"';
1619
1620 if ( $bg_color && $atts['bg'] ) {
1621 echo ' style="background-color:' . esc_attr( $bg_color ) . '"';
1622 }
1623
1624 echo '>';
1625 FrmAppHelper::icon_by_class( 'frmfont frm_' . $icon_name . '_icon' );
1626 echo '</span>';
1627 }
1628
1629 /**
1630 * Get template install link.
1631 *
1632 * @since 4.02
1633 *
1634 * @param array $template Template details.
1635 * @param array $args Additional arguments.
1636 *
1637 * @return array The link attributes.
1638 */
1639 public static function get_template_install_link( $template, $args ) {
1640 $defaults = array(
1641 'class' => 'install-now',
1642 'href' => 'href',
1643 'atts' => true,
1644 );
1645
1646 if ( ! empty( $template['url'] ) ) {
1647 $link = array(
1648 'url' => $template['url'],
1649 'label' => __( 'Create Form', 'formidable' ),
1650 'class' => 'frm-install-template',
1651 'href' => 'rel',
1652 'atts' => '',
1653 );
1654 } else {
1655 $link = array(
1656 'url' => $args['pricing'],
1657 'label' => __( 'Upgrade', 'formidable' ),
1658 );
1659 }
1660
1661 return array_merge( $defaults, $link );
1662 }
1663
1664 /**
1665 * Is the template included with the license type?
1666 *
1667 * @since 4.02.02
1668 *
1669 * @param array $args
1670 *
1671 * @return bool
1672 */
1673 public static function plan_is_allowed( $args ) {
1674 if ( empty( $args['license_type'] ) ) {
1675 return false;
1676 }
1677
1678 $plans = array( 'free', 'personal', 'business', 'elite' );
1679 $license_type = strtolower( $args['license_type'] );
1680 $plan_required = strtolower( $args['plan_required'] );
1681 $included = $license_type === $plan_required;
1682
1683 if ( $included || ! in_array( $plan_required, $plans, true ) ) {
1684 return $included;
1685 }
1686
1687 foreach ( $plans as $plan ) {
1688 if ( $included || $plan === $license_type ) {
1689 break;
1690 }
1691
1692 $included = $plan === $plan_required;
1693 }
1694
1695 return $included;
1696 }
1697
1698 /**
1699 * If a template or add-on cannot be installed, show a message
1700 * about which plan is required.
1701 *
1702 * @since 4.0
1703 *
1704 * @param string $requires
1705 * @param string $link
1706 *
1707 * @return void
1708 */
1709 public static function show_plan_required( $requires, $link ) {
1710 if ( ! $requires ) {
1711 return;
1712 }
1713
1714 // phpcs:disable Generic.WhiteSpace.ScopeIndent
1715 ?>
1716 <p class="frm_plan_required">
1717 <?php esc_html_e( 'Plan required:', 'formidable' ); ?>
1718 <a href="<?php echo esc_url( $link ); ?>" target="_blank" rel="noopener">
1719 <?php echo esc_html( $requires ); ?>
1720 </a>
1721 </p>
1722 <?php
1723 // phpcs:enable Generic.WhiteSpace.ScopeIndent
1724 }
1725
1726 /**
1727 * @since 4.0
1728 *
1729 * @param array $item
1730 *
1731 * @return false|string
1732 */
1733 public static function get_plan_required( &$item ) {
1734 if ( ! isset( $item['categories'] ) || ! is_array( $item['categories'] ) || ! empty( $item['url'] ) ) {
1735 return false;
1736 }
1737
1738 $plans = self::get_license_types();
1739
1740 foreach ( $item['categories'] as $k => $category ) {
1741 if ( in_array( $category, $plans, true ) ) {
1742 unset( $item['categories'][ $k ] );
1743 return self::convert_legacy_package_names( $category );
1744 }
1745 }
1746
1747 return false;
1748 }
1749
1750 /**
1751 * Converts legacy package names to the current standard package name.
1752 *
1753 * @since 6.15
1754 *
1755 * @param string $package_name
1756 *
1757 * @return string The updated package name.
1758 */
1759 public static function convert_legacy_package_names( $package_name ) {
1760 if ( in_array( $package_name, array( 'Creator', 'Personal' ), true ) ) {
1761 return 'Plus';
1762 }
1763
1764 return $package_name;
1765 }
1766
1767 /**
1768 * Get the license types.
1769 *
1770 * @since 6.15
1771 *
1772 * @param array $args
1773 *
1774 * @return array
1775 */
1776 public static function get_license_types( $args = array() ) {
1777 $defaults = array(
1778 'include_all' => true,
1779 'case_lower' => false,
1780 );
1781 $args = wp_parse_args( $args, $defaults );
1782 $license_types = array( 'Basic', 'Plus', 'Business', 'Elite' );
1783
1784 if ( $args['include_all'] ) {
1785 $license_types = array_merge( array( 'free', 'Personal', 'Creator' ), $license_types );
1786 }
1787
1788 if ( $args['case_lower'] ) {
1789 return array_map( 'strtolower', $license_types );
1790 }
1791
1792 return $license_types;
1793 }
1794
1795 /**
1796 * Checks for warnings to be displayed after form settings are saved.
1797 *
1798 * @since 4.04
1799 *
1800 * @param array $values The $_POST array, which contains values submitted in a form.
1801 *
1802 * @return array An array of warnings or an empty array.
1803 */
1804 public static function check_for_warnings( $values ) {
1805 $warnings = array();
1806 $redirect_warning = self::check_redirect_url_for_unsafe_params( $values );
1807
1808 if ( $redirect_warning ) {
1809 $warnings[] = $redirect_warning;
1810 }
1811
1812 return apply_filters( 'frm_check_for_warnings', $warnings, $values );
1813 }
1814
1815 /**
1816 * Checks the redirect URL for params whose names are reserved words.
1817 *
1818 * @since 4.04
1819 *
1820 * @param array $values The $_POST array, which contains the values submitted in a form.
1821 *
1822 * @return bool|string A warning message about unsafe params or false.
1823 */
1824 private static function check_redirect_url_for_unsafe_params( $values ) {
1825 if ( ! isset( $values['options'] ) ) {
1826 return false;
1827 }
1828
1829 $options = $values['options'];
1830 FrmAppHelper::sanitize_with_html( $options );
1831
1832 if ( ! isset( $options['success_action'] ) || $options['success_action'] !== 'redirect' || ! isset( $options['success_url'] ) ) {
1833 return false;
1834 }
1835
1836 $unsafe_params_in_redirect = self::get_unsafe_params( $options['success_url'] );
1837
1838 return self::create_unsafe_param_warning( $unsafe_params_in_redirect );
1839 }
1840
1841 /**
1842 * Returns an array of params whose names are reserved words in the specified URL.
1843 *
1844 * @since 4.04
1845 *
1846 * @param string $url The URL whose params are being checked.
1847 *
1848 * @return array An array of params whose names are reserved words or an empty array.
1849 */
1850 private static function get_unsafe_params( $url ) {
1851 $redirect_components = parse_url( $url );
1852
1853 if ( empty( $redirect_components['query'] ) ) {
1854 return array();
1855 }
1856
1857 parse_str( $redirect_components['query'], $redirect_params );
1858 $redirect_param_names = array_keys( $redirect_params );
1859 $unsafe_params_in_redirect = array_intersect( $redirect_param_names, self::reserved_words() );
1860
1861 return array_values( $unsafe_params_in_redirect );
1862 }
1863
1864 /**
1865 * Returns a warning if reserved words have been used as param names in the redirect URL.
1866 *
1867 * @since 4.04
1868 *
1869 * @param array $unsafe_params_in_redirect Array of params from the redirect URL whose names are reserved words.
1870 *
1871 * @return bool|string A string with an unsafe param message or false.
1872 */
1873 private static function create_unsafe_param_warning( $unsafe_params_in_redirect ) {
1874 $count = count( $unsafe_params_in_redirect );
1875
1876 if ( $count === 0 ) {
1877 return false;
1878 }
1879
1880 $caution = esc_html__( 'Is this intentional?', 'formidable' );
1881 $reserved_words_intro = esc_html__( 'See the list of reserved words in WordPress.', 'formidable' );
1882 $reserved_words_link = '<a href="https://codex.wordpress.org/WordPress_Query_Vars" target="_blank"> ' . $reserved_words_intro . '</a>';
1883
1884 if ( $count === 1 ) {
1885 /* translators: %s: the name of a single parameter in the redirect URL */
1886 return sprintf( esc_html__( 'The redirect URL is using the parameter "%s", which is reserved by WordPress. ', 'formidable' ), $unsafe_params_in_redirect[0] ) . $caution . $reserved_words_link; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
1887 }
1888
1889 $unsafe_params_string = implode( '", "', $unsafe_params_in_redirect );
1890
1891 /* translators: %s: the names of two or more parameters in the redirect URL, separated by commas */
1892 return sprintf( esc_html__( 'The redirect URL is using the parameters "%s", which are reserved by WordPress. ', 'formidable' ), $unsafe_params_string ) . $caution . $reserved_words_link; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
1893 }
1894
1895 /**
1896 * Returns an array of common reserved words in WordPress.
1897 *
1898 * An edited list of reserved terms from the Codex.
1899 * https://codex.wordpress.org/Reserved_Terms
1900 *
1901 * @since 4.04
1902 *
1903 * @return array Array of WordPress reserved words.
1904 */
1905 public static function reserved_words() {
1906 return array(
1907 'id',
1908 'attachment',
1909 'author',
1910 'author_name',
1911 'calendar',
1912 'cat',
1913 'category',
1914 'category_name',
1915 'cpage',
1916 'custom',
1917 'day',
1918 'date',
1919 'error',
1920 'feed',
1921 'hour',
1922 'm',
1923 'minute',
1924 'more',
1925 'name',
1926 'order',
1927 'p',
1928 'page',
1929 'page_id',
1930 'paged',
1931 'pb',
1932 'post',
1933 'posts',
1934 'preview',
1935 's',
1936 'search',
1937 'second',
1938 'sentence',
1939 'tag',
1940 'taxonomy',
1941 'tb',
1942 'term',
1943 'terms',
1944 'theme',
1945 'title',
1946 'type',
1947 'w',
1948 'year',
1949 );
1950 }
1951
1952 /**
1953 * Make sure the field shortcodes in a url always add the sanitize_url=1 option if nothing is defined.
1954 * This is to prevent some field characters like ', @, and | from being stripped from the redirect URL.
1955 *
1956 * @since 5.0.16
1957 *
1958 * @param string $url
1959 * @param int $form_id
1960 *
1961 * @return string
1962 */
1963 public static function maybe_add_sanitize_url_attr( $url, $form_id ) {
1964 if ( ! str_contains( $url, '[' ) ) {
1965 // Do nothing if no shortcodes are detected.
1966 return $url;
1967 }
1968
1969 $parsed = wp_parse_url( $url );
1970
1971 if ( empty( $parsed['query'] ) ) {
1972 // Do nothing if no query can be detected in the url string.
1973 return $url;
1974 }
1975
1976 $original_query = $parsed['query'];
1977 $query = $parsed['query'];
1978 $shortcodes = FrmFieldsHelper::get_shortcodes( $query, $form_id );
1979
1980 if ( empty( $shortcodes[0] ) ) {
1981 // No shortcodes found, do nothing.
1982 return $url;
1983 }
1984
1985 foreach ( $shortcodes[0] as $key => $shortcode ) {
1986 $options = trim( $shortcodes[3][ $key ] );
1987
1988 if ( in_array( $shortcodes[1][ $key ], array( 'if ' ), true ) ) {
1989 // Skip if shortcodes.
1990 continue;
1991 }
1992
1993 if ( str_contains( $options, 'sanitize_url=' ) || str_contains( $options, 'sanitize=' ) ) {
1994 // A sanitize option is already set so leave it alone.
1995 continue;
1996 }
1997
1998 $new_shortcode = '[' . $shortcodes[2][ $key ];
1999
2000 if ( $options ) {
2001 $new_shortcode .= ' ' . $options;
2002 }
2003
2004 $new_shortcode .= ' sanitize_url=1]';
2005 $query = str_replace( $shortcode, $new_shortcode, $query );
2006 }//end foreach
2007
2008 if ( $query === $original_query ) {
2009 return $url;
2010 }
2011
2012 return str_replace( $original_query, $query, $url );
2013 }
2014
2015 /**
2016 * Outputs the appropriate button text in the publish box.
2017 *
2018 * @return void
2019 */
2020 public static function publish_box_button_text() {
2021 $is_new_template = FrmAppHelper::simple_get( 'new_template' );
2022 $action = FrmAppHelper::simple_get( 'frm_action' );
2023
2024 if ( ( 'edit' === $action || 'settings' === $action ) && $is_new_template ) {
2025 esc_html_e( 'Save', 'formidable' );
2026 } else {
2027 esc_html_e( 'Update', 'formidable' );
2028 }
2029 }
2030
2031 /**
2032 * Strip characters similar to the WordPress sanitize_html_class function, but allow for [ and ].
2033 * This allows shortcodes inside of the layout classes setting.
2034 *
2035 * @since 6.16
2036 *
2037 * @param string $classname
2038 *
2039 * @return string
2040 */
2041 public static function sanitize_layout_class( $classname ) {
2042 // Strip out any percent-encoded characters.
2043 $sanitized = preg_replace( '|%[a-fA-F0-9][a-fA-F0-9]|', '', $classname );
2044
2045 // Limit to A-Z, a-z, 0-9, '_', '-', '[', ']'.
2046 return preg_replace( '/[^A-Za-z0-9_\-\[\]]/', '', $sanitized );
2047 }
2048
2049 /**
2050 * Returns true if the preview should be blocked.
2051 *
2052 * @since 6.20
2053 *
2054 * @param string $form_key
2055 *
2056 * @return bool
2057 */
2058 public static function should_block_preview( $form_key ) {
2059 $should_block = in_array( $form_key, array( 'contact-form', 'contact-us' ), true ) && ! current_user_can( 'frm_view_forms' );
2060 /**
2061 * Filters whether the form preview should be blocked.
2062 *
2063 * @since 6.20
2064 *
2065 * @param bool $should_block
2066 * @param string $form_key
2067 */
2068 return (bool) apply_filters( 'frm_block_preview', $should_block, $form_key );
2069 }
2070
2071 /**
2072 * Checks if the form is loaded by API.
2073 *
2074 * @since 6.21
2075 *
2076 * @return bool
2077 */
2078 public static function form_is_loaded_by_api() {
2079 global $frm_vars;
2080
2081 if ( ! empty( $frm_vars['inplace_edit'] ) ) {
2082 return true;
2083 }
2084
2085 return self::is_formidable_api_form() || self::is_block_or_page_builder_preview();
2086 }
2087
2088 /**
2089 * Checks if the form is rendered inside a block editor or page builder preview.
2090 *
2091 * @since 6.29
2092 *
2093 * @return bool
2094 */
2095 public static function is_block_or_page_builder_preview() {
2096 return self::is_gutenberg_editor() || self::is_elementor_ajax() || self::is_visual_views_preview();
2097 }
2098
2099 /**
2100 * @since 6.21
2101 *
2102 * @return bool
2103 */
2104 private static function is_visual_views_preview() {
2105 return 'frm_views_process_box_preview' === FrmAppHelper::get_post_param( 'action' );
2106 }
2107
2108 /**
2109 * @since 6.21
2110 *
2111 * @return bool
2112 */
2113 private static function is_elementor_ajax() {
2114 return 'elementor_ajax' === FrmAppHelper::get_post_param( 'action' );
2115 }
2116
2117 /**
2118 * @since 6.21
2119 *
2120 * @return bool
2121 */
2122 private static function is_gutenberg_editor() {
2123 $url = FrmAppHelper::get_server_value( 'REQUEST_URI' );
2124
2125 if ( str_contains( $url, '/wp-json/wp/v2/block-renderer/formidable/simple-form' ) ) {
2126 return true;
2127 }
2128
2129 if ( str_contains( urldecode( $url ), 'rest_route=/wp/v2/block-renderer/formidable/' ) ) {
2130 return true;
2131 }
2132
2133 global $pagenow;
2134 return 'post.php' === $pagenow;
2135 }
2136
2137 /**
2138 * @since 6.21
2139 *
2140 * @return bool
2141 */
2142 private static function is_formidable_api_form() {
2143 if ( ! class_exists( 'FrmAPIAppController' ) ) {
2144 return false;
2145 }
2146
2147 $url = FrmAppHelper::get_server_value( 'REQUEST_URI' );
2148
2149 if ( str_contains( $url, '/wp-json/frm/v2/forms/' ) ) {
2150 // Prevent the honeypot from appearing for an API loaded form.
2151 // This is to prevent conflicts where the script is not working.
2152 return true;
2153 }
2154
2155 if ( is_callable( 'FrmProFormState::get_from_request' ) ) {
2156 $api = FrmProFormState::get_from_request( 'a', 0 );
2157
2158 if ( $api ) {
2159 return true;
2160 }
2161 }
2162
2163 return false;
2164 }
2165
2166 /**
2167 * @since 6.30
2168 *
2169 * @return void
2170 */
2171 public static function load_currency_js() {
2172 global $frm_vars;
2173
2174 if ( empty( $frm_vars['currency'] ) ) {
2175 return;
2176 }
2177
2178 echo '<script>';
2179 echo 'var frmcurrency=' . json_encode( $frm_vars['currency'] ) . ";\n";
2180 echo 'if(typeof __FRMCURR == "undefined"){__FRMCURR=frmcurrency;}';
2181 echo 'else{__FRMCURR=jQuery.extend(true,{},__FRMCURR,frmcurrency);}';
2182 echo '</script>';
2183 }
2184
2185 /**
2186 * Returns the form name or the no title text if the form name is empty.
2187 *
2188 * @since 6.30
2189 *
2190 * @param array|stdClass $form The form data.
2191 * @param int $length The form name length to truncate to.
2192 *
2193 * @return string
2194 */
2195 public static function get_form_name( $form, $length = 0 ) {
2196 $form_name = is_object( $form ) ? $form->name : $form['name'];
2197
2198 if ( '' === $form_name || null === $form_name ) {
2199 return self::get_no_title_text();
2200 }
2201
2202 if ( ! $length ) {
2203 return $form_name;
2204 }
2205
2206 return FrmAppHelper::truncate( $form_name, $length );
2207 }
2208 }
2209