PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.22.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.22.1
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
← All changes | classes/helpers/FrmFieldsHelper.php +466 -204 6.36.22.1 View file →
@@ -4,8 +4,15 @@
4 4 }
5 5
6 6 class FrmFieldsHelper {
7 7
8 + /**
9 + * The context is memoized for re-use as the context is checked for each field.
10 + *
11 + * @var bool|null
12 + */
13 + private static $context_is_safe_to_load_field_options_from_request_data;
14 +
8 15 public static function setup_new_vars( $type = '', $form_id = '' ) {
9 16
10 17 if ( strpos( $type, '|' ) ) {
11 18 list( $type, $setting ) = explode( '|', $type );
@@ -13,9 +20,14 @@
13 20
14 21 $values = self::get_default_field( $type );
15 22
16 23 global $wpdb;
17 - $field_count = FrmDb::get_var( 'frm_fields', array( 'form_id' => $form_id ), 'field_order', array( 'order_by' => 'field_order DESC' ) );
24 + $field_count = FrmDb::get_var(
25 + 'frm_fields',
26 + array( 'form_id' => $form_id ),
27 + 'field_order',
28 + array( 'order_by' => 'field_order DESC' )
29 + );
18 30
19 31 $values['field_key'] = FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_fields', 'field_key' );
20 32 $values['form_id'] = $form_id;
21 33 $values['field_order'] = $field_count + 1;
@@ -21,10 +33,10 @@
21 33 $values['field_order'] = $field_count + 1;
22 34
23 35 $values['field_options']['custom_html'] = self::get_default_html( $type );
24 36
25 - if ( isset( $setting ) && ! empty( $setting ) ) {
26 - if ( in_array( $type, array( 'data', 'lookup' ) ) ) {
37 + if ( ! empty( $setting ) ) {
38 + if ( in_array( $type, array( 'data', 'lookup' ), true ) ) {
27 39 $values['field_options']['data_type'] = $setting;
28 40 } else {
29 41 $values['field_options'][ $setting ] = 1;
30 42 }
@@ -29,8 +41,19 @@
29 41 $values['field_options'][ $setting ] = 1;
30 42 }
31 43 }
32 44
45 + // Increase the field order of submit field and fields in the same row.
46 + $last_row_field_ids = FrmAppHelper::get_post_param( 'last_row_field_ids', array() );
47 + if ( $last_row_field_ids ) {
48 + foreach ( $last_row_field_ids as $index => $last_row_field_id ) {
49 + FrmField::update(
50 + $last_row_field_id,
51 + array( 'field_order' => $field_count + $index + 2 )
52 + );
53 + }
54 + }
55 +
33 56 return $values;
34 57 }
35 58
36 59 public static function get_html_id( $field, $plus = '' ) {
@@ -47,9 +70,9 @@
47 70 $values = (array) $field;
48 71
49 72 self::fill_field_array( $field, $values );
50 73
51 - $values['custom_html'] = ( isset( $field->field_options['custom_html'] ) ) ? $field->field_options['custom_html'] : self::get_default_html( $field->type );
74 + $values['custom_html'] = isset( $field->field_options['custom_html'] ) ? $field->field_options['custom_html'] : self::get_default_html( $field->type );
52 75
53 76 return $values;
54 77 }
55 78
@@ -86,8 +109,13 @@
86 109 /**
87 110 * Prepare field while creating a new entry
88 111 *
89 112 * @since 3.0
113 + *
114 + * @param array $field_array
115 + * @param stdClass $field
116 + * @param array $args
117 + * @return void
90 118 */
91 119 private static function prepare_front_field( &$field_array, $field, $args ) {
92 120 self::fill_default_field_opts( $field, $field_array );
93 121 self::fill_cleared_strings( $field, $field_array );
@@ -96,11 +124,22 @@
96 124 $field_array['original_type'] = isset( $field->field_options['original_type'] ) ? $field->field_options['original_type'] : $field->type;
97 125
98 126 self::prepare_field_options_for_display( $field_array, $field, $args );
99 127
100 - if ( $args['action'] == 'edit' ) {
128 + if ( $args['action'] === 'edit' ) {
129 + /**
130 + * @param array $field_array
131 + * @param stdClass $field
132 + * @param int|string $entry_id
133 + * @param array $args
134 + */
101 135 $field_array = apply_filters( 'frm_setup_edit_fields_vars', $field_array, $field, $args['entry_id'], $args );
102 136 } else {
137 + /**
138 + * @param array $field_array
139 + * @param stdClass $field
140 + * @param array $args
141 + */
103 142 $field_array = apply_filters( 'frm_setup_new_fields_vars', $field_array, $field, $args );
104 143 }
105 144 }
106 145
@@ -120,14 +159,14 @@
120 159 /**
121 160 * @since 3.0
122 161 *
123 162 * @param object $field
124 - * @param array $values
163 + * @param array $values
125 164 */
126 165 private static function fill_default_field_opts( $field, array &$values ) {
127 - $check_post = FrmAppHelper::is_admin_page() && $_POST && isset( $_POST['field_options'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
166 + $check_post = self::context_is_safe_to_load_field_options_from_request_data();
167 + $defaults = self::get_default_field_options_from_field( $field, $values );
128 168
129 - $defaults = self::get_default_field_options_from_field( $field, $values );
130 169 if ( ! $check_post ) {
131 170 $defaults['required_indicator'] = '';
132 171 $defaults['original_type'] = $field->type;
133 172 }
@@ -137,11 +176,58 @@
137 176
138 177 if ( $check_post ) {
139 178 self::get_posted_field_setting( $opt . '_' . $field->id, $values[ $opt ] );
140 179 }
180 + }
181 + }
141 182
142 - unset( $opt, $default );
183 + /**
184 + * The fill_default_field_opts method is called when loading a field.
185 + * This is used to preserve the $_POST data after updating settings for a field.
186 + * To prevent this from happening when creating an entry, we need to check the context.
187 + *
188 + * @return bool
189 + */
190 + private static function context_is_safe_to_load_field_options_from_request_data() {
191 + if ( isset( self::$context_is_safe_to_load_field_options_from_request_data ) ) {
192 + return self::$context_is_safe_to_load_field_options_from_request_data;
143 193 }
194 +
195 + $function = function () {
196 + if ( ! FrmAppHelper::is_admin_page() ) {
197 + return false;
198 + }
199 +
200 + if ( ! $_POST || ! isset( $_POST['field_options'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
201 + return false;
202 + }
203 +
204 + if ( ! current_user_can( 'frm_edit_forms' ) ) {
205 + return false;
206 + }
207 +
208 + $action = FrmAppHelper::get_post_param( 'action', '', 'sanitize_title' );
209 + if ( 'frm_forms_preview' === $action ) {
210 + // Never trigger when previewing.
211 + return false;
212 + }
213 +
214 + // Confirm an allowed action is being used, and that the correct nonce is being used.
215 + if ( 'update' === $action ) {
216 + $nonce = FrmAppHelper::get_post_param( 'frm_save_form', '', 'sanitize_text_field' );
217 + return wp_verify_nonce( $nonce, 'frm_save_form_nonce' );
218 + }
219 +
220 + $action = FrmAppHelper::get_post_param( 'frm_action', '', 'sanitize_title' );
221 + if ( 'update_settings' === $action ) {
222 + $nonce = FrmAppHelper::get_post_param( 'process_form', '', 'sanitize_text_field' );
223 + return wp_verify_nonce( $nonce, 'process_form_nonce' );
224 + }
225 + };
226 +
227 + self::$context_is_safe_to_load_field_options_from_request_data = $function();
228 +
229 + return self::$context_is_safe_to_load_field_options_from_request_data;
144 230 }
145 231
146 232 /**
147 233 * Fill the required message, invalid message,
@@ -149,23 +235,21 @@
149 235 *
150 236 * @since 3.0
151 237 *
152 238 * @param object $field
153 - * @param array $field_array
239 + * @param array $field_array
154 240 */
155 241 private static function fill_cleared_strings( $field, array &$field_array ) {
156 - $frm_settings = FrmAppHelper::get_settings();
157 -
158 242 if ( '' == $field_array['blank'] && '1' === $field_array['required'] ) {
159 - $field_array['blank'] = $frm_settings->blank_msg;
243 + $field_array['blank'] = self::default_blank_msg();
160 244 }
161 245
162 246 if ( '' === $field_array['invalid'] ) {
163 247 if ( 'captcha' === $field->type ) {
248 + $frm_settings = FrmAppHelper::get_settings();
164 249 $field_array['invalid'] = $frm_settings->re_msg;
165 250 } else {
166 - /* translators: %s: Field name */
167 - $field_array['invalid'] = sprintf( __( '%s is invalid', 'formidable' ), $field_array['name'] );
251 + $field_array['invalid'] = self::default_invalid_msg();
168 252 }
169 253 }
170 254
171 255 if ( '' == $field_array['custom_html'] ) {
@@ -173,12 +257,48 @@
173 257 }
174 258 }
175 259
176 260 /**
261 + * @since 6.8.3
262 + *
263 + * @return string
264 + */
265 + public static function default_invalid_msg() {
266 + /* translators: %s: [field_name] shortcode (Which gets replaced by a Field Name) */
267 + return sprintf( __( '%s is invalid', 'formidable' ), '[field_name]' );
268 + }
269 +
270 + /**
271 + * @since 6.8.3
272 + *
273 + * @return string
274 + */
275 + public static function default_unique_msg() {
276 + $frm_settings = FrmAppHelper::get_settings();
277 + $unique_message = $frm_settings->unique_msg;
278 + $unique_message = str_replace( 'This value', '[field_name]', $unique_message );
279 + return $unique_message;
280 + }
281 +
282 + /**
283 + * @since 6.8.3
284 + *
285 + * @return string
286 + */
287 + public static function default_blank_msg() {
288 + $frm_settings = FrmAppHelper::get_settings();
289 + $blank_message = $frm_settings->blank_msg;
290 + $blank_message = str_replace( 'This field', '[field_name]', $blank_message );
291 + return $blank_message;
292 + }
293 +
294 + /**
295 + * When loading settings for a field, check the $_POST data and possibly use that instead of the DB value.
296 + *
177 297 * @since 3.0
178 298 *
179 299 * @param string $setting
180 - * @param mixed $value
300 + * @param mixed $value
181 301 */
182 302 private static function get_posted_field_setting( $setting, &$value ) {
183 303 if ( ! isset( $_POST['field_options'][ $setting ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
184 304 return;
@@ -184,10 +304,14 @@
184 304 return;
185 305 }
186 306
187 307 if ( strpos( $setting, 'html' ) !== false ) {
188 - // Strip slashes from HTML but not regex or script tags.
189 308 $value = wp_unslash( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
309 +
310 + // Conditionally strip script tags if the user sending $_POST data is not allowed to use unfiltered HTML.
311 + if ( ! FrmAppHelper::allow_unfiltered_html() ) {
312 + $value = FrmAppHelper::kses( $value, 'all' );
313 + }
190 314 } elseif ( strpos( $setting, 'format_' ) === 0 ) {
191 315 // TODO: Remove stripslashes on output, and use on input only.
192 316 $value = sanitize_text_field( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.NonceVerification.Missing
193 317 } else {
@@ -199,9 +323,9 @@
199 323 /**
200 324 * @since 3.0
201 325 *
202 326 * @param object $field
203 - * @param array $values The field array is needed for hooks
327 + * @param array $values The field array is needed for hooks.
204 328 *
205 329 * @return array
206 330 */
207 331 public static function get_default_field_options_from_field( $field, $values = array() ) {
@@ -218,9 +342,9 @@
218 342 * @since 3.0
219 343 *
220 344 * @param object $field
221 345 *
222 - * @return array
346 + * @return FrmFieldType
223 347 */
224 348 private static function get_original_field( $field ) {
225 349 $original_type = FrmField::get_option( $field, 'original_type' );
226 350 if ( ! empty( $original_type ) && $field->type != $original_type ) {
@@ -232,11 +356,11 @@
232 356
233 357 /**
234 358 * @since 3.0
235 359 *
236 - * @param array $field_array
360 + * @param array $field_array
237 361 * @param object $field
238 - * @param array $atts
362 + * @param array $atts
239 363 */
240 364 private static function prepare_field_options_for_display( &$field_array, $field, $atts ) {
241 365 $field_obj = FrmFieldFactory::get_field_object( $field );
242 366 $field_array = $field_obj->prepare_front_field( $field_array, $atts );
@@ -270,29 +394,27 @@
270 394
271 395 /**
272 396 * @since 2.0
273 397 *
274 - * @param $field
275 - * @param $error
398 + * @param array|object $field
399 + * @param string $error
276 400 *
277 401 * @return string
278 402 */
279 403 public static function get_error_msg( $field, $error ) {
280 - $frm_settings = FrmAppHelper::get_settings();
281 - $default_settings = $frm_settings->default_options();
282 - $field_name = is_array( $field ) ? $field['name'] : $field->name;
404 + $frm_settings = FrmAppHelper::get_settings();
283 405
284 406 $conf_msg = __( 'The entered values do not match', 'formidable' );
285 407 $defaults = array(
286 408 'unique_msg' => array(
287 - 'full' => $default_settings['unique_msg'],
409 + 'full' => self::default_unique_msg(),
288 410 /* translators: %s: Field name */
289 - 'part' => sprintf( __( '%s must be unique', 'formidable' ), $field_name ),
411 + 'part' => sprintf( __( '%s must be unique', 'formidable' ), '[field_name]' ),
290 412 ),
291 413 'invalid' => array(
292 414 'full' => __( 'This field is invalid', 'formidable' ),
293 415 /* translators: %s: Field name */
294 - 'part' => sprintf( __( '%s is invalid', 'formidable' ), $field_name ),
416 + 'part' => sprintf( __( '%s is invalid', 'formidable' ), '[field_name]' ),
295 417 ),
296 418 'blank' => array(
297 419 'full' => $frm_settings->blank_msg,
298 420 'part' => $frm_settings->blank_msg,
@@ -306,11 +428,74 @@
306 428 $msg = FrmField::get_option( $field, $error );
307 429 $msg = empty( $msg ) ? $defaults[ $error ]['part'] : $msg;
308 430 $msg = do_shortcode( $msg );
309 431
432 + $msg = self::maybe_replace_substrings_with_field_name( $msg, $error, $field );
433 +
310 434 return $msg;
311 435 }
312 436
437 + /**
438 + * @since 6.8.3
439 + *
440 + * @param string $msg
441 + * @param string $error
442 + * @param array|object $field
443 + */
444 + private static function maybe_replace_substrings_with_field_name( $msg, $error, $field ) {
445 + $field_name = is_array( $field ) ? $field['name'] : $field->name;
446 + $field_name = FrmAppHelper::maybe_kses( $field_name );
447 + $substrings = self::get_substrings_to_replace_with_field_name( $field_name, compact( 'msg', 'error', 'field' ) );
448 +
449 + // Use the "This value"/"This field" placeholder strings if field name is empty.
450 + if ( ! $field_name ) {
451 + if ( 'unique_msg' === $error ) {
452 + $field_name = __( 'This value', 'formidable' );
453 + } else {
454 + $field_name = __( 'This field', 'formidable' );
455 + }
456 + }
457 +
458 + $msg = str_replace( $substrings, $field_name, $msg );
459 + return $msg;
460 + }
461 +
462 + /**
463 + * @since 6.8.3
464 + *
465 + * @param string $field_name
466 + * @param array $filter_args {
467 + * Filter arguments.
468 + *
469 + * @type string $msg The current error message before the substrings are replaced.
470 + * @type string $error A key including 'unique_msg', 'invalid', 'blank', or 'conf_msg'.
471 + * @type array|object $field The field with the error.
472 + * }
473 + * @return array
474 + */
475 + private static function get_substrings_to_replace_with_field_name( $field_name, $filter_args ) {
476 + $substrings = array( '[field_name]' );
477 + if ( $field_name ) {
478 + array_push( $substrings, 'This value', 'This field' );
479 + }
480 +
481 + /**
482 + * @since 6.8.3
483 + *
484 + * @param array<string> $substrings
485 + * @param array $filter_args
486 + */
487 + $filtered_substrings = apply_filters( 'frm_error_substrings_to_replace_with_field_name', $substrings, $filter_args );
488 +
489 + if ( is_array( $filtered_substrings ) ) {
490 + $substrings = $filtered_substrings;
491 + } else {
492 + _doing_it_wrong( __METHOD__, 'Only arrays should be returned when using the frm_error_substrings_to_replace_with_field_name filter.', '6.8.3' );
493 + }
494 +
495 + return $substrings;
496 + }
497 +
313 498 public static function get_form_fields( $form_id, $error = array() ) {
314 499 $fields = FrmField::get_all_for_form( $form_id );
315 500
316 501 return apply_filters( 'frm_get_paged_fields', $fields, $form_id, $error );
@@ -328,12 +513,12 @@
328 513 return apply_filters( 'frm_custom_html', $default_html, $type );
329 514 }
330 515
331 516 /**
332 - * @param array $fields
333 - * @param array $errors
517 + * @param array $fields
518 + * @param array $errors
334 519 * @param object $form
335 - * @param $form_action
520 + * @param object $form_action
336 521 */
337 522 public static function show_fields( $fields, $errors, $form, $form_action ) {
338 523 foreach ( $fields as $field ) {
339 524 $field_obj = FrmFieldFactory::get_field_type( $field['type'], $field );
@@ -343,10 +528,10 @@
343 528
344 529 /**
345 530 * @since 3.0
346 531 *
347 - * @param array $atts
348 - * @param string|array $value
532 + * @param array $atts
533 + * @param array|string $value
349 534 */
350 535 public static function run_wpautop( $atts, &$value ) {
351 536 $autop = isset( $atts['wpautop'] ) ? $atts['wpautop'] : true;
352 537 if ( apply_filters( 'frm_use_wpautop', $autop ) ) {
@@ -363,9 +548,9 @@
363 548 * @since 2.05
364 549 */
365 550 public static function &label_position( $position, $field, $form ) {
366 551 if ( $position && $position != '' ) {
367 - if ( $position == 'inside' && ! self::is_placeholder_field_type( $field['type'] ) ) {
552 + if ( $position === 'inside' && ! self::is_placeholder_field_type( $field['type'] ) ) {
368 553 $position = 'top';
369 554 }
370 555
371 556 return $position;
@@ -371,18 +556,18 @@
371 556 return $position;
372 557 }
373 558
374 559 $position = FrmStylesController::get_style_val( 'position', $form );
375 - if ( $position == 'none' ) {
560 + if ( $position === 'none' ) {
376 561 $position = 'top';
377 - } elseif ( $position == 'no_label' ) {
562 + } elseif ( $position === 'no_label' ) {
378 563 $position = 'none';
379 - } elseif ( $position == 'inside' && ! self::is_placeholder_field_type( $field['type'] ) ) {
564 + } elseif ( $position === 'inside' && ! self::is_placeholder_field_type( $field['type'] ) ) {
380 565 $position = 'top';
381 566 }
382 567
383 568 $position = apply_filters( 'frm_html_label_position', $position, $field, $form );
384 - $position = ( ! empty( $position ) ) ? $position : 'top';
569 + $position = ! empty( $position ) ? $position : 'top';
385 570
386 571 return $position;
387 572 }
388 573
@@ -413,9 +598,9 @@
413 598 return;
414 599 }
415 600
416 601 $base_name = 'default_value_' . $field['id'];
417 - $html_id = isset( $field['html_id'] ) ? $field['html_id'] : self::get_html_id( $field );
602 + $html_id = isset( $field['html_id'] ) ? $field['html_id'] : self::get_html_id( $field );
418 603
419 604 $default_type = self::get_default_value_type( $field );
420 605
421 606 foreach ( $field['options'] as $opt_key => $opt ) {
@@ -428,12 +613,12 @@
428 613
429 614 // If this is an "Other" option, get the HTML for it.
430 615 if ( self::is_other_opt( $opt_key ) ) {
431 616 if ( FrmAppHelper::pro_is_installed() ) {
432 - require( FrmProAppHelper::plugin_path() . '/classes/views/frmpro-fields/other-option.php' );
617 + require FrmProAppHelper::plugin_path() . '/classes/views/frmpro-fields/other-option.php';
433 618 }
434 619 } else {
435 - require( FrmAppHelper::plugin_path() . '/classes/views/frm-fields/single-option.php' );
620 + require FrmAppHelper::plugin_path() . '/classes/views/frm-fields/single-option.php';
436 621 }
437 622
438 623 unset( $checked );
439 624 }
@@ -461,9 +646,9 @@
461 646
462 647 $default_type = self::get_default_value_type( $field );
463 648 $field_name .= ( $default_type === 'checkbox' ? '[' . $opt_key . ']' : '' );
464 649
465 - require( FrmAppHelper::plugin_path() . '/classes/views/frm-fields/single-option.php' );
650 + require FrmAppHelper::plugin_path() . '/classes/views/frm-fields/single-option.php';
466 651 }
467 652
468 653 /**
469 654 * @since 4.0
@@ -491,22 +676,28 @@
491 676 return FrmFieldsController::check_label( $opt );
492 677 }
493 678
494 679 /**
680 + * Shows the inline modal.
681 + *
495 682 * @since 4.0
683 + * @since 6.4.1 Added `inside_class` in the arguments.
684 + *
685 + * @param array $args The arguments.
496 686 */
497 687 public static function inline_modal( $args ) {
498 688 $defaults = array(
499 - 'id' => '',
500 - 'class' => '',
501 - 'show' => 0,
502 - 'callback' => array(),
503 - 'args' => array(),
504 - 'title' => '',
689 + 'id' => '',
690 + 'class' => '',
691 + 'show' => 0,
692 + 'callback' => array(),
693 + 'args' => array(),
694 + 'title' => '',
695 + 'inside_class' => 'inside',
505 696 );
506 - $args = array_merge( $defaults, $args );
697 + $args = array_merge( $defaults, $args );
507 698
508 - include( FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/inline-modal.php' );
699 + include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/inline-modal.php';
509 700 }
510 701
511 702 /**
512 703 * @since 4.0
@@ -517,9 +708,9 @@
517 708 $upgrade_link = array(
518 709 'medium' => 'builder',
519 710 'content' => 'smart-tags',
520 711 );
521 - include( FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/smart-values.php' );
712 + include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/smart-values.php';
522 713 }
523 714 }
524 715
525 716 /**
@@ -525,9 +716,9 @@
525 716 /**
526 717 * @since 4.0
527 718 */
528 719 public static function input_mask() {
529 - include( FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/input-mask-info.php' );
720 + include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/input-mask-info.php';
530 721 }
531 722
532 723 /**
533 724 * @since 4.0
@@ -532,9 +723,9 @@
532 723 /**
533 724 * @since 4.0
534 725 */
535 726 public static function layout_classes() {
536 - include( FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/layout-classes.php' );
727 + include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/layout-classes.php';
537 728 }
538 729
539 730 /**
540 731 * @param int $tax_id
@@ -560,10 +751,10 @@
560 751 return $link;
561 752 }
562 753
563 754 public static function value_meets_condition( $observed_value, $cond, $hide_opt ) {
564 - $hide_opt = self::get_value_for_comparision( $hide_opt );
565 - $observed_value = self::get_value_for_comparision( $observed_value );
755 + $hide_opt = self::get_value_for_comparison( $hide_opt );
756 + $observed_value = self::get_value_for_comparison( $observed_value );
566 757
567 758 if ( is_array( $observed_value ) ) {
568 759 return self::array_value_condition( $observed_value, $cond, $hide_opt );
569 760 }
@@ -583,11 +774,11 @@
583 774 $m = $observed_value <= $hide_opt;
584 775 } elseif ( $cond === 'LIKE' || $cond === 'not LIKE' ) {
585 776 $m = stripos( $observed_value, $hide_opt );
586 777 if ( $cond === 'not LIKE' ) {
587 - $m = ( $m === false ) ? true : false;
778 + $m = $m === false;
588 779 } else {
589 - $m = ( $m === false ) ? false : true;
780 + $m = $m !== false;
590 781 }
591 782 } elseif ( $cond === '%LIKE' ) {
592 783 // ends with
593 784 $length = strlen( $hide_opt );
@@ -597,9 +788,9 @@
597 788 // starts with
598 789 $length = strlen( $hide_opt );
599 790 $substr = substr( $observed_value, 0, $length );
600 791 $m = 0 === strcasecmp( $substr, $hide_opt );
601 - }
792 + }//end if
602 793
603 794 return $m;
604 795 }
605 796
@@ -607,9 +798,9 @@
607 798 * Trim and sanitize the values
608 799 *
609 800 * @since 2.05
610 801 */
611 - private static function get_value_for_comparision( $value ) {
802 + private static function get_value_for_comparison( $value ) {
612 803 // Remove white space from hide_opt
613 804 if ( ! is_array( $value ) ) {
614 805 $value = trim( $value );
615 806 }
@@ -623,9 +814,9 @@
623 814 $m = false;
624 815 if ( $cond === '==' ) {
625 816 if ( is_array( $hide_opt ) ) {
626 817 $m = array_intersect( $hide_opt, $observed_value );
627 - $m = empty( $m ) ? false : true;
818 + $m = ! empty( $m );
628 819 } else {
629 820 $m = in_array( $hide_opt, $observed_value );
630 821 }
631 822 } elseif ( $cond === '!=' ) {
@@ -645,9 +836,9 @@
645 836 }
646 837 }
647 838
648 839 if ( $cond === 'not LIKE' ) {
649 - $m = ( $m === false ) ? true : false;
840 + $m = $m === false;
650 841 }
651 842 } elseif ( $cond === '%LIKE' ) {
652 843 // ends with
653 844 foreach ( $observed_value as $ob ) {
@@ -663,9 +854,9 @@
663 854 $m = true;
664 855 break;
665 856 }
666 857 }
667 - }
858 + }//end if
668 859
669 860 return $m;
670 861 }
671 862
@@ -714,13 +905,16 @@
714 905 'ip',
715 906 'siteurl',
716 907 'sitename',
717 908 'admin_email',
909 + 'default-email',
910 + 'default-from-email',
718 911 'post[-|_]id',
719 912 'created[-|_]at',
720 913 'updated[-|_]at',
721 914 'updated[-|_]by',
722 915 'parent[-|_]id',
916 + 'form_name',
723 917 );
724 918
725 919 foreach ( $fields as $field ) {
726 920 $tagregexp[] = $field->id;
@@ -762,9 +956,9 @@
762 956 * @param array $atts
763 957 * @return string
764 958 */
765 959 private static function trigger_shortcode_atts( $replace_with, $atts ) {
766 - $supported_atts = array( 'sanitize', 'sanitize_url' );
960 + $supported_atts = array( 'remove_accents', 'sanitize', 'sanitize_url' );
767 961 $included_atts = array_intersect( $supported_atts, array_keys( $atts ) );
768 962 foreach ( $included_atts as $included_att ) {
769 963 if ( '0' === $atts[ $included_att ] ) {
770 964 // Skip any option that uses 0 so sanitize_url=0 does not encode.
@@ -776,8 +970,21 @@
776 970 return $replace_with;
777 971 }
778 972
779 973 /**
974 + * Converts all accent characters to ASCII characters.
975 + *
976 + * @since 6.3.1
977 + *
978 + * @param string $replace_with The text to remove accents from.
979 + *
980 + * @return string
981 + */
982 + public static function atts_remove_accents( $replace_with ) {
983 + return remove_accents( $replace_with );
984 + }
985 +
986 + /**
780 987 * @param string $replace_with
781 988 * @return string
782 989 */
783 990 private static function atts_sanitize( $replace_with ) {
@@ -796,12 +1003,17 @@
796 1003 * Prevent shortcodes in fields from being processed
797 1004 *
798 1005 * @since 3.01.02
799 1006 *
800 - * @param array $atts - includes entry object
801 - * @param string $value
1007 + * @param array $atts Includes entry object.
1008 + * @param string|null $value
1009 + * @return void
802 1010 */
803 1011 public static function sanitize_embedded_shortcodes( $atts, &$value ) {
1012 + if ( is_null( $value ) ) {
1013 + return;
1014 + }
1015 +
804 1016 $atts['value'] = $value;
805 1017 $should_sanitize = apply_filters( 'frm_sanitize_shortcodes', true, $atts );
806 1018 if ( $should_sanitize ) {
807 1019 $value = str_replace( '[', '&#91;', $value );
@@ -810,9 +1022,9 @@
810 1022
811 1023 /**
812 1024 * @since 3.0
813 1025 *
814 - * @param $atts
1026 + * @param array $atts
815 1027 *
816 1028 * @return string
817 1029 */
818 1030 private static function get_value_for_shortcode( $atts ) {
@@ -823,21 +1035,21 @@
823 1035 'key' => $atts['entry']->item_key,
824 1036 'ip' => $atts['entry']->ip,
825 1037 );
826 1038
827 - $dynamic_default = array( 'admin_email', 'siteurl', 'frmurl', 'sitename', 'get' );
1039 + $dynamic_default = array( 'admin_email', 'siteurl', 'frmurl', 'sitename', 'get', 'default-email', 'default-from-email' );
828 1040
829 1041 if ( isset( $shortcode_values[ $atts['tag'] ] ) ) {
830 1042 $replace_with = $shortcode_values[ $atts['tag'] ];
831 - } elseif ( in_array( $atts['tag'], $dynamic_default ) ) {
1043 + } elseif ( in_array( $atts['tag'], $dynamic_default, true ) ) {
832 1044 $replace_with = self::dynamic_default_values( $atts['tag'], $atts );
833 - } elseif ( $clean_tag == 'user_agent' ) {
1045 + } elseif ( $clean_tag === 'user_agent' ) {
834 1046 $description = $atts['entry']->description;
835 1047 $replace_with = FrmEntriesHelper::get_browser( $description['browser'] );
836 - } elseif ( $clean_tag == 'created_at' || $clean_tag == 'updated_at' ) {
1048 + } elseif ( $clean_tag === 'created_at' || $clean_tag === 'updated_at' ) {
837 1049 $atts['tag'] = $clean_tag;
838 1050 $replace_with = self::get_entry_timestamp( $atts );
839 - } elseif ( $clean_tag == 'created_by' || $clean_tag == 'updated_by' ) {
1051 + } elseif ( $clean_tag === 'created_by' || $clean_tag === 'updated_by' ) {
840 1052 $replace_with = self::get_display_value( $atts['entry']->{$clean_tag}, (object) array( 'type' => 'user_id' ), $atts );
841 1053 } else {
842 1054 $replace_with = self::get_field_shortcode_value( $atts );
843 1055 }
@@ -847,9 +1059,9 @@
847 1059
848 1060 /**
849 1061 * @since 3.0
850 1062 *
851 - * @param $atts
1063 + * @param array $atts
852 1064 *
853 1065 * @return string
854 1066 */
855 1067 private static function get_entry_timestamp( $atts ) {
@@ -865,11 +1077,11 @@
865 1077
866 1078 /**
867 1079 * @since 3.0
868 1080 *
869 - * @param $atts
1081 + * @param array $atts
870 1082 *
871 - * @return null|string
1083 + * @return string|null
872 1084 */
873 1085 private static function get_field_shortcode_value( $atts ) {
874 1086 $field = FrmField::getOne( $atts['tag'] );
875 1087 if ( empty( $field ) ) {
@@ -884,9 +1096,9 @@
884 1096 $replace_with = FrmEntryMeta::get_meta_value( $atts['entry'], $field->id );
885 1097 $string_value = $replace_with;
886 1098 if ( is_array( $replace_with ) ) {
887 1099 $sep = isset( $atts['sep'] ) ? $atts['sep'] : ', ';
888 - $string_value = implode( $sep, $replace_with );
1100 + $string_value = FrmAppHelper::safe_implode( $sep, $replace_with );
889 1101 }
890 1102
891 1103 if ( empty( $string_value ) && $string_value != '0' ) {
892 1104 $replace_with = '';
@@ -911,8 +1123,16 @@
911 1123 switch ( $tag ) {
912 1124 case 'admin_email':
913 1125 $new_value = get_option( 'admin_email' );
914 1126 break;
1127 + case 'default-email':
1128 + $frm_settings = FrmAppHelper::get_settings();
1129 + $new_value = ! empty( $frm_settings->default_email ) && is_email( $frm_settings->default_email ) ? $frm_settings->default_email : get_option( 'admin_email' );
1130 + break;
1131 + case 'default-from-email':
1132 + $frm_settings = FrmAppHelper::get_settings();
1133 + $new_value = ! empty( $frm_settings->from_email ) && is_email( $frm_settings->from_email ) ? $frm_settings->from_email : get_option( 'admin_email' );
1134 + break;
915 1135 case 'siteurl':
916 1136 $new_value = FrmAppHelper::site_url();
917 1137 break;
918 1138 case 'frmurl':
@@ -922,9 +1142,9 @@
922 1142 $new_value = FrmAppHelper::site_name();
923 1143 break;
924 1144 case 'get':
925 1145 $new_value = self::process_get_shortcode( $atts, $return_array );
926 - }
1146 + }//end switch
927 1147
928 1148 return $new_value;
929 1149 }
930 1150
@@ -931,9 +1151,9 @@
931 1151 /**
932 1152 * Process the [get] shortcode
933 1153 *
934 1154 * @since 2.0
935 - * @return string|array
1155 + * @return array|string
936 1156 */
937 1157 public static function process_get_shortcode( $atts, $return_array = false ) {
938 1158 if ( ! isset( $atts['param'] ) ) {
939 1159 return '';
@@ -972,9 +1192,9 @@
972 1192 return apply_filters( 'frm_display_value', $value, $field, $atts );
973 1193 }
974 1194
975 1195 /**
976 - * @param $atts array Includes value, field, and atts
1196 + * @param array $atts Includes value, field, and atts.
977 1197 */
978 1198 public static function get_unfiltered_display_value( $atts ) {
979 1199 $value = $atts['value'];
980 1200 $field = $atts['field'];
@@ -992,8 +1212,10 @@
992 1212 /**
993 1213 * Get a value from the user profile from the user ID
994 1214 *
995 1215 * @since 3.0
1216 + *
1217 + * @return string
996 1218 */
997 1219 public static function get_user_display_name( $user_id, $user_info = 'display_name', $args = array() ) {
998 1220 $defaults = array(
999 1221 'blank' => false,
@@ -1006,11 +1228,11 @@
1006 1228 $user = get_userdata( $user_id );
1007 1229 $info = '';
1008 1230
1009 1231 if ( $user ) {
1010 - if ( $user_info == 'avatar' ) {
1232 + if ( $user_info === 'avatar' ) {
1011 1233 $info = get_avatar( $user_id, $args['size'] );
1012 - } elseif ( $user_info == 'author_link' ) {
1234 + } elseif ( $user_info === 'author_link' ) {
1013 1235 $info = get_author_posts_url( $user_id );
1014 1236 } else {
1015 1237 $info = isset( $user->$user_info ) ? $user->$user_info : '';
1016 1238 }
@@ -1026,18 +1248,21 @@
1026 1248
1027 1249 return $info;
1028 1250 }
1029 1251
1252 + /**
1253 + * @param string $type
1254 + * @return array
1255 + */
1030 1256 public static function get_field_types( $type ) {
1031 - $single_input = self::single_input_fields();
1032 - $multiple_input = array( 'radio', 'checkbox', 'select', 'scale', 'star', 'lookup' );
1033 -
1257 + $single_input = self::single_input_fields();
1258 + $multiple_input = array( 'radio', 'checkbox', 'select', 'scale', 'star', 'lookup' );
1034 1259 $field_selection = FrmField::all_field_selection();
1260 + $field_types = array();
1035 1261
1036 - $field_types = array();
1037 - if ( in_array( $type, $single_input ) ) {
1262 + if ( in_array( $type, $single_input, true ) ) {
1038 1263 self::field_types_for_input( $single_input, $field_selection, $field_types );
1039 - } elseif ( in_array( $type, $multiple_input ) ) {
1264 + } elseif ( in_array( $type, $multiple_input, true ) ) {
1040 1265 self::field_types_for_input( $multiple_input, $field_selection, $field_types );
1041 1266 } elseif ( isset( $field_selection[ $type ] ) ) {
1042 1267 $field_types[ $type ] = $field_selection[ $type ];
1043 1268 }
@@ -1065,15 +1290,25 @@
1065 1290 'hidden',
1066 1291 'time',
1067 1292 'tag',
1068 1293 'password',
1294 + 'gdpr',
1069 1295 );
1070 1296 return apply_filters( 'frm_single_input_fields', $fields );
1071 1297 }
1072 1298
1299 + /**
1300 + * @param string[] $inputs
1301 + * @param array $fields
1302 + * @param array $field_types
1303 + * @return void
1304 + */
1073 1305 private static function field_types_for_input( $inputs, $fields, &$field_types ) {
1074 1306 foreach ( $inputs as $input ) {
1075 - $field_types[ $input ] = $fields[ $input ];
1307 + // This may not be set if a field type was removed using the frm_available_fields or frm_pro_available_fields filters.
1308 + if ( array_key_exists( $input, $fields ) ) {
1309 + $field_types[ $input ] = $fields[ $input ];
1310 + }
1076 1311 unset( $input );
1077 1312 }
1078 1313 }
1079 1314
@@ -1083,9 +1318,9 @@
1083 1318 * @since 2.0.6
1084 1319 *
1085 1320 * @param string $opt_key
1086 1321 *
1087 - * @return boolean Returns true if current field option is an "Other" option
1322 + * @return bool Returns true if current field option is an "Other" option
1088 1323 */
1089 1324 public static function is_other_opt( $opt_key ) {
1090 1325 return $opt_key && strpos( $opt_key, 'other_' ) === 0;
1091 1326 }
@@ -1128,10 +1363,11 @@
1128 1363 $other_val = sanitize_text_field( wp_unslash( $_POST['item_meta'][ $parent ][ $pointer ]['other'][ $field['id'] ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1129 1364 }
1130 1365
1131 1366 return $other_val;
1367 + }
1132 1368
1133 - } elseif ( isset( $field['id'] ) && isset( $_POST['item_meta']['other'][ $field['id'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1369 + if ( isset( $field['id'] ) && isset( $_POST['item_meta']['other'][ $field['id'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1134 1370 // For normal fields
1135 1371
1136 1372 if ( FrmField::is_field_with_multiple_values( $field ) ) {
1137 1373 // phpcs:ignore WordPress.Security.NonceVerification.Missing
@@ -1140,9 +1376,9 @@
1140 1376 $other_val = sanitize_text_field( wp_unslash( $_POST['item_meta']['other'][ $field['id'] ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1141 1377 }
1142 1378
1143 1379 return $other_val;
1144 - }
1380 + }//end if
1145 1381
1146 1382 // For checkboxes
1147 1383 if ( $field['type'] === 'checkbox' && is_array( $field['value'] ) ) {
1148 1384 // Check if there is an "other" val in saved value and make sure the
@@ -1154,9 +1390,9 @@
1154 1390 /**
1155 1391 * For radio buttons and dropdowns
1156 1392 * Check if saved value equals any of the options. If not, set it as the other value.
1157 1393 */
1158 - foreach ( $field['options'] as $opt_key => $opt_val ) {
1394 + foreach ( $field['options'] as $opt_val ) {
1159 1395 $temp_val = is_array( $opt_val ) ? $opt_val['value'] : $opt_val;
1160 1396 // Multi-select dropdowns - key is not preserved
1161 1397 if ( is_array( $field['value'] ) ) {
1162 1398 $o_key = array_search( $temp_val, $field['value'] );
@@ -1168,15 +1404,15 @@
1168 1404 return '';
1169 1405 } else {
1170 1406 $other_val = $field['value'];
1171 1407 }
1172 - unset( $opt_key, $opt_val, $temp_val );
1408 + unset( $opt_val, $temp_val );
1173 1409 }
1174 1410 // For multi-select dropdowns only
1175 1411 if ( is_array( $field['value'] ) && ! empty( $field['value'] ) ) {
1176 1412 $other_val = reset( $field['value'] );
1177 1413 }
1178 - }
1414 + }//end if
1179 1415
1180 1416 return $other_val;
1181 1417 }
1182 1418
@@ -1185,10 +1421,10 @@
1185 1421 * Intended for front-end use
1186 1422 *
1187 1423 * @since 2.0.6
1188 1424 *
1189 - * @param array $args should include field, opt_key and field name
1190 - * @param boolean $other_opt
1425 + * @param array $args Should include field, opt_key and field name.
1426 + * @param bool $other_opt
1191 1427 * @param string $checked
1192 1428 *
1193 1429 * @return array $other_args
1194 1430 */
@@ -1197,14 +1433,14 @@
1197 1433 'name' => '',
1198 1434 'value' => '',
1199 1435 );
1200 1436
1201 - //Check if this is an "Other" option
1437 + // Check if this is an "Other" option.
1202 1438 if ( ! self::is_other_opt( $args['opt_key'] ) ) {
1203 1439 return $other_args;
1204 1440 }
1205 1441
1206 - $other_opt = true;
1442 + $other_opt = true;
1207 1443
1208 1444 self::set_other_name( $args, $other_args );
1209 1445 self::set_other_value( $args, $other_args );
1210 1446
@@ -1211,25 +1447,34 @@
1211 1447 if ( '' !== $other_args['value'] ) {
1212 1448 $checked = 'checked="checked" ';
1213 1449 }
1214 1450
1451 + // If 'other' is selected as one of the default values for a checkbox field, 'checked' attribute should be on.
1452 + if ( ! $checked &&
1453 + $args['field']['type'] === 'checkbox' &&
1454 + is_array( $args['field']['value'] ) &&
1455 + isset( $args['field_val'] ) &&
1456 + in_array( $args['field_val'], $args['field']['value'], true )
1457 + ) {
1458 + $checked = 'checked="checked" ';
1459 + }
1460 +
1215 1461 return $other_args;
1216 1462 }
1217 1463
1218 1464 /**
1465 + * @since 2.0.6
1219 1466 * @param array $args
1220 1467 * @param array $other_args
1221 - *
1222 - * @since 2.0.6
1223 1468 */
1224 1469 private static function set_other_name( $args, &$other_args ) {
1225 - //Set up name for other field
1470 + // Set up name for other field
1226 1471 $other_args['name'] = str_replace( '[]', '', $args['field_name'] );
1227 1472 $other_args['name'] = preg_replace( '/\[' . $args['field']['id'] . '\]$/', '', $other_args['name'] );
1228 1473 $other_args['name'] = $other_args['name'] . '[other][' . $args['field']['id'] . ']';
1229 1474
1230 - //Converts item_meta[field_id] => item_meta[other][field_id] and
1231 - //item_meta[parent][0][field_id] => item_meta[parent][0][other][field_id]
1475 + // Converts item_meta[field_id] => item_meta[other][field_id] and
1476 + // item_meta[parent][0][field_id] => item_meta[parent][0][other][field_id]
1232 1477 if ( FrmField::is_field_with_multiple_values( $args['field'] ) ) {
1233 1478 $other_args['name'] .= '[' . $args['opt_key'] . ']';
1234 1479 }
1235 1480 }
@@ -1236,12 +1481,11 @@
1236 1481
1237 1482 /**
1238 1483 * Find the parent and pointer, and get text for "other" text field
1239 1484 *
1485 + * @since 2.0.6
1240 1486 * @param array $args
1241 1487 * @param array $other_args
1242 - *
1243 - * @since 2.0.6
1244 1488 */
1245 1489 private static function set_other_value( $args, &$other_args ) {
1246 1490 $parent = '';
1247 1491 $pointer = '';
@@ -1268,11 +1512,10 @@
1268 1512
1269 1513 /**
1270 1514 * If this field includes an other option, show it
1271 1515 *
1272 - * @param $args array
1273 - *
1274 1516 * @since 2.0.6
1517 + * @param array $args
1275 1518 */
1276 1519 public static function include_other_input( $args ) {
1277 1520 if ( ! $args['other_opt'] ) {
1278 1521 return;
@@ -1282,9 +1525,9 @@
1282 1525 if ( ! $args['checked'] || trim( $args['checked'] ) == '' ) {
1283 1526 // hide the field if the other option is not selected
1284 1527 $classes[] = 'frm_pos_none';
1285 1528 }
1286 - if ( $args['field']['type'] == 'select' && $args['field']['multiple'] ) {
1529 + if ( $args['field']['type'] === 'select' && ! empty( $args['field']['multiple'] ) ) {
1287 1530 $classes[] = 'frm_other_full';
1288 1531 }
1289 1532
1290 1533 // Set up HTML ID for Other field
@@ -1305,11 +1548,11 @@
1305 1548 * Note: This does not affect fields in repeating sections
1306 1549 *
1307 1550 * @since 2.0.08
1308 1551 *
1309 - * @param string $type - field type
1310 - * @param string $html_id
1311 - * @param string|boolean $opt_key
1552 + * @param string $type Field type.
1553 + * @param string $html_id
1554 + * @param bool|string $opt_key
1312 1555 *
1313 1556 * @return string $other_id
1314 1557 */
1315 1558 public static function get_other_field_html_id( $type, $html_id, $opt_key = false ) {
@@ -1315,9 +1558,9 @@
1315 1558 public static function get_other_field_html_id( $type, $html_id, $opt_key = false ) {
1316 1559 $other_id = $html_id;
1317 1560
1318 1561 // If hidden radio field, add an opt key of 0
1319 - if ( $type == 'radio' && $opt_key === false ) {
1562 + if ( $type === 'radio' && $opt_key === false ) {
1320 1563 $opt_key = 0;
1321 1564 }
1322 1565
1323 1566 if ( $opt_key !== false ) {
@@ -1356,12 +1599,17 @@
1356 1599 $replace_with[] = 'field_id="' . $new . '"';
1357 1600 $replace[] = 'field_id=\"' . $old . '\"';
1358 1601 $replace_with[] = 'field_id=\"' . $new . '\"';
1359 1602 unset( $old, $new );
1360 - }
1603 + }//end foreach
1361 1604 if ( is_array( $val ) ) {
1362 1605 foreach ( $val as $k => $v ) {
1363 1606 if ( is_string( $v ) ) {
1607 + if ( 'custom_html' === $k ) {
1608 + $val[ $k ] = self::switch_ids_except_strings( $replace, $replace_with, array( '[if description]', '[description]', '[/if description]' ), $v );
1609 + unset( $k, $v );
1610 + continue;
1611 + }
1364 1612 $val[ $k ] = str_replace( $replace, $replace_with, $v );
1365 1613 unset( $k, $v );
1366 1614 }
1367 1615 }
@@ -1372,8 +1620,33 @@
1372 1620 return $val;
1373 1621 }
1374 1622
1375 1623 /**
1624 + * Removes exception strings from replacement arrays and replaces the rest in the provided value string.
1625 + *
1626 + * @since 6.14
1627 + *
1628 + * @param array $replace Values to be replaced.
1629 + * @param array $replace_with Replacement values.
1630 + * @param array $exceptions Array of strings to skip.
1631 + * @param string $value Value to be updated.
1632 + *
1633 + * @return string
1634 + */
1635 + private static function switch_ids_except_strings( $replace, $replace_with, $exceptions, $value ) {
1636 + foreach ( $exceptions as $exception ) {
1637 + $index = array_search( $exception, $replace, true );
1638 + if ( false === $index ) {
1639 + continue;
1640 + }
1641 + unset( $replace[ $index ] );
1642 + unset( $replace_with[ $index ] );
1643 + }
1644 + $value = str_replace( $replace, $replace_with, $value );
1645 + return $value;
1646 + }
1647 +
1648 + /**
1376 1649 * @since 4.0
1377 1650 */
1378 1651 public static function bulk_options_overlay() {
1379 1652 $prepop = array();
@@ -1378,9 +1651,9 @@
1378 1651 public static function bulk_options_overlay() {
1379 1652 $prepop = array();
1380 1653 self::get_bulk_prefilled_opts( $prepop, true );
1381 1654
1382 - include( FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/bulk-options-overlay.php' );
1655 + include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/bulk-options-overlay.php';
1383 1656 }
1384 1657
1385 1658 public static function get_us_states() {
1386 1659 $states = array(
@@ -1820,9 +2093,9 @@
1820 2093 * Display a field value selector
1821 2094 *
1822 2095 * @since 2.03.05
1823 2096 *
1824 - * @param int $selector_field_id
2097 + * @param int $selector_field_id
1825 2098 * @param array $selector_args
1826 2099 */
1827 2100 public static function display_field_value_selector( $selector_field_id, $selector_args ) {
1828 2101 $field_value_selector = FrmFieldFactory::create_field_value_selector( $selector_field_id, $selector_args );
@@ -1838,9 +2111,9 @@
1838 2111 *
1839 2112 * @return array
1840 2113 */
1841 2114 public static function convert_field_object_to_flat_array( $field ) {
1842 - $field_options = $field->field_options;
2115 + $field_options = is_array( $field->field_options ) ? $field->field_options : array();
1843 2116 $field_array = get_object_vars( $field );
1844 2117 unset( $field_array['field_options'] );
1845 2118
1846 2119 return $field_array + $field_options;
@@ -1858,8 +2131,14 @@
1858 2131 $field_label = FrmAppHelper::icon_by_class( FrmFormsHelper::get_field_link_icon( $field_type ), array( 'echo' => false ) );
1859 2132 $field_name = FrmFormsHelper::get_field_link_name( $field_type );
1860 2133 $field_label .= ' <span>' . $field_name . '</span>';
1861 2134
2135 + if ( ! empty( $field_type['is_new'] ) ) {
2136 + ob_start();
2137 + FrmAppHelper::show_pill_text();
2138 + $field_label .= ob_get_clean();
2139 + }
2140 +
1862 2141 // If the individual field isn't allowed, disable it.
1863 2142 $run_filter = true;
1864 2143 $single_no_allow = ' ';
1865 2144 $install_data = '';
@@ -1864,9 +2143,9 @@
1864 2143 $single_no_allow = ' ';
1865 2144 $install_data = '';
1866 2145 $requires = '';
1867 2146 $link = isset( $field_type['link'] ) ? esc_url_raw( $field_type['link'] ) : '';
1868 - $has_show_upgrade_class = strpos( $field_type['icon'], ' frm_show_upgrade' );
2147 + $has_show_upgrade_class = isset( $field_type['icon'] ) && strpos( $field_type['icon'], ' frm_show_upgrade' );
1869 2148 $show_upgrade = $has_show_upgrade_class || false !== strpos( $args['no_allow_class'], 'frm_show_upgrade' );
1870 2149
1871 2150 if ( $has_show_upgrade_class ) {
1872 2151 $single_no_allow .= 'frm_show_upgrade';
@@ -1904,8 +2183,16 @@
1904 2183 'data-content' => $field_key,
1905 2184 'data-requires' => $requires,
1906 2185 );
1907 2186
2187 + if ( ! empty( $field_type['hide'] ) ) {
2188 + $li_params['class'] .= ' frm_hidden';
2189 + }
2190 +
2191 + if ( ! empty( $field_type['upsell_image'] ) ) {
2192 + $li_params['data-upsell-image'] = $field_type['upsell_image'];
2193 + }
2194 +
1908 2195 if ( $upgrade_message ) {
1909 2196 $li_params['data-message'] = $upgrade_message;
1910 2197 }
1911 2198 ?>
@@ -1913,9 +2200,9 @@
1913 2200 <?php
1914 2201 if ( $run_filter ) {
1915 2202 $field_label = apply_filters( 'frmpro_field_links', $field_label, $args['id'], $field_key );
1916 2203 }
1917 - echo FrmAppHelper::kses( $field_label, array( 'a', 'i', 'span', 'use', 'svg' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2204 + FrmAppHelper::kses_echo( $field_label, array( 'a', 'i', 'span', 'use', 'svg' ) );
1918 2205 ?>
1919 2206 </li>
1920 2207 <?php
1921 2208 }
@@ -1927,12 +2214,29 @@
1927 2214 *
1928 2215 * @param array $field Field data.
1929 2216 */
1930 2217 public static function show_radio_display_format( $field ) {
2218 + $options = self::get_display_format_options( $field );
2219 +
2220 + $args = self::get_display_format_args( $field, $options );
2221 +
2222 + include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/radio-display-format.php';
2223 + }
2224 +
2225 + /**
2226 + * Creates an array that contains variables used for display format options setting.
2227 + *
2228 + * @since 6.3.2
2229 + *
2230 + * @param array $field The field.
2231 + *
2232 + * @return array
2233 + */
2234 + public static function get_display_format_options( $field ) {
1931 2235 $options = array(
1932 2236 '0' => array(
1933 - 'text' => __( 'Simple', 'formidable' ),
1934 - 'svg' => 'frm_simple_radio',
2237 + 'text' => __( 'Simple', 'formidable' ),
2238 + 'svg' => 'frm_simple_radio',
1935 2239 ),
1936 2240 '1' => array(
1937 2241 'text' => __( 'Images', 'formidable' ),
1938 2242 'svg' => 'frm_image_as_option',
@@ -1956,14 +2260,13 @@
1956 2260 *
1957 2261 * @since 5.0.04
1958 2262 *
1959 2263 * @param array $options Options.
2264 + * @param array $field
1960 2265 */
1961 - $options = apply_filters( 'frm_radio_display_format_options', $options );
2266 + $options = apply_filters( 'frm_' . $field['type'] . '_display_format_options', $options, $field );
1962 2267
1963 - $args = self::get_display_format_args( $field, $options );
1964 -
1965 - include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/radio-display-format.php';
2268 + return $options;
1966 2269 }
1967 2270
1968 2271 /**
1969 2272 * Gets display format arguments to pass to the images_dropdown() method.
@@ -1973,9 +2276,9 @@
1973 2276 * @param array $field Field data.
1974 2277 * @param array $options Options array.
1975 2278 * @return array
1976 2279 */
1977 - private static function get_display_format_args( $field, $options ) {
2280 + public static function get_display_format_args( $field, $options ) {
1978 2281 $args = array(
1979 2282 'selected' => '0',
1980 2283 'options' => array(),
1981 2284 'name' => 'field_options[image_options_' . $field['id'] . ']',
@@ -1993,9 +2296,9 @@
1993 2296 *
1994 2297 * @param array $args Arguments.
1995 2298 * @param array $method_args The arguments from the method. Contains `field`, `options`.
1996 2299 */
1997 - return apply_filters( 'frm_radio_display_format_args', $args, compact( 'field', 'options' ) );
2300 + return apply_filters( 'frm_' . $field['type'] . '_display_format_args', $args, compact( 'field', 'options' ) );
1998 2301 }
1999 2302
2000 2303 /**
2001 2304 * @since 5.0.04
@@ -2055,9 +2358,10 @@
2055 2358 }
2056 2359
2057 2360 /**
2058 2361 * Maybe adjust a field value based on type.
2059 - * Some types require unserializing an array (@see self::field_type_requires_unserialize).
2362 + * Some types require unserializing an array.
2363 + * These types are defined by a array_allowed property on their field model class.
2060 2364 *
2061 2365 * @since 6.2
2062 2366 *
2063 2367 * @param mixed $value
@@ -2069,95 +2373,53 @@
2069 2373 $value = $field_object->maybe_decode_value( $value );
2070 2374 }
2071 2375
2072 2376 /**
2073 - * @deprecated 4.0
2377 + * @since 6.8
2378 + *
2379 + * @param int|string $form_id
2380 + * @param array $field_ids If this is not empty, the results will be filtered by field id.
2381 + * @return array
2074 2382 */
2075 - public static function show_icon_link_js( $atts ) {
2076 - _deprecated_function( __METHOD__, '4.0' );
2077 - $atts['icon'] .= $atts['is_selected'] ? ' ' : ' frm_inactive_icon ';
2078 - if ( isset( $atts['has_default'] ) && ! $atts['has_default'] ) {
2079 - $atts['icon'] .= 'frm_hidden ';
2383 + public static function get_draft_field_results( $form_id, $field_ids = array() ) {
2384 + if ( FrmAppHelper::pro_is_installed() ) {
2385 + $child_form_ids = FrmDb::get_col( 'frm_forms', array( 'parent_form_id' => $form_id ) );
2386 + $form_ids = array_merge( array( $form_id ), $child_form_ids );
2387 + } else {
2388 + $form_ids = array( $form_id );
2080 2389 }
2081 - echo '<a href="javascript:void(0)" class="frm_bstooltip ' . esc_attr( $atts['icon'] ) . 'frm_default_val_icons frm_action_icon frm_icon_font" title="' . esc_attr( $atts['message'] ) . '"></a>';
2082 - }
2083 2390
2084 - /**
2085 - * @deprecated 4.0
2086 - */
2087 - public static function show_default_blank_js( $is_selected, $has_default_value = true ) {
2088 - _deprecated_function( __METHOD__, '4.0' );
2089 - }
2391 + $where = array(
2392 + 'form_id' => $form_ids,
2393 + // Do a soft check for fields that look like drafts only.
2394 + 'field_options LIKE' => 's:5:"draft";i:1;',
2395 + );
2090 2396
2091 - /**
2092 - * @deprecated 4.0
2093 - */
2094 - public static function clear_on_focus_html( $field, $display, $id = '' ) {
2095 - _deprecated_function( __METHOD__, '4.0' );
2096 - }
2397 + if ( $field_ids ) {
2398 + $where['id'] = $field_ids;
2399 + }
2097 2400
2098 - /**
2099 - * @deprecated 4.0
2100 - */
2101 - public static function show_onfocus_js( $is_selected, $has_default_value = true ) {
2102 - _deprecated_function( __METHOD__, '4.0' );
2103 - }
2401 + $rows = FrmDb::get_results( 'frm_fields', $where, 'id, field_options' );
2104 2402
2105 - /**
2106 - * @deprecated 3.0
2107 - * @codeCoverageIgnore
2108 - */
2109 - public static function display_recaptcha() {
2110 - _deprecated_function( __FUNCTION__, '3.0', 'FrmFieldCaptcha::field_input' );
2403 + return array_filter(
2404 + $rows,
2405 + function ( $row ) {
2406 + FrmAppHelper::unserialize_or_decode( $row->field_options );
2407 + return is_array( $row->field_options ) && ! empty( $row->field_options['draft'] );
2408 + }
2409 + );
2111 2410 }
2112 2411
2113 2412 /**
2114 - * @deprecated 3.0
2115 - * @codeCoverageIgnore
2116 - */
2117 - public static function remove_inline_conditions( $no_vars, $code, $replace_with, &$html ) {
2118 - FrmDeprecated::remove_inline_conditions( $no_vars, $code, $replace_with, $html );
2119 - }
2120 -
2121 - /**
2122 - * @deprecated 3.0
2123 - * @codeCoverageIgnore
2124 - */
2125 - public static function get_shortcode_tag( $shortcodes, $short_key, $args ) {
2126 - return FrmDeprecated::get_shortcode_tag( $shortcodes, $short_key, $args );
2127 - }
2128 -
2129 - /**
2130 - * @deprecated 3.0
2131 - * @codeCoverageIgnore
2413 + * This is called when loading the form builder.
2414 + * Any unsaved draft fields get added to a hidden draft_fields input on load.
2132 2415 *
2133 - * @param string $html
2134 - * @param array $field
2135 - * @param array $errors
2136 - * @param object|false $form
2137 - * @param array $args
2416 + * @since 6.8
2138 2417 *
2139 - * @return string
2418 + * @param int|string $form_id
2419 + * @return array
2140 2420 */
2141 - public static function replace_shortcodes( $html, $field, $errors = array(), $form = false, $args = array() ) {
2142 - return FrmDeprecated::replace_shortcodes( $html, $field, $errors, $form, $args );
2143 - }
2144 -
2145 - /**
2146 - * @deprecated 3.0
2147 - * @codeCoverageIgnore
2148 - */
2149 - public static function get_default_field_opts( $type, $field = null, $limit = false ) {
2150 - return FrmDeprecated::get_default_field_opts( $type, $field, $limit );
2151 - }
2152 -
2153 - /**
2154 - * @deprecated 2.02.07 This is still referenced in the Highrise add on as of v1.06.
2155 - * @codeCoverageIgnore
2156 - *
2157 - * @param array $args
2158 - * @return string
2159 - */
2160 - public static function dropdown_categories( $args ) {
2161 - return FrmDeprecated::dropdown_categories( $args );
2421 + public static function get_all_draft_field_ids( $form_id ) {
2422 + $draft_field_rows = self::get_draft_field_results( $form_id );
2423 + return wp_list_pluck( $draft_field_rows, 'id' );
2162 2424 }
2163 2425 }