PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.28
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.28
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 / controllers / FrmEntriesController.php

FrmEntriesController.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.28, at classes/controllers/FrmEntriesController.php

978 lines 26.2 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 FrmEntriesController {
7
8 /**
9 * @return void
10 */
11 public static function menu() {
12 FrmAppHelper::force_capability( 'frm_view_entries' );
13
14 add_submenu_page( 'formidable', 'Formidable | ' . __( 'Entries', 'formidable' ), __( 'Entries', 'formidable' ), 'frm_view_entries', 'formidable-entries', 'FrmEntriesController::route' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
15
16 $views_installed = is_callable( 'FrmProAppHelper::views_is_installed' ) && FrmProAppHelper::views_is_installed();
17
18 if ( ! $views_installed ) {
19 add_submenu_page( 'formidable', 'Formidable | ' . __( 'Views', 'formidable' ), __( 'Views', 'formidable' ), 'frm_view_entries', 'formidable-views', 'FrmFormsController::no_views' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
20 self::maybe_redirect_to_views_upsell();
21 } else {
22 self::maybe_redirect_to_views_index();
23 }
24
25 if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) ) {
26 self::load_manage_entries_hooks();
27 }
28 }
29
30 /**
31 * This function is called when views is installed.
32 * The Views add-on uses a different URL for the Views tab than the upsell page.
33 * If the user is on the upsell page, instead of showing a permission error on reload,
34 * redirect to the views index page.
35 *
36 * @since 6.14.1
37 *
38 * @return void
39 */
40 private static function maybe_redirect_to_views_index() {
41 if ( ! FrmAppHelper::is_admin_page( 'formidable-views' ) ) {
42 return;
43 }
44
45 $query_args = array(
46 'post_type' => 'frm_display',
47 );
48 $query_args = self::add_url_params_to_views_redirect_query_args( $query_args );
49
50 wp_safe_redirect( add_query_arg( $query_args, admin_url( 'edit.php' ) ) );
51 die();
52 }
53
54 /**
55 * This function is called when views is inactive.
56 * A user may deactivate views but then try to reload the views index.
57 * Instead of showing a permission error, redirect to the views upsell page.
58 *
59 * @since 6.14.1
60 *
61 * @return void
62 */
63 private static function maybe_redirect_to_views_upsell() {
64 global $pagenow;
65
66 if ( 'edit.php' !== $pagenow || 'frm_display' !== FrmAppHelper::simple_get( 'post_type' ) ) {
67 return;
68 }
69
70 $query_args = array(
71 'page' => 'formidable-views',
72 );
73 $query_args = self::add_url_params_to_views_redirect_query_args( $query_args );
74
75 wp_safe_redirect( add_query_arg( $query_args, admin_url( 'admin.php' ) ) );
76 die();
77 }
78
79 /**
80 * @since 6.14.1
81 *
82 * @param array $query_args
83 *
84 * @return array
85 */
86 private static function add_url_params_to_views_redirect_query_args( $query_args ) {
87 $query_args['show_nav'] = FrmAppHelper::simple_get( 'show_nav', 'absint', 0 );
88 $form_id = FrmAppHelper::simple_get( 'form', 'absint', 0 );
89
90 if ( $form_id ) {
91 $query_args['form'] = $form_id;
92 }
93
94 return $query_args;
95 }
96
97 /**
98 * @since 2.05.07
99 *
100 * @return void
101 */
102 private static function load_manage_entries_hooks() {
103 if ( ! in_array( FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' ), array( 'edit', 'show', 'new', 'duplicate' ), true ) ) {
104 $menu_name = FrmAppHelper::get_menu_name();
105 $base = self::base_column_key( $menu_name );
106
107 add_filter( 'manage_' . $base . '_columns', 'FrmEntriesController::manage_columns' );
108 add_filter( 'get_user_option_' . self::hidden_column_key( $menu_name ), 'FrmEntriesController::hidden_columns' );
109 add_filter( 'manage_' . $base . '_sortable_columns', 'FrmEntriesController::sortable_columns' );
110 } else {
111 add_filter( 'screen_options_show_screen', self::class . '::remove_screen_options', 10, 2 );
112 }
113 }
114
115 /**
116 * Display in Back End.
117 *
118 * @return mixed
119 */
120 public static function route() {
121 $action = FrmAppHelper::get_param( 'frm_action', '', 'get', 'sanitize_title' );
122 FrmAppHelper::include_svg();
123
124 switch ( $action ) {
125 case 'show':
126 case 'destroy':
127 return self::$action();
128
129 default:
130 do_action( 'frm_entry_action_route', $action );
131
132 if ( apply_filters( 'frm_entry_stop_action_route', false, $action ) ) {
133 return null;
134 }
135
136 self::display_list();
137 return null;
138 }
139 }
140
141 /**
142 * Prevent the "screen options" tab from showing when
143 * editing or creating an entry
144 *
145 * @since 3.0
146 *
147 * @param bool $show_screen Whether to show the screen options tab.
148 * @param object $screen The current screen object.
149 *
150 * @return bool
151 */
152 public static function remove_screen_options( $show_screen, $screen ) {
153 $menu_name = sanitize_title( FrmAppHelper::get_menu_name() );
154 $unread_count = FrmEntriesHelper::get_visible_unread_inbox_count();
155
156 if ( $screen->id === $menu_name . ( $unread_count ? '-' . $unread_count : '' ) . '_page_formidable-entries' ) {
157 return false;
158 }
159
160 return $show_screen;
161 }
162
163 /**
164 * @param array $columns
165 *
166 * @return array
167 */
168 public static function manage_columns( $columns ) {
169 global $frm_vars;
170 $form_id = FrmForm::get_current_form_id();
171
172 $columns[ $form_id . '_id' ] = 'ID';
173 $columns[ $form_id . '_item_key' ] = esc_html__( 'Entry Key', 'formidable' );
174
175 if ( $form_id ) {
176 self::get_columns_for_form( $form_id, $columns );
177 } else {
178 $columns[ $form_id . '_form_id' ] = esc_html__( 'Form', 'formidable' );
179 $columns[ $form_id . '_name' ] = esc_html__( 'Entry Name', 'formidable' );
180 $columns[ $form_id . '_user_id' ] = esc_html__( 'Created By', 'formidable' );
181 }
182
183 $columns[ $form_id . '_is_draft' ] = esc_html__( 'Entry Status', 'formidable' );
184 $columns[ $form_id . '_created_at' ] = __( 'Entry creation date', 'formidable' );
185 $columns[ $form_id . '_updated_at' ] = __( 'Entry update date', 'formidable' );
186 self::maybe_add_ip_col( $form_id, $columns );
187
188 $frm_vars['cols'] = $columns;
189 $action = FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
190
191 if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) && in_array( $action, array( '', 'list', 'destroy' ), true ) ) {
192 add_screen_option(
193 'per_page',
194 array(
195 'label' => esc_html__( 'Entries', 'formidable' ),
196 'default' => 20,
197 'option' => 'formidable_page_formidable_entries_per_page',
198 )
199 );
200 }
201
202 return $columns;
203 }
204
205 /**
206 * @param int|string $form_id
207 * @param array $columns
208 *
209 * @return void
210 */
211 private static function get_columns_for_form( $form_id, &$columns ) {
212 $form_cols = FrmField::get_all_for_form( $form_id, '', 'include' );
213
214 /**
215 * Allows changing fields in the Entries list table heading.
216 *
217 * @since 5.0.04
218 *
219 * @param array $fields Array of fields.
220 * @param array $args The arguments. Contains `form_id`.
221 */
222 $form_cols = apply_filters( 'frm_fields_in_entries_list_table', $form_cols, compact( 'form_id' ) );
223
224 foreach ( $form_cols as $form_col ) {
225 if ( FrmField::is_no_save_field( $form_col->type ) ) {
226 continue;
227 }
228
229 $has_child_fields = $form_col->type === 'form' && ! empty( $form_col->field_options['form_select'] );
230
231 if ( $has_child_fields ) {
232 self::add_subform_cols( $form_col, $form_id, $columns );
233 } else {
234 self::add_field_cols( $form_col, $form_id, $columns );
235 }
236 }
237 }
238
239 /**
240 * @since 3.01
241 *
242 * @param object $field The field object.
243 * @param int|string $form_id The form ID.
244 * @param array $columns The columns array.
245 *
246 * @return void
247 */
248 private static function add_subform_cols( $field, $form_id, &$columns ) {
249 $sub_form_cols = FrmField::get_all_for_form( $field->field_options['form_select'] );
250
251 if ( ! $sub_form_cols ) {
252 return;
253 }
254
255 foreach ( $sub_form_cols as $k => $sub_form_col ) {
256 if ( FrmField::is_no_save_field( $sub_form_col->type ) ) {
257 unset( $sub_form_cols[ $k ] );
258 continue;
259 }
260
261 $columns[ $form_id . '_' . $sub_form_col->field_key . '-_-' . $field->id ] = FrmAppHelper::truncate( $sub_form_col->name, 35 );
262 unset( $sub_form_col );
263 }
264 }
265
266 /**
267 * @since 3.01
268 *
269 * @param object $field The field object.
270 * @param int|string $form_id The form ID.
271 * @param array $columns The columns array.
272 *
273 * @return void
274 */
275 private static function add_field_cols( $field, $form_id, &$columns ) {
276 $col_id = $field->field_key;
277
278 if ( (int) $field->form_id !== (int) $form_id ) {
279 $col_id .= '-_-form' . $field->form_id;
280 }
281
282 $has_separate_value = ! FrmField::is_option_empty( $field, 'separate_value' );
283 $is_post_status = FrmField::is_option_true( $field, 'post_field' ) && $field->field_options['post_field'] === 'post_status';
284 $include_column_for_sep_val = $has_separate_value && ! $is_post_status;
285
286 if ( $include_column_for_sep_val ) {
287 $columns[ $form_id . '_frmsep_' . $col_id ] = self::maybe_format_field_name_for_column_title( $field, $include_column_for_sep_val );
288 }
289
290 $columns[ $form_id . '_' . $col_id ] = self::maybe_format_field_name_for_column_title( $field, $include_column_for_sep_val, false );
291 }
292
293 /**
294 * Appends "(Value)" or "(Label)" to the field name if it's an option field that has a separate value/label.
295 *
296 * @since 6.25.1
297 *
298 * @param object $field
299 * @param bool $include_column_for_sep_val
300 * @param bool $is_value
301 *
302 * @return string
303 */
304 private static function maybe_format_field_name_for_column_title( $field, $include_column_for_sep_val, $is_value = true ) {
305 $field_name = FrmAppHelper::truncate( $field->name, 35 );
306
307 if ( ! $include_column_for_sep_val || ! in_array( $field->type, array( 'select', 'radio', 'checkbox' ), true ) ) {
308 return $field_name;
309 }
310
311 $append_text = $is_value ? esc_html__( 'value', 'formidable' ) : esc_html__( 'label', 'formidable' );
312
313 return sprintf( '%s (%s)', $field_name, $append_text );
314 }
315
316 /**
317 * @param int|string $form_id The form ID.
318 * @param array $columns The columns array.
319 *
320 * @return void
321 */
322 private static function maybe_add_ip_col( $form_id, &$columns ) {
323 if ( FrmAppHelper::ips_saved() ) {
324 $columns[ $form_id . '_ip' ] = 'IP';
325 }
326 }
327
328 /**
329 * @param bool $check The check value.
330 * @param int $object_id The object ID.
331 * @param string $meta_key The meta key.
332 * @param mixed $meta_value The meta value.
333 * @param mixed $prev_value The previous value.
334 *
335 * @return bool
336 */
337 public static function check_hidden_cols( $check, $object_id, $meta_key, $meta_value, $prev_value ) {
338 $this_page_name = self::hidden_column_key();
339
340 // phpcs:ignore Universal.Operators.StrictComparisons
341 if ( $meta_key != $this_page_name || $meta_value == $prev_value ) {
342 return $check;
343 }
344
345 if ( ! $prev_value ) {
346 $prev_value = get_metadata( 'user', $object_id, $meta_key, true );
347 }
348
349 global $frm_vars;
350 // Add a check so we don't create a loop.
351 $frm_vars['prev_hidden_cols'] = ! empty( $frm_vars['prev_hidden_cols'] ) ? false : $prev_value;
352
353 return $check;
354 }
355
356 /**
357 * Add hidden columns back from other forms
358 *
359 * @param int $meta_id The meta ID.
360 * @param int $object_id The object ID.
361 * @param string $meta_key The meta key.
362 * @param array $meta_value The meta value.
363 *
364 * @return void
365 */
366 public static function update_hidden_cols( $meta_id, $object_id, $meta_key, $meta_value ) {
367 $this_page_name = self::hidden_column_key();
368
369 // phpcs:ignore Universal.Operators.StrictComparisons
370 if ( $meta_key != $this_page_name ) {
371 return;
372 }
373
374 global $frm_vars;
375
376 if ( empty( $frm_vars['prev_hidden_cols'] ) ) {
377 // Don't continue if there's no previous value.
378 return;
379 }
380
381 foreach ( $meta_value as $mk => $mv ) {
382 // Remove blank values.
383 if ( ! $mv ) {
384 unset( $meta_value[ $mk ] );
385 }
386 }
387
388 $cur_form_prefix = reset( $meta_value );
389 $cur_form_prefix = explode( '_', $cur_form_prefix );
390 $cur_form_prefix = $cur_form_prefix[0];
391 $save = false;
392
393 foreach ( (array) $frm_vars['prev_hidden_cols'] as $prev_hidden ) {
394 // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
395 if ( ! $prev_hidden || in_array( $prev_hidden, $meta_value ) ) {
396 // Don't add blank cols or process included cols.
397 continue;
398 }
399
400 $form_prefix = explode( '_', $prev_hidden );
401 $form_prefix = $form_prefix[0];
402
403 if ( $form_prefix === $cur_form_prefix ) {
404 // Don't add back columns that are meant to be hidden.
405 continue;
406 }
407
408 $meta_value[] = $prev_hidden;
409 $save = true;
410 unset( $form_prefix );
411 }
412
413 if ( ! $save ) {
414 return;
415 }
416
417 $user_id = get_current_user_id();
418 update_user_option( $user_id, $this_page_name, $meta_value, true );
419 }
420
421 /**
422 * @since 2.05.07
423 *
424 * @param string $menu_name
425 *
426 * @return string
427 */
428 private static function hidden_column_key( $menu_name = '' ) {
429 $base = self::base_column_key( $menu_name );
430 return 'manage' . $base . 'columnshidden';
431 }
432
433 /**
434 * @since 2.05.07
435 *
436 * @param string $menu_name
437 *
438 * @return string
439 */
440 private static function base_column_key( $menu_name = '' ) {
441 if ( ! $menu_name ) {
442 $menu_name = FrmAppHelper::get_menu_name();
443 }
444
445 $unread_count = FrmEntriesHelper::get_visible_unread_inbox_count();
446
447 return sanitize_title( $menu_name ) . ( $unread_count ? '-' . $unread_count : '' ) . '_page_formidable-entries';
448 }
449
450 /**
451 * @param int $save
452 * @param string $option
453 * @param string $value
454 *
455 * @return int
456 */
457 public static function save_per_page( $save, $option, $value ) {
458 if ( $option === 'formidable_page_formidable_entries_per_page' ) {
459 return (int) $value;
460 }
461
462 return $save;
463 }
464
465 /**
466 * @return array
467 */
468 public static function sortable_columns() {
469 $form_id = FrmForm::get_current_form_id();
470 $fields = FrmField::get_all_for_form( $form_id );
471
472 $columns = array(
473 $form_id . '_id' => 'id',
474 $form_id . '_created_at' => 'created_at',
475 $form_id . '_updated_at' => 'updated_at',
476 $form_id . '_ip' => 'ip',
477 $form_id . '_item_key' => 'item_key',
478 $form_id . '_is_draft' => 'is_draft',
479 );
480
481 if ( ! $form_id ) {
482 $columns[ $form_id . '_user_id' ] = 'user_id';
483 $columns[ $form_id . '_name' ] = 'name';
484 $columns[ $form_id . '_form_id' ] = 'form_id';
485 }
486
487 foreach ( $fields as $field ) {
488 if ( self::field_supports_sorting( $field ) ) {
489 $columns[ $form_id . '_' . $field->field_key ] = 'meta_' . $field->id;
490 }
491 }
492
493 return $columns;
494 }
495
496 /**
497 * Can't sort on checkboxes because they are sorted serialized.
498 * Some post content can be sorted but not everything.
499 *
500 * @param stdClass $field
501 *
502 * @return bool
503 */
504 private static function field_supports_sorting( $field ) {
505 $is_sortable = 'checkbox' !== $field->type && empty( $field->field_options['post_field'] );
506 return apply_filters( 'frm_field_column_is_sortable', $is_sortable, $field );
507 }
508
509 /**
510 * @param mixed $result Option value from database for hidden columns in entries table.
511 *
512 * @return array
513 */
514 public static function hidden_columns( $result ) {
515 global $frm_vars;
516
517 if ( ! is_array( $result ) ) {
518 // Force an unexpected value to be an array.
519 // Since $result is a filtered option and gets saved to the database, it's possible it could be a string.
520 // Since this code expects an array it would break with a "Uncaught Error: [] operator not supported for strings" error.
521 $result = array();
522 }
523
524 $form_id = FrmForm::get_current_form_id();
525 $hidden = self::user_hidden_columns_for_form( $form_id, $result );
526 $i = isset( $frm_vars['cols'] ) ? count( $frm_vars['cols'] ) : 0;
527 $max_columns = 11;
528
529 if ( $hidden ) {
530 $result = $hidden;
531 $i = $i - count( $result );
532 }
533
534 if ( $i <= $max_columns ) {
535 return $result;
536 }
537
538 self::remove_excess_cols( compact( 'i', 'max_columns', 'form_id' ), $result );
539
540 return $result;
541 }
542
543 /**
544 * @since 2.05.07
545 *
546 * @param int|string $form_id
547 * @param mixed $result
548 *
549 * @return array
550 */
551 private static function user_hidden_columns_for_form( $form_id, $result ) {
552 $hidden = array();
553
554 foreach ( (array) $result as $r ) {
555 if ( $r ) {
556 list( $form_prefix, $field_key ) = explode( '_', $r );
557
558 if ( (int) $form_prefix === (int) $form_id ) {
559 $hidden[] = $r;
560 }
561
562 unset( $form_prefix );
563 }
564 }
565
566 return $hidden;
567 }
568
569 /**
570 * Remove some columns by default when there are too many
571 *
572 * @since 2.05.07
573 *
574 * @param array $atts
575 * @param array $result
576 *
577 * @return void
578 */
579 private static function remove_excess_cols( $atts, &$result ) {
580 global $frm_vars;
581
582 $remove_first = array(
583 $atts['form_id'] . '_item_key' => '',
584 $atts['form_id'] . '_id' => '',
585 );
586 $cols = $remove_first + array_reverse( $frm_vars['cols'], true );
587 $i = $atts['i'];
588
589 foreach ( $cols as $col_key => $col ) {
590 if ( $i <= $atts['max_columns'] ) {
591 break;
592 }
593
594 if ( ! $result || ! in_array( $col_key, $result, true ) ) {
595 $result[] = $col_key;
596 --$i;
597 }
598
599 unset( $col_key, $col );
600 }
601 }
602
603 /**
604 * @param string $message
605 * @param array $errors
606 *
607 * @return void
608 */
609 public static function display_list( $message = '', $errors = array() ) {
610 global $wpdb, $frm_vars;
611
612 $form = FrmForm::maybe_get_current_form();
613 $params = FrmForm::get_admin_params( $form );
614
615 if ( $form ) {
616 $params['form'] = $form->id;
617 $frm_vars['current_form'] = $form;
618
619 self::get_delete_form_time( $form, $errors );
620 }
621
622 $table_class = apply_filters( 'frm_entries_list_class', 'FrmEntriesListHelper' );
623 $wp_list_table = new $table_class( array( 'params' => $params ) );
624 $pagenum = $wp_list_table->get_pagenum();
625
626 $wp_list_table->prepare_items();
627
628 $total_pages = $wp_list_table->get_pagination_arg( 'total_pages' );
629
630 if ( $pagenum > $total_pages && $total_pages > 0 ) {
631 $url = add_query_arg( 'paged', $total_pages );
632
633 if ( headers_sent() ) {
634 FrmAppHelper::js_redirect( $url, true );
635 } else {
636 wp_safe_redirect( esc_url_raw( $url ) );
637 }
638
639 die();
640 }
641
642 if ( ! $message && isset( $_GET['import-message'] ) ) {
643 $message = __( 'Your import is complete', 'formidable' );
644 }
645
646 require FrmAppHelper::plugin_path() . '/classes/views/frm-entries/list.php';
647 }
648
649 /**
650 * @param object $form
651 * @param array $errors
652 *
653 * @return void
654 */
655 private static function get_delete_form_time( $form, &$errors ) {
656 if ( 'trash' === $form->status ) {
657 $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
658 $time_to_delete = FrmAppHelper::human_time_diff( $delete_timestamp, $form->options['trash_time'] ?? time() );
659
660 /* translators: %1$s: Time string */
661 $errors['trash'] = sprintf( __( 'This form is in the trash and is scheduled to be deleted permanently in %s along with any entries.', 'formidable' ), $time_to_delete );
662 }
663 }
664
665 /**
666 * Back End CRUD.
667 *
668 * @param int $id
669 *
670 * @return void
671 */
672 public static function show( $id = 0 ) {
673 FrmAppHelper::permission_check( 'frm_view_entries' );
674
675 if ( ! $id ) {
676 $id = FrmAppHelper::get_param( 'id', 0, 'get', 'absint' );
677
678 if ( ! $id ) {
679 $id = FrmAppHelper::get_param( 'item_id', 0, 'get', 'absint' );
680 }
681 }
682
683 $entry = FrmEntry::getOne( $id, true );
684
685 if ( ! $entry ) {
686 FrmAppController::show_error_modal(
687 array(
688 'title' => __( 'You can\'t view the entry', 'formidable' ),
689 'body' => __( 'You are trying to view an entry that does not exist', 'formidable' ),
690 'cancel_url' => admin_url( 'admin.php?page=formidable' ),
691 )
692 );
693 return;
694 }
695
696 $data = $entry->description;
697
698 if ( ! is_array( $data ) || ! isset( $data['referrer'] ) ) {
699 $data = array( 'referrer' => $data );
700 }
701
702 $fields = FrmField::get_all_for_form( $entry->form_id, '', 'include' );
703 $form = FrmForm::getOne( $entry->form_id );
704
705 include FrmAppHelper::plugin_path() . '/classes/views/frm-entries/show.php';
706 }
707
708 /**
709 * Destroy an entry from the admin page.
710 * This is triggered from the entries list from the "Delete" row action, and also from the "Delete Entry" trigger in the view/edit entry sidebar.
711 *
712 * @return void
713 */
714 public static function destroy() {
715 $permission_error = FrmAppHelper::permission_nonce_error( 'frm_delete_entries', '_wpnonce', -1 );
716
717 if ( false !== $permission_error ) {
718 $error_args = array(
719 'title' => __( 'Verification failed', 'formidable' ),
720 'body' => $permission_error,
721 'cancel_url' => admin_url( 'admin.php?page=formidable-entries' ),
722 );
723 FrmAppController::show_error_modal( $error_args );
724 return;
725 }
726
727 $params = FrmForm::get_admin_params();
728
729 if ( ! empty( $params['keep_post'] ) ) {
730 self::unlink_post( $params['id'] );
731 }
732
733 $message = '';
734
735 if ( FrmEntry::destroy( $params['id'] ) ) {
736 $message = __( 'Entry was successfully deleted', 'formidable' );
737 }
738
739 self::display_list( $message );
740 }
741
742 /**
743 * @param array|string $errors
744 * @param bool $ajax
745 *
746 * @return void
747 */
748 public static function process_entry( $errors = '', $ajax = false ) {
749 $form_id = FrmAppHelper::get_post_param( 'form_id', '', 'absint' );
750
751 if ( FrmAppHelper::is_admin() || empty( $_POST ) || ! $form_id || ! isset( $_POST['item_key'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
752 return;
753 }
754
755 global $frm_vars;
756
757 $form = FrmForm::getOne( $form_id );
758
759 if ( ! $form ) {
760 return;
761 }
762
763 $is_preview = 'frm_forms_preview' === FrmAppHelper::simple_get( 'action' );
764
765 if ( $is_preview && FrmFormsHelper::should_block_preview( $form->form_key ) ) {
766 return;
767 }
768
769 $params = FrmForm::get_params( $form );
770
771 if ( ! isset( $frm_vars['form_params'] ) ) {
772 $frm_vars['form_params'] = array();
773 }
774 $frm_vars['form_params'][ $form->id ] = $params;
775
776 if ( isset( $frm_vars['created_entries'][ $form_id ] ) ) {
777 return;
778 }
779
780 // phpcs:ignore Universal.Operators.StrictComparisons
781 if ( $errors == '' && ! $ajax ) {
782 $errors = FrmEntryValidate::validate( wp_unslash( $_POST ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
783 }
784
785 /**
786 * Use this filter to add trigger actions and add errors after
787 * all other errors have been processed
788 *
789 * @since 2.0.6
790 */
791 $errors = apply_filters( 'frm_entries_before_create', $errors, $form );
792
793 $frm_vars['created_entries'][ $form_id ] = array( 'errors' => $errors );
794
795 if ( $errors ) {
796 return;
797 }
798
799 $_POST['frm_skip_cookie'] = 1;
800 $do_success = false;
801
802 if ( $params['action'] === 'create' ) {
803 if ( apply_filters( 'frm_continue_to_create', true, $form_id ) && ! isset( $frm_vars['created_entries'][ $form_id ]['entry_id'] ) ) {
804 $frm_vars['created_entries'][ $form_id ]['entry_id'] = FrmEntry::create( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
805
806 $params['id'] = $frm_vars['created_entries'][ $form_id ]['entry_id'];
807 $do_success = true;
808 }
809 }
810
811 do_action( 'frm_process_entry', $params, $errors, $form, array( 'ajax' => $ajax ) );
812
813 if ( $do_success ) {
814 FrmFormsController::maybe_trigger_redirect( $form, $params, array( 'ajax' => $ajax ) );
815 }
816 unset( $_POST['frm_skip_cookie'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
817 }
818
819 /**
820 * Escape url entities before redirect
821 *
822 * @since 3.0
823 *
824 * @param string $url
825 *
826 * @return string
827 */
828 public static function prepare_redirect_url( $url ) {
829 return str_replace( array( ' ', '[', ']', '|', '@' ), array( '%20', '%5B', '%5D', '%7C', '%40' ), $url );
830 }
831
832 /**
833 * Delete entry if redirected.
834 *
835 * @param string $url
836 * @param object $form
837 * @param array $atts
838 *
839 * @return string
840 */
841 public static function delete_entry_before_redirect( $url, $form, $atts ) {
842 self::_delete_entry( $atts['id'], $form );
843 return $url;
844 }
845
846 /**
847 * Delete entry if not redirected.
848 *
849 * @param array $atts
850 *
851 * @return void
852 */
853 public static function delete_entry_after_save( $atts ) {
854 self::_delete_entry( $atts['entry_id'], $atts['form'] );
855 }
856
857 /**
858 * Delete entry if not redirected.
859 *
860 * @param int $entry_id
861 * @param object $form
862 *
863 * @return void
864 */
865 private static function _delete_entry( $entry_id, $form ) {
866 if ( ! $form ) {
867 return;
868 }
869
870 FrmAppHelper::unserialize_or_decode( $form->options );
871
872 if ( empty( $form->options['no_save'] ) ) {
873 return;
874 }
875
876 self::unlink_post( $entry_id );
877 FrmEntry::destroy( $entry_id );
878 }
879
880 /**
881 * Unlink entry from post
882 *
883 * @param int $entry_id
884 *
885 * @return void
886 */
887 private static function unlink_post( $entry_id ) {
888 global $wpdb;
889 $wpdb->update( $wpdb->prefix . 'frm_items', array( 'post_id' => '' ), array( 'id' => $entry_id ) );
890 FrmEntry::clear_cache();
891 }
892
893 /**
894 * @param array $atts
895 *
896 * @return array|string
897 */
898 public static function show_entry_shortcode( $atts ) {
899 $defaults = array(
900 'id' => false,
901 'entry' => false,
902 'fields' => false,
903 'plain_text' => false,
904 'user_info' => false,
905 'include_blank' => false,
906 'default_email' => false,
907 'form_id' => false,
908 'format' => 'text',
909 'array_key' => 'key',
910 'direction' => 'ltr',
911 'font_size' => '',
912 'text_color' => '',
913 'border_width' => '',
914 'border_color' => '',
915 'bg_color' => '',
916 'alt_bg_color' => '',
917 'class' => '',
918 'clickable' => false,
919 'exclude_fields' => '',
920 'include_fields' => '',
921 'include_extras' => '',
922 'inline_style' => 1,
923 'table_style' => '',
924 // Return embedded fields as nested array.
925 'child_array' => false,
926 'line_breaks' => true,
927 'array_separator' => ', ',
928 );
929 $defaults = apply_filters( 'frm_show_entry_defaults', $defaults );
930 $atts = shortcode_atts( $defaults, $atts );
931
932 if ( $atts['default_email'] ) {
933 $shortcode_atts = array(
934 'format' => $atts['format'],
935 'plain_text' => $atts['plain_text'],
936 );
937 $entry_formatter = FrmEntryFactory::entry_shortcode_formatter_instance( $atts['form_id'], $shortcode_atts );
938 return $entry_formatter->content();
939 }
940
941 $entry_formatter = FrmEntryFactory::entry_formatter_instance( $atts );
942
943 return $entry_formatter->get_formatted_entry_values();
944 }
945
946 /**
947 * @param false|object $entry
948 *
949 * @return void
950 */
951 public static function entry_sidebar( $entry = false ) {
952 $data = array();
953 $id = 0;
954 $date_format = get_option( 'date_format' );
955 $time_format = get_option( 'time_format' );
956
957 if ( $entry ) {
958 $id = $entry->id;
959 $data = $entry->description;
960
961 if ( isset( $data['browser'] ) ) {
962 $browser = FrmEntriesHelper::get_browser( $data['browser'] );
963 }
964 /**
965 * Add or remove information in the entry sidebar.
966 *
967 * @since 5.5.2
968 *
969 * @param array $data
970 * @param array{entry:\stdClass} $entry
971 */
972 $data = apply_filters( 'frm_sidebar_data', $data, compact( 'entry' ) );
973 }
974
975 include FrmAppHelper::plugin_path() . '/classes/views/frm-entries/sidebar-shared.php';
976 }
977 }
978