PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.26.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.26.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
formidable / classes / helpers / FrmEntriesHelper.php

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

991 lines 29.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 FrmEntriesHelper {
7
8 /**
9 * "Submitted" entry status.
10 *
11 * @since 6.4.2
12 *
13 * @var int
14 */
15 const SUBMITTED_ENTRY_STATUS = 0;
16
17 /**
18 * "Draft" entry status.
19 *
20 * @since 6.4.2
21 *
22 * @var int
23 */
24 const DRAFT_ENTRY_STATUS = 1;
25
26 /**
27 * @param mixed $fields
28 * @param object|string $form
29 * @param bool $reset
30 * @param array $args
31 *
32 * @return array
33 */
34 public static function setup_new_vars( $fields, $form = '', $reset = false, $args = array() ) {
35 remove_action( 'media_buttons', 'FrmFormsController::insert_form_button' );
36
37 $values = array(
38 'name' => '',
39 'description' => '',
40 'item_key' => '',
41 );
42
43 $values['fields'] = array();
44
45 if ( empty( $fields ) ) {
46 return apply_filters( 'frm_setup_new_entry', $values );
47 }
48
49 foreach ( (array) $fields as $field ) {
50 $original_default = $field->default_value;
51 self::prepare_field_default_value( $field );
52 $new_value = self::get_field_value_for_new_entry( $field, $reset, $args );
53
54 $field_array = FrmAppHelper::start_field_array( $field );
55 $field_array['value'] = $new_value;
56 $field_array['type'] = apply_filters( 'frm_field_type', $field->type, $field, $new_value );
57 $field_array['parent_form_id'] = $args['parent_form_id'] ?? $field->form_id;
58 $field_array['reset_value'] = $reset;
59 $field_array['in_embed_form'] = $args['in_embed_form'] ?? '0';
60 $field_array['original_default'] = $original_default;
61
62 FrmFieldsHelper::prepare_new_front_field( $field_array, $field, $args );
63
64 if ( ! is_array( $field->field_options ) ) {
65 $field->field_options = array();
66 }
67
68 $field_array = array_merge( $field->field_options, $field_array );
69
70 $values['fields'][] = $field_array;
71
72 if ( ! $form || ! isset( $form->id ) ) {
73 $form = FrmForm::getOne( $field->form_id );
74 }
75 }//end foreach
76
77 FrmAppHelper::unserialize_or_decode( $form->options );
78
79 if ( is_array( $form->options ) ) {
80 $values = array_merge( $values, $form->options );
81 }
82
83 $form_defaults = FrmFormsHelper::get_default_opts();
84 $form_defaults['custom_style'] = FrmAppHelper::custom_style_value( array() );
85
86 $values = array_merge( $form_defaults, $values );
87
88 return apply_filters( 'frm_setup_new_entry', $values );
89 }
90
91 /**
92 * @since 2.05
93 *
94 * @param object $field
95 *
96 * @return void
97 */
98 private static function prepare_field_default_value( &$field ) {
99 // If checkbox, multi-select dropdown, or checkbox data from entries field, the value should be an array.
100 $return_array = FrmField::is_field_with_multiple_values( $field );
101
102 /**
103 * Do any shortcodes in default value and allow customization of default value.
104 * Calls FrmProFieldsHelper::get_default_value
105 */
106 $field->default_value = apply_filters( 'frm_get_default_value', $field->default_value, $field, true, $return_array );
107
108 if ( isset( $field->field_options['placeholder'] ) ) {
109 $field->field_options['placeholder'] = apply_filters( 'frm_get_default_value', $field->field_options['placeholder'], $field, false, false );
110 }
111 }
112
113 /**
114 * Set the value for each field
115 * This function is used when the form is first loaded and on all page turns *for a new entry*
116 *
117 * @since 2.0.13
118 *
119 * @param object $field - this is passed by reference since it is an object.
120 * @param bool $reset
121 * @param array $args
122 *
123 * @return array|string $new_value
124 */
125 private static function get_field_value_for_new_entry( $field, $reset, $args ) {
126 $new_value = $field->default_value;
127
128 if ( ! $reset && self::value_is_posted( $field, $args ) ) {
129 self::get_posted_value( $field, $new_value, $args );
130 }
131
132 if ( ! is_array( $new_value ) ) {
133 $new_value = str_replace( '"', '&quot;', $new_value );
134 }
135
136 return $new_value;
137 }
138
139 /**
140 * Check if a field has a posted value
141 *
142 * @since 2.01.0
143 *
144 * @param object $field
145 * @param array $args
146 *
147 * @return bool $value_is_posted
148 */
149 public static function value_is_posted( $field, $args ) {
150 $value_is_posted = false;
151
152 if ( $_POST ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
153 $repeating = isset( $args['repeating'] ) && $args['repeating'];
154
155 if ( $repeating ) {
156 if ( isset( $_POST['item_meta'][ $args['parent_field_id'] ][ $args['key_pointer'] ][ $field->id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
157 $value_is_posted = true;
158 }
159 } elseif ( isset( $_POST['item_meta'][ $field->id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
160 $value_is_posted = true;
161 }
162 }
163
164 return $value_is_posted;
165 }
166
167 /**
168 * @param array $values
169 * @param object $record
170 *
171 * @return array
172 */
173 public static function setup_edit_vars( $values, $record ) {
174 remove_action( 'media_buttons', 'FrmFormsController::insert_form_button' );
175
176 $values['item_key'] = FrmAppHelper::get_post_param( 'item_key', $record->item_key, 'sanitize_title' );
177 $values['form_id'] = $record->form_id;
178 $values['is_draft'] = $record->is_draft;
179
180 return apply_filters( 'frm_setup_edit_entry_vars', $values, $record );
181 }
182
183 /**
184 * @param string $message
185 * @param array $atts
186 *
187 * @return string
188 */
189 public static function replace_default_message( $message, $atts ) {
190 if ( strpos( $message, '[default-message' ) === false &&
191 strpos( $message, '[default_message' ) === false &&
192 ! empty( $message ) ) {
193 return $message;
194 }
195
196 if ( empty( $message ) ) {
197 $message = '[default-message]';
198 }
199
200 preg_match_all( "/\[(default-message|default_message)\b(.*?)(?:(\/))?\]/s", $message, $shortcodes, PREG_PATTERN_ORDER );
201
202 foreach ( $shortcodes[0] as $short_key => $tag ) {
203 $add_atts = FrmShortcodeHelper::get_shortcode_attribute_array( $shortcodes[2][ $short_key ] );
204
205 if ( ! empty( $add_atts ) ) {
206 $this_atts = array_merge( $atts, $add_atts );
207 } else {
208 $this_atts = $atts;
209 }
210
211 $default = FrmEntriesController::show_entry_shortcode( $this_atts );
212
213 // Add the default message.
214 $message = str_replace( $shortcodes[0][ $short_key ], $default, $message );
215 }
216
217 return $message;
218 }
219
220 /**
221 * @param stdClass $entry
222 * @param stdClass $field
223 * @param array $atts
224 *
225 * @return string
226 */
227 public static function prepare_display_value( $entry, $field, $atts ) {
228 $field_value = $entry->metas[ $field->id ] ?? false;
229
230 if ( FrmAppHelper::pro_is_installed() ) {
231 $empty = empty( $field_value );
232 FrmProEntriesHelper::get_dynamic_list_values( $field, $entry, $field_value );
233
234 if ( $empty && ! empty( $field_value ) ) {
235 // We've got an entry id, so switch it to a value.
236 $atts['force_id'] = true;
237 }
238 }
239
240 if ( $field->form_id == $entry->form_id || empty( $atts['embedded_field_id'] ) ) {
241 return self::display_value( $field_value, $field, $atts );
242 }
243
244 if ( ! FrmAppHelper::pro_is_installed() ) {
245 return '';
246 }
247
248 if ( is_callable( 'FrmProEntriesHelper::prepare_child_display_value' ) ) {
249 return FrmProEntriesHelper::prepare_child_display_value( $entry, $field, $atts );
250 }
251
252 // This is an embedded form.
253 if ( strpos( $atts['embedded_field_id'], 'form' ) === 0 ) {
254 // This is a repeating section.
255 $child_entries = FrmEntry::getAll( array( 'it.parent_item_id' => $entry->id ), '', '', true );
256 } else {
257 // Get all values for this field.
258 $child_values = $entry->metas[ $atts['embedded_field_id'] ] ?? false;
259
260 if ( $child_values ) {
261 $child_entries = FrmEntry::getAll( array( 'it.id' => (array) $child_values ) );
262 }
263 }
264
265 $field_value = array();
266
267 if ( empty( $child_entries ) ) {
268 return '';
269 }
270
271 foreach ( $child_entries as $child_entry ) {
272 $atts['item_id'] = $child_entry->id;
273 $atts['post_id'] = $child_entry->post_id;
274
275 // Fet the value for this field -- check for post values as well.
276 $entry_val = FrmProEntryMetaHelper::get_post_or_meta_value( $child_entry, $field );
277
278 if ( $entry_val || '0' === $entry_val ) {
279 // foreach entry get display_value.
280 $field_value[] = self::display_value( $entry_val, $field, $atts );
281 }
282
283 unset( $child_entry );
284 }
285
286 $sep = ', ';
287
288 if ( strpos( implode( ' ', $field_value ), '<img' ) !== false ) {
289 $sep = '<br/>';
290 }
291
292 $val = implode( $sep, $field_value );
293
294 return FrmAppHelper::kses( $val, 'all' );
295 }
296
297 /**
298 * Prepare the saved value for display
299 *
300 * @param array|string $value
301 * @param object $field
302 * @param array $atts
303 *
304 * @return string
305 */
306 public static function display_value( $value, $field, $atts = array() ) {
307
308 $defaults = array(
309 'type' => '',
310 'html' => false,
311 'show_filename' => true,
312 'truncate' => false,
313 'sep' => ', ',
314 'post_id' => 0,
315 'form_id' => $field->form_id,
316 'field' => $field,
317 'keepjs' => 0,
318 'return_array' => false,
319 );
320
321 $atts = wp_parse_args( $atts, $defaults );
322
323 if ( FrmField::is_image( $field ) || $field->type === 'star' ) {
324 $atts['truncate'] = false;
325 $atts['html'] = true;
326 }
327
328 $atts = apply_filters( 'frm_display_value_atts', $atts, $field, $value );
329
330 if ( is_string( $field->field_options ) ) {
331 $field->field_options = array();
332 }
333
334 if ( ! isset( $field->field_options['post_field'] ) ) {
335 $field->field_options['post_field'] = '';
336 }
337
338 if ( ! isset( $field->field_options['custom_field'] ) ) {
339 $field->field_options['custom_field'] = '';
340 }
341
342 if ( FrmAppHelper::pro_is_installed() && $atts['post_id'] && ( $field->field_options['post_field'] || $atts['type'] === 'tag' ) ) {
343 $atts['pre_truncate'] = $atts['truncate'];
344 $atts['truncate'] = true;
345 $atts['exclude_cat'] = $field->field_options['exclude_cat'] ?? 0;
346
347 $value = FrmProEntryMetaHelper::get_post_value( $atts['post_id'], $field->field_options['post_field'], $field->field_options['custom_field'], $atts );
348 $atts['truncate'] = $atts['pre_truncate'];
349 }
350
351 if ( $value == '' ) {
352 return $value;
353 }
354
355 $unfiltered_value = $value;
356 FrmFieldsHelper::prepare_field_value( $unfiltered_value, $field->type );
357
358 $value = apply_filters( 'frm_display_value_custom', $unfiltered_value, $field, $atts );
359 $value = apply_filters( 'frm_display_' . $field->type . '_value_custom', $value, compact( 'field', 'atts' ) );
360
361 if ( $value == $unfiltered_value ) {
362 $value = FrmFieldsHelper::get_unfiltered_display_value( compact( 'value', 'field', 'atts' ) );
363 }
364
365 if ( $atts['truncate'] && $atts['type'] !== 'url' ) {
366 $value = FrmAppHelper::truncate( $value, 50 );
367 }
368
369 if ( ! $atts['keepjs'] && ! is_array( $value ) ) {
370 $value = FrmAppHelper::kses( $value, 'all' );
371 }
372
373 return apply_filters( 'frm_display_value', $value, $field, $atts );
374 }
375
376 /**
377 * @param object $field
378 * @param mixed $value
379 * @param array $args
380 *
381 * @return void
382 */
383 public static function set_posted_value( $field, $value, $args ) {
384 // If validating a field with "other" opt, set back to prev value now.
385 if ( ! empty( $args['other'] ) ) {
386 $value = $args['temp_value'];
387 }
388
389 if ( empty( $args['parent_field_id'] ) ) {
390 $_POST['item_meta'][ $field->id ] = $value;
391 } else {
392 self::set_parent_field_posted_value( $field, $value, $args );
393 }
394 }
395
396 /**
397 * Init arrays if necessary, else we get fatal error.
398 *
399 * @since 4.01
400 *
401 * @param object $field Field object.
402 * @param mixed $value Value to set.
403 * @param array $args Additional arguments.
404 *
405 * @return void
406 */
407 private static function set_parent_field_posted_value( $field, $value, $args ) {
408 if ( isset( $_POST['item_meta'][ $args['parent_field_id'] ] ) && is_array( $_POST['item_meta'][ $args['parent_field_id'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
409 if ( ! isset( $_POST['item_meta'][ $args['parent_field_id'] ][ $args['key_pointer'] ] ) || ! is_array( $_POST['item_meta'][ $args['parent_field_id'] ][ $args['key_pointer'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
410 $_POST['item_meta'][ $args['parent_field_id'] ][ $args['key_pointer'] ] = array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing
411 }
412 } else {
413 // All of the section was probably removed.
414 $_POST['item_meta'][ $args['parent_field_id'] ] = array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing
415 $_POST['item_meta'][ $args['parent_field_id'] ][ $args['key_pointer'] ] = array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing
416 }
417
418 $_POST['item_meta'][ $args['parent_field_id'] ][ $args['key_pointer'] ][ $field->id ] = $value; // phpcs:ignore WordPress.Security.NonceVerification.Missing
419 }
420
421 /**
422 * @param array|int|object $field
423 * @param mixed $value
424 * @param array $args
425 *
426 * @return void
427 */
428 public static function get_posted_value( $field, &$value, $args ) {
429 if ( is_array( $field ) ) {
430 $field_id = $field['id'];
431 $field_obj = FrmFieldFactory::get_field_object( $field['id'] );
432 } elseif ( is_object( $field ) ) {
433 $field_id = $field->id;
434
435 if ( 'hidden' === $field->type && ! empty( $field->field_options['original_type'] ) ) {
436 $field_obj = FrmFieldFactory::get_field_type( $field->field_options['original_type'], $field );
437 } else {
438 $field_obj = FrmFieldFactory::get_field_object( $field );
439 }
440 } elseif ( is_numeric( $field ) ) {
441 $field_id = $field;
442 $field_obj = FrmFieldFactory::get_field_object( $field );
443 } else {
444 $value = self::get_posted_meta( $field, $args );
445 FrmAppHelper::sanitize_value( 'sanitize_text_field', $value );
446 return;
447 }
448
449 $value = self::get_posted_meta( $field_id, $args );
450
451 $field_obj->sanitize_value( $value );
452 }
453
454 /**
455 * @since 4.02.04
456 *
457 * @param int|string $field_id Field ID.
458 * @param array $args Additional arguments.
459 *
460 * @return mixed
461 */
462 private static function get_posted_meta( $field_id, $args ) {
463 if ( empty( $args['parent_field_id'] ) ) {
464 // Sanitizing is done next.
465 $value = isset( $_POST['item_meta'][ $field_id ] ) ? wp_unslash( $_POST['item_meta'][ $field_id ] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
466 } else {
467 $value = isset( $_POST['item_meta'][ $args['parent_field_id'] ][ $args['key_pointer'] ][ $field_id ] ) ? wp_unslash( $_POST['item_meta'][ $args['parent_field_id'] ][ $args['key_pointer'] ][ $field_id ] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
468 }
469 return $value;
470 }
471
472 /**
473 * Check if field has an "Other" option and if any other values are posted
474 *
475 * @since 2.0
476 *
477 * @param object $field Field object.
478 * @param array|string $value Field value, passed by reference.
479 * @param array $args Arguments array, passed by reference.
480 *
481 * @return void
482 */
483 public static function maybe_set_other_validation( $field, &$value, &$args ) {
484 $args['other'] = false;
485
486 if ( ! $value || ! FrmAppHelper::pro_is_installed() ) {
487 return;
488 }
489
490 // Trim excess values if selection limit is exceeded for checkbox. Necessary to do here
491 // as the value set here will be used later in this class's set_posted_value() method.
492 if ( FrmField::is_checkbox( $field ) ) {
493 $field_obj = FrmFieldFactory::get_field_object( $field );
494 $field_obj->maybe_trim_excess_values( $value );
495 }
496
497 // Get other value for fields in repeating section.
498 self::set_other_repeating_vals( $field, $value, $args );
499
500 // Check if there are any posted "Other" values.
501 if ( FrmField::is_option_true( $field, 'other' ) && isset( $_POST['item_meta']['other'][ $field->id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
502
503 // Save original value.
504 $args['temp_value'] = $value;
505 $args['other'] = true;
506
507 // Sanitizing is done next.
508 $other_vals = wp_unslash( $_POST['item_meta']['other'][ $field->id ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
509 FrmAppHelper::sanitize_value( 'sanitize_text_field', $other_vals );
510
511 // Set the validation value now
512 self::set_other_validation_val( $value, $other_vals, $field, $args );
513 }
514 }
515
516 /**
517 * Sets radio or checkbox value equal to "other" value if it is set - FOR REPEATING SECTIONS
518 *
519 * @since 2.0
520 *
521 * @param object $field Field object.
522 * @param array|string $value Field value, passed by reference.
523 * @param array $args Arguments array, passed by reference.
524 *
525 * @return void
526 */
527 public static function set_other_repeating_vals( $field, &$value, &$args ) {
528 if ( ! $args['parent_field_id'] ) {
529 return;
530 }
531
532 // Check if there are any other posted "other" values for this field.
533 if ( FrmField::is_option_true( $field, 'other' ) && isset( $_POST['item_meta'][ $args['parent_field_id'] ][ $args['key_pointer'] ]['other'][ $field->id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
534 // Save original value
535 $args['temp_value'] = $value;
536 $args['other'] = true;
537
538 $other_vals = wp_unslash( $_POST['item_meta'][ $args['parent_field_id'] ][ $args['key_pointer'] ]['other'][ $field->id ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
539 FrmAppHelper::sanitize_value( 'sanitize_text_field', $other_vals );
540
541 // Set the validation value now.
542 self::set_other_validation_val( $value, $other_vals, $field, $args );
543 }
544 }
545
546 /**
547 * Modify value used for validation
548 * This function essentially removes the "Other" radio or checkbox value from the $value being validated.
549 * It also adds any text from the free text fields to the value
550 *
551 * Needs to accommodate for times when other opt is selected, but no other free text is entered
552 *
553 * @since 2.0
554 *
555 * @param array|string $value
556 * @param array|string $other_vals (usually of posted values).
557 * @param object $field
558 * @param array $args
559 *
560 * @return void
561 */
562 public static function set_other_validation_val( &$value, $other_vals, $field, &$args ) {
563 // Checkboxes and multi-select dropdowns.
564 if ( is_array( $value ) && $field->type === 'checkbox' ) {
565 // Combine "Other" values with checked values. "Other" values will override checked box values.
566 foreach ( $other_vals as $k => $v ) {
567 if ( isset( $value[ $k ] ) && trim( $v ) === '' ) {
568 // If the other box is checked, but doesn't have a value.
569 $value = '';
570 break;
571 }
572 }
573
574 if ( is_array( $value ) && ! empty( $value ) ) {
575 $value = array_merge( $value, $other_vals );
576 }
577 } else {
578 // Radio and dropdowns.
579 $other_key = array_filter( array_keys( $field->options ), 'is_string' );
580 $other_key = reset( $other_key );
581
582 // Multi-select dropdown.
583 if ( is_array( $value ) ) {
584 $o_key = array_search( $field->options[ $other_key ], $value );
585
586 if ( $o_key !== false ) {
587 // Modify the original value so other key will be preserved.
588 $value[ $other_key ] = $value[ $o_key ];
589
590 // By default, the array keys will be numeric for multi-select dropdowns.
591 // If going backwards and forwards between pages, the array key will match the other key.
592 if ( $o_key !== $other_key ) {
593 unset( $value[ $o_key ] );
594 }
595
596 $args['temp_value'] = $value;
597 $value[ $other_key ] = reset( $other_vals );
598
599 if ( FrmAppHelper::is_empty_value( $value[ $other_key ] ) ) {
600 unset( $value[ $other_key ] );
601 }
602 }
603 } elseif ( $field->options[ $other_key ] == $value ) {
604 $value = $other_vals;
605 }//end if
606 }//end if
607 }
608
609 /**
610 * Add submitted values to a string for spam checking.
611 *
612 * @param array $values
613 *
614 * @return string
615 */
616 public static function entry_array_to_string( $values ) {
617 $content = '';
618
619 foreach ( $values['item_meta'] as $val ) {
620 if ( $content !== '' ) {
621 $content .= "\n\n";
622 }
623
624 if ( is_array( $val ) ) {
625 $val = FrmAppHelper::array_flatten( $val );
626 $val = implode( ', ', $val );
627 }
628
629 $content .= $val;
630 }
631
632 return $content;
633 }
634
635 /**
636 * Get the browser from the user agent
637 *
638 * @since 2.04
639 *
640 * @param string $u_agent
641 *
642 * @return string
643 */
644 public static function get_browser( $u_agent ) {
645 $bname = __( 'Unknown', 'formidable' );
646 $platform = $bname;
647 $ub = '';
648
649 // Get the operating system
650 if ( preg_match( '/windows|win32/i', $u_agent ) ) {
651 $platform = 'Windows';
652 } elseif ( preg_match( '/android/i', $u_agent ) ) {
653 $platform = 'Android';
654 } elseif ( preg_match( '/linux/i', $u_agent ) ) {
655 $platform = 'Linux';
656 } elseif ( preg_match( '/macintosh|mac os x/i', $u_agent ) ) {
657 $platform = 'OS X';
658 }
659
660 $agent_options = array(
661 'Chrome' => 'Google Chrome',
662 'Safari' => 'Apple Safari',
663 'Opera' => 'Opera',
664 'Netscape' => 'Netscape',
665 'Firefox' => 'Mozilla Firefox',
666 );
667
668 // Next get the name of the useragent yes separately and for good reason.
669 if ( strpos( $u_agent, 'MSIE' ) !== false && strpos( $u_agent, 'Opera' ) === false ) {
670 $bname = 'Internet Explorer';
671 $ub = 'MSIE';
672 } else {
673 foreach ( $agent_options as $agent_key => $agent_name ) {
674 if ( strpos( $u_agent, $agent_key ) !== false ) {
675 $bname = $agent_name;
676 $ub = $agent_key;
677 break;
678 }
679 }
680 }
681
682 // finally get the correct version number
683 $known = array( 'Version', $ub, 'other' );
684 $pattern = '#(?<browser>' . implode( '|', $known ) . ')[/ ]+(?<version>[0-9.|a-zA-Z.]*)#';
685 // Get the matching numbers.
686 preg_match_all( $pattern, $u_agent, $matches );
687
688 // see how many we have
689 $i = count( $matches['browser'] );
690
691 if ( $i > 1 ) {
692 // We will have two since we are not using 'other' argument yet
693 // see if version is before or after the name.
694 if ( strripos( $u_agent, 'Version' ) < strripos( $u_agent, $ub ) ) {
695 $version = $matches['version'][0];
696 } else {
697 $version = $matches['version'][1];
698 }
699 } elseif ( $i === 1 ) {
700 $version = $matches['version'][0];
701 } else {
702 $version = '';
703 }
704
705 // check if we have a number
706 if ( $version === '' ) {
707 $version = '?';
708 }
709
710 return $bname . ' ' . $version . ' / ' . $platform;
711 }
712
713 /**
714 * @since 3.0
715 *
716 * @param array $atts Action dropdown attributes.
717 *
718 * @return void
719 */
720 public static function actions_dropdown( $atts ) {
721 $id = $atts['id'] ?? FrmAppHelper::get_param( 'id', 0, 'get', 'absint' );
722 $links = self::get_action_links( $id, $atts['entry'] );
723
724 foreach ( $links as $link ) {
725 ?>
726 <div class="misc-pub-section">
727 <a href="<?php echo esc_url( $link['url'] ); ?>"
728 <?php
729 if ( isset( $link['data'] ) ) {
730 foreach ( $link['data'] as $data => $value ) {
731 echo 'data-' . esc_attr( $data ) . '="' . esc_attr( $value ) . '" ';
732 }
733 }
734
735 if ( isset( $link['class'] ) ) {
736 echo 'class="' . esc_attr( $link['class'] ) . '" ';
737 }
738
739 if ( isset( $link['id'] ) ) {
740 echo 'id="' . esc_attr( $link['id'] ) . '" ';
741 }
742 ?>
743 >
744 <?php FrmAppHelper::icon_by_class( $link['icon'], array( 'aria-hidden' => 'true' ) ); ?>
745 <span class="frm_link_label"><?php echo esc_html( $link['label'] ); ?></span>
746 </a>
747 </div>
748 <?php
749 }//end foreach
750 }
751
752 /**
753 * @since 3.0
754 *
755 * @param int $id Entry ID.
756 * @param array|object $entry Entry object.
757 *
758 * @return array
759 */
760 private static function get_action_links( $id, $entry ) {
761 $page = FrmAppHelper::get_param( 'frm_action' );
762 $actions = array();
763
764 if ( $page !== 'show' ) {
765 $actions['frm_view'] = array(
766 'url' => admin_url( 'admin.php?page=formidable-entries&frm_action=show&id=' . $id . '&form=' . $entry->form_id ),
767 'label' => __( 'View Entry', 'formidable' ),
768 'icon' => 'frm_icon_font frm_save_icon',
769 );
770 }
771
772 if ( current_user_can( 'frm_delete_entries' ) ) {
773 $actions['frm_delete'] = array(
774 'url' => wp_nonce_url( admin_url( 'admin.php?page=formidable-entries&frm_action=destroy&id=' . $id . '&form=' . $entry->form_id ) ),
775 'label' => __( 'Delete Entry', 'formidable' ),
776 'icon' => 'frm_icon_font frm_delete_icon',
777 'data' => array(
778 'frmverify' => __( 'Permanently delete this entry?', 'formidable' ),
779 'frmverify-btn' => 'frm-button-red',
780 ),
781 );
782 }
783
784 if ( $page === 'show' ) {
785 $actions['frm_print'] = array(
786 'url' => '#',
787 'label' => __( 'Print Entry', 'formidable' ),
788 'data' => array(
789 'frmprint' => '1',
790 ),
791 'icon' => 'frm_icon_font frm_printer_icon',
792 );
793 }
794
795 $actions['frm_resend'] = array(
796 'url' => '#',
797 'label' => __( 'Resend Emails', 'formidable' ),
798 'class' => 'frm_noallow',
799 'data' => array(
800 'upgrade' => __( 'Resend Emails', 'formidable' ),
801 'medium' => 'resend-email',
802 'content' => 'entry',
803 ),
804 'icon' => 'frm_icon_font frm_email_icon',
805 );
806
807 if ( ! function_exists( 'frm_pdfs_autoloader' ) ) {
808 $actions['frm_download_pdf'] = array(
809 'url' => '#',
810 'label' => __( 'Download as PDF', 'formidable' ),
811 'class' => 'frm_noallow',
812 'data' => self::get_pdfs_upgrade_link_data( 'download-pdf-entry' ),
813 'icon' => 'frm_icon_font frm_download_icon',
814 );
815 }
816
817 $actions['frm_edit'] = array(
818 'url' => '#',
819 'label' => __( 'Edit Entry', 'formidable' ),
820 'class' => 'frm_noallow',
821 'data' => array(
822 'upgrade' => __( 'Entry edits', 'formidable' ),
823 'medium' => 'edit-entries',
824 'content' => 'entry',
825 ),
826 'icon' => 'frm_icon_font frm_pencil_icon',
827 );
828
829 return apply_filters( 'frm_entry_actions_dropdown', $actions, compact( 'id', 'entry' ) );
830 }
831
832 /**
833 * Gets data attributes for PDFs addon upgrade link.
834 *
835 * @param string $medium The source of the upgrade link used for analytics data.
836 *
837 * @return array
838 */
839 private static function get_pdfs_upgrade_link_data( $medium = 'pdfs' ) {
840 $data = array(
841 'oneclick' => '',
842 'requires' => '',
843 'upgrade' => __( 'Forms to PDF', 'formidable' ),
844 'medium' => $medium,
845 );
846
847 $upgrading = FrmAddonsController::install_link( 'pdfs' );
848
849 if ( isset( $upgrading['url'] ) ) {
850 $data['oneclick'] = json_encode( $upgrading );
851 } else {
852 $data['requires'] = FrmAddonsController::get_addon_required_plan( 28136428 );
853 }
854
855 return $data;
856 }
857
858 /**
859 * @since 5.0.15
860 *
861 * @param int|string $entry_id
862 *
863 * @return void
864 */
865 public static function maybe_render_captcha_score( $entry_id ) {
866 $query = array(
867 'item_id' => (int) $entry_id,
868 'field_id' => 0,
869 );
870 $metas_without_a_field = (array) FrmEntryMeta::getAll( $query, ' ORDER BY it.created_at DESC', '', true );
871
872 foreach ( $metas_without_a_field as $meta ) {
873 if ( ! empty( $meta->meta_value['captcha_score'] ) ) {
874 echo '<div class="misc-pub-section">';
875 FrmAppHelper::icon_by_class( 'frm_icon_font frm_shield_check_icon', array( 'aria-hidden' => 'true' ) );
876 echo ' ' . esc_html__( 'reCAPTCHA Score', 'formidable' ) . ': ';
877 echo '<b>' . esc_html( $meta->meta_value['captcha_score'] ) . '</b>';
878 echo '</div>';
879 return;
880 }
881 }
882 }
883
884 /**
885 * Return entry status based on is_draft column value.
886 *
887 * @since 6.5
888 *
889 * @param int $status is_draft column.
890 *
891 * @return int
892 */
893 public static function get_entry_status( $status ) {
894 $statuses = self::get_entry_statuses();
895
896 if ( array_key_exists( $status, $statuses ) ) {
897 return $status;
898 }
899
900 if ( empty( $status ) ) {
901 // If the status is empty, let's default to 0.
902 return self::SUBMITTED_ENTRY_STATUS;
903 }
904
905 // If it has a value that isn't in the array, let's default to 1. There may be old entries that don't have a value for is_draft.
906 return self::DRAFT_ENTRY_STATUS;
907 }
908
909 /**
910 * Return entry status label based on passed value.
911 *
912 * @since 6.5
913 *
914 * @param int $status is_draft column.
915 *
916 * @return string
917 */
918 public static function get_entry_status_label( $status ) {
919 $statuses = self::get_entry_statuses();
920
921 return $statuses[ self::get_entry_status( $status ) ];
922 }
923
924 /**
925 * Get all entry statuses.
926 *
927 * @since 6.5
928 * @since 6.6 function went from private to public.
929 *
930 * @return array<string>
931 */
932 public static function get_entry_statuses() {
933
934 $default_entry_statuses = array(
935 self::SUBMITTED_ENTRY_STATUS => __( 'Submitted', 'formidable' ),
936 self::DRAFT_ENTRY_STATUS => __( 'Draft', 'formidable' ),
937 );
938
939 /**
940 * Register entry status.
941 *
942 * "2" is used in abandonment-addon and reserved for "In progress".
943 * "3" is used in abandonment-addon and reserved for "Abandoned".
944 *
945 * @since 6.5
946 *
947 * @param array<string> $extended_entry_status Entry statuses.
948 */
949 $extended_entry_status = apply_filters( 'frm_entry_statuses', array() );
950
951 if ( ! is_array( $extended_entry_status ) ) {
952 _doing_it_wrong( __METHOD__, esc_html__( 'Entry status must be return in array format.', 'formidable' ), '6.5' );
953 $extended_entry_status = array();
954 }
955
956 $existing_entry_statuses = array_replace( $default_entry_statuses, $extended_entry_status );
957
958 return $existing_entry_statuses;
959 }
960
961 /**
962 * @since 6.17
963 *
964 * @return int
965 */
966 public static function get_visible_unread_inbox_count() {
967 $menu_name = FrmAppHelper::get_menu_name();
968
969 if ( ! in_array( $menu_name, array( 'Formidable', 'Forms' ), true ) ) {
970 return 0;
971 }
972
973 $inbox = new FrmInbox();
974 $inbox_count = count( $inbox->unread() );
975
976 if ( ! $inbox_count ) {
977 return 0;
978 }
979
980 if ( is_callable( 'FrmProSettingsController::inbox_badge' ) ) {
981 $inbox_count = FrmProSettingsController::inbox_badge( $inbox_count );
982
983 if ( ! $inbox_count ) {
984 return 0;
985 }
986 }
987
988 return $inbox_count;
989 }
990 }
991