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

980 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 self::maybe_redirect_to_views_index();
20 } else {
21 add_submenu_page( 'formidable', 'Formidable | ' . __( 'Views', 'formidable' ), __( 'Views', 'formidable' ), 'frm_view_entries', 'formidable-views', 'FrmFormsController::no_views' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
22 self::maybe_redirect_to_views_upsell();
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 add_filter( 'screen_options_show_screen', self::class . '::remove_screen_options', 10, 2 );
105 return;
106 }
107
108 $menu_name = FrmAppHelper::get_menu_name();
109 $base = self::base_column_key( $menu_name );
110
111 add_filter( 'manage_' . $base . '_columns', 'FrmEntriesController::manage_columns' );
112 add_filter( 'get_user_option_' . self::hidden_column_key( $menu_name ), 'FrmEntriesController::hidden_columns' );
113 add_filter( 'manage_' . $base . '_sortable_columns', 'FrmEntriesController::sortable_columns' );
114 }
115
116 /**
117 * Display in Back End.
118 *
119 * @return mixed
120 */
121 public static function route() {
122 $action = FrmAppHelper::get_param( 'frm_action', '', 'get', 'sanitize_title' );
123 FrmAppHelper::include_svg();
124
125 switch ( $action ) {
126 case 'show':
127 case 'destroy':
128 return self::$action();
129
130 default:
131 do_action( 'frm_entry_action_route', $action );
132
133 if ( apply_filters( 'frm_entry_stop_action_route', false, $action ) ) {
134 return null;
135 }
136
137 self::display_list();
138 return null;
139 }
140 }
141
142 /**
143 * Prevent the "screen options" tab from showing when
144 * editing or creating an entry
145 *
146 * @since 3.0
147 *
148 * @param bool $show_screen Whether to show the screen options tab.
149 * @param object $screen The current screen object.
150 *
151 * @return bool
152 */
153 public static function remove_screen_options( $show_screen, $screen ) {
154 $menu_name = sanitize_title( FrmAppHelper::get_menu_name() );
155 $unread_count = FrmEntriesHelper::get_visible_unread_inbox_count();
156
157 if ( $screen->id === $menu_name . ( $unread_count ? '-' . $unread_count : '' ) . '_page_formidable-entries' ) {
158 return false;
159 }
160
161 return $show_screen;
162 }
163
164 /**
165 * @param array $columns
166 *
167 * @return array
168 */
169 public static function manage_columns( $columns ) {
170 global $frm_vars;
171 $form_id = FrmForm::get_current_form_id();
172
173 $columns[ $form_id . '_id' ] = 'ID';
174 $columns[ $form_id . '_item_key' ] = esc_html__( 'Entry Key', 'formidable' );
175
176 if ( $form_id ) {
177 self::get_columns_for_form( $form_id, $columns );
178 } else {
179 $columns[ $form_id . '_form_id' ] = esc_html__( 'Form', 'formidable' );
180 $columns[ $form_id . '_name' ] = esc_html__( 'Entry Name', 'formidable' );
181 $columns[ $form_id . '_user_id' ] = esc_html__( 'Created By', 'formidable' );
182 }
183
184 $columns[ $form_id . '_is_draft' ] = esc_html__( 'Entry Status', 'formidable' );
185 $columns[ $form_id . '_created_at' ] = esc_html__( 'Entry creation date', 'formidable' );
186 $columns[ $form_id . '_updated_at' ] = esc_html__( 'Entry update date', 'formidable' );
187 self::maybe_add_ip_col( $form_id, $columns );
188
189 $frm_vars['cols'] = $columns;
190 $action = FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
191
192 if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) && in_array( $action, array( '', 'list', 'destroy' ), true ) ) {
193 add_screen_option(
194 'per_page',
195 array(
196 'label' => esc_html__( 'Entries', 'formidable' ),
197 'default' => 20,
198 'option' => 'formidable_page_formidable_entries_per_page',
199 )
200 );
201 }
202
203 return $columns;
204 }
205
206 /**
207 * @param int|string $form_id
208 * @param array $columns
209 *
210 * @return void
211 */
212 private static function get_columns_for_form( $form_id, &$columns ) {
213 $form_cols = FrmField::get_all_for_form( $form_id, '', 'include' );
214
215 /**
216 * Allows changing fields in the Entries list table heading.
217 *
218 * @since 5.0.04
219 *
220 * @param array $fields Array of fields.
221 * @param array $args The arguments. Contains `form_id`.
222 */
223 $form_cols = apply_filters( 'frm_fields_in_entries_list_table', $form_cols, compact( 'form_id' ) );
224
225 foreach ( $form_cols as $form_col ) {
226 if ( FrmField::is_no_save_field( $form_col->type ) ) {
227 continue;
228 }
229
230 $has_child_fields = $form_col->type === 'form' && ! empty( $form_col->field_options['form_select'] );
231
232 if ( $has_child_fields ) {
233 self::add_subform_cols( $form_col, $form_id, $columns );
234 } else {
235 self::add_field_cols( $form_col, $form_id, $columns );
236 }
237 }
238 }
239
240 /**
241 * @since 3.01
242 *
243 * @param object $field The field object.
244 * @param int|string $form_id The form ID.
245 * @param array $columns The columns array.
246 *
247 * @return void
248 */
249 private static function add_subform_cols( $field, $form_id, &$columns ) {
250 $sub_form_cols = FrmField::get_all_for_form( $field->field_options['form_select'] );
251
252 if ( ! $sub_form_cols ) {
253 return;
254 }
255
256 foreach ( $sub_form_cols as $k => $sub_form_col ) {
257 if ( FrmField::is_no_save_field( $sub_form_col->type ) ) {
258 unset( $sub_form_cols[ $k ] );
259 continue;
260 }
261
262 $columns[ $form_id . '_' . $sub_form_col->field_key . '-_-' . $field->id ] = FrmAppHelper::truncate( $sub_form_col->name, 35 );
263 unset( $sub_form_col );
264 }
265 }
266
267 /**
268 * @since 3.01
269 *
270 * @param object $field The field object.
271 * @param int|string $form_id The form ID.
272 * @param array $columns The columns array.
273 *
274 * @return void
275 */
276 private static function add_field_cols( $field, $form_id, &$columns ) {
277 $col_id = $field->field_key;
278
279 if ( (int) $field->form_id !== (int) $form_id ) {
280 $col_id .= '-_-form' . $field->form_id;
281 }
282
283 $has_separate_value = ! FrmField::is_option_empty( $field, 'separate_value' );
284 $is_post_status = FrmField::is_option_true( $field, 'post_field' ) && $field->field_options['post_field'] === 'post_status';
285 $include_column_for_sep_val = $has_separate_value && ! $is_post_status;
286
287 if ( $include_column_for_sep_val ) {
288 $columns[ $form_id . '_frmsep_' . $col_id ] = self::maybe_format_field_name_for_column_title( $field, $include_column_for_sep_val );
289 }
290
291 $columns[ $form_id . '_' . $col_id ] = self::maybe_format_field_name_for_column_title( $field, $include_column_for_sep_val, false );
292 }
293
294 /**
295 * Appends "(Value)" or "(Label)" to the field name if it's an option field that has a separate value/label.
296 *
297 * @since 6.25.1
298 *
299 * @param object $field
300 * @param bool $include_column_for_sep_val
301 * @param bool $is_value
302 *
303 * @return string
304 */
305 private static function maybe_format_field_name_for_column_title( $field, $include_column_for_sep_val, $is_value = true ) {
306 $field_name = FrmAppHelper::truncate( $field->name, 35 );
307
308 if ( ! $include_column_for_sep_val || ! in_array( $field->type, array( 'select', 'radio', 'checkbox', 'product', 'ranking' ), true ) ) {
309 return $field_name;
310 }
311
312 $append_text = $is_value ? esc_html__( 'value', 'formidable' ) : esc_html__( 'label', 'formidable' );
313
314 return sprintf( '%s (%s)', $field_name, $append_text );
315 }
316
317 /**
318 * @param int|string $form_id The form ID.
319 * @param array $columns The columns array.
320 *
321 * @return void
322 */
323 private static function maybe_add_ip_col( $form_id, &$columns ) {
324 if ( FrmAppHelper::ips_saved() ) {
325 $columns[ $form_id . '_ip' ] = 'IP';
326 }
327 }
328
329 /**
330 * @param bool $check The check value.
331 * @param int $object_id The object ID.
332 * @param string $meta_key The meta key.
333 * @param mixed $meta_value The meta value.
334 * @param mixed $prev_value The previous value.
335 *
336 * @return bool
337 */
338 public static function check_hidden_cols( $check, $object_id, $meta_key, $meta_value, $prev_value ) {
339 $this_page_name = self::hidden_column_key();
340
341 // phpcs:ignore Universal.Operators.StrictComparisons
342 if ( $meta_key != $this_page_name || $meta_value == $prev_value ) {
343 return $check;
344 }
345
346 if ( ! $prev_value ) {
347 $prev_value = get_metadata( 'user', $object_id, $meta_key, true );
348 }
349
350 global $frm_vars;
351 // Add a check so we don't create a loop.
352 $frm_vars['prev_hidden_cols'] = ! empty( $frm_vars['prev_hidden_cols'] ) ? false : $prev_value;
353
354 return $check;
355 }
356
357 /**
358 * Add hidden columns back from other forms
359 *
360 * @param int $meta_id The meta ID.
361 * @param int $object_id The object ID.
362 * @param string $meta_key The meta key.
363 * @param array $meta_value The meta value.
364 *
365 * @return void
366 */
367 public static function update_hidden_cols( $meta_id, $object_id, $meta_key, $meta_value ) {
368 $this_page_name = self::hidden_column_key();
369
370 // phpcs:ignore Universal.Operators.StrictComparisons
371 if ( $meta_key != $this_page_name ) {
372 return;
373 }
374
375 global $frm_vars;
376
377 if ( empty( $frm_vars['prev_hidden_cols'] ) ) {
378 // Don't continue if there's no previous value.
379 return;
380 }
381
382 foreach ( $meta_value as $mk => $mv ) {
383 // Remove blank values.
384 if ( ! $mv ) {
385 unset( $meta_value[ $mk ] );
386 }
387 }
388
389 $cur_form_prefix = reset( $meta_value );
390 $cur_form_prefix = explode( '_', $cur_form_prefix );
391 $cur_form_prefix = $cur_form_prefix[0];
392 $save = false;
393
394 foreach ( (array) $frm_vars['prev_hidden_cols'] as $prev_hidden ) {
395 // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
396 if ( ! $prev_hidden || in_array( $prev_hidden, $meta_value ) ) {
397 // Don't add blank cols or process included cols.
398 continue;
399 }
400
401 $form_prefix = explode( '_', $prev_hidden );
402 $form_prefix = $form_prefix[0];
403
404 if ( $form_prefix === $cur_form_prefix ) {
405 // Don't add back columns that are meant to be hidden.
406 continue;
407 }
408
409 $meta_value[] = $prev_hidden;
410 $save = true;
411 unset( $form_prefix );
412 }
413
414 if ( ! $save ) {
415 return;
416 }
417
418 update_user_option( get_current_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 continue;
557 }
558
559 list( $form_prefix, $field_key ) = explode( '_', $r );
560
561 if ( (int) $form_prefix === (int) $form_id ) {
562 $hidden[] = $r;
563 }
564
565 unset( $form_prefix );
566 }
567
568 return $hidden;
569 }
570
571 /**
572 * Remove some columns by default when there are too many
573 *
574 * @since 2.05.07
575 *
576 * @param array $atts
577 * @param array $result
578 *
579 * @return void
580 */
581 private static function remove_excess_cols( $atts, &$result ) {
582 global $frm_vars;
583
584 $remove_first = array(
585 $atts['form_id'] . '_item_key' => '',
586 $atts['form_id'] . '_id' => '',
587 );
588 $cols = $remove_first + array_reverse( $frm_vars['cols'], true );
589 $i = $atts['i'];
590
591 foreach ( $cols as $col_key => $col ) {
592 if ( $i <= $atts['max_columns'] ) {
593 break;
594 }
595
596 if ( ! $result || ! in_array( $col_key, $result, true ) ) {
597 $result[] = $col_key;
598 --$i;
599 }
600
601 unset( $col_key, $col );
602 }
603 }
604
605 /**
606 * @param string $message
607 * @param array $errors
608 *
609 * @return void
610 */
611 public static function display_list( $message = '', $errors = array() ) {
612 global $wpdb, $frm_vars;
613
614 $form = FrmForm::maybe_get_current_form();
615 $params = FrmForm::get_admin_params( $form );
616
617 if ( $form ) {
618 $params['form'] = $form->id;
619 $frm_vars['current_form'] = $form;
620
621 self::get_delete_form_time( $form, $errors );
622 }
623
624 $table_class = apply_filters( 'frm_entries_list_class', 'FrmEntriesListHelper' );
625 $wp_list_table = new $table_class( array( 'params' => $params ) );
626 $pagenum = $wp_list_table->get_pagenum();
627
628 $wp_list_table->prepare_items();
629
630 $total_pages = $wp_list_table->get_pagination_arg( 'total_pages' );
631
632 if ( $pagenum > $total_pages && $total_pages > 0 ) {
633 $url = add_query_arg( 'paged', $total_pages );
634
635 if ( headers_sent() ) {
636 FrmAppHelper::js_redirect( $url, true );
637 } else {
638 wp_safe_redirect( esc_url_raw( $url ) );
639 }
640
641 die();
642 }
643
644 if ( ! $message && isset( $_GET['import-message'] ) ) {
645 $message = __( 'Your import is complete', 'formidable' );
646 }
647
648 require FrmAppHelper::plugin_path() . '/classes/views/frm-entries/list.php';
649 }
650
651 /**
652 * @param object $form
653 * @param array $errors
654 *
655 * @return void
656 */
657 private static function get_delete_form_time( $form, &$errors ) {
658 if ( 'trash' !== $form->status ) {
659 return;
660 }
661
662 $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
663 $time_to_delete = FrmAppHelper::human_time_diff( $delete_timestamp, $form->options['trash_time'] ?? time() );
664
665 /* translators: %1$s: Time string */
666 $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 );
667 }
668
669 /**
670 * Back End CRUD.
671 *
672 * @param int $id
673 *
674 * @return void
675 */
676 public static function show( $id = 0 ) {
677 FrmAppHelper::permission_check( 'frm_view_entries' );
678
679 if ( ! $id ) {
680 $id = FrmAppHelper::get_param( 'id', 0, 'get', 'absint' );
681
682 if ( ! $id ) {
683 $id = FrmAppHelper::get_param( 'item_id', 0, 'get', 'absint' );
684 }
685 }
686
687 $entry = FrmEntry::getOne( $id, true );
688
689 if ( ! $entry ) {
690 FrmAppController::show_error_modal(
691 array(
692 'title' => __( 'You can\'t view the entry', 'formidable' ),
693 'body' => __( 'You are trying to view an entry that does not exist', 'formidable' ),
694 'cancel_url' => admin_url( 'admin.php?page=formidable' ),
695 )
696 );
697 return;
698 }
699
700 $data = $entry->description;
701
702 if ( ! is_array( $data ) || ! isset( $data['referrer'] ) ) {
703 $data = array( 'referrer' => $data );
704 }
705
706 $fields = FrmField::get_all_for_form( $entry->form_id, '', 'include' );
707 $form = FrmForm::getOne( $entry->form_id );
708
709 include FrmAppHelper::plugin_path() . '/classes/views/frm-entries/show.php';
710 }
711
712 /**
713 * Destroy an entry from the admin page.
714 * 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.
715 *
716 * @return void
717 */
718 public static function destroy() {
719 $permission_error = FrmAppHelper::permission_nonce_error( 'frm_delete_entries', '_wpnonce', -1 );
720
721 if ( false !== $permission_error ) {
722 $error_args = array(
723 'title' => __( 'Verification failed', 'formidable' ),
724 'body' => $permission_error,
725 'cancel_url' => admin_url( 'admin.php?page=formidable-entries' ),
726 );
727 FrmAppController::show_error_modal( $error_args );
728 return;
729 }
730
731 $params = FrmForm::get_admin_params();
732
733 if ( ! empty( $params['keep_post'] ) ) {
734 self::unlink_post( $params['id'] );
735 }
736
737 $message = '';
738
739 if ( FrmEntry::destroy( $params['id'] ) ) {
740 $message = __( 'Entry was successfully deleted', 'formidable' );
741 }
742
743 self::display_list( $message );
744 }
745
746 /**
747 * @param array|string $errors
748 * @param bool $ajax
749 *
750 * @return void
751 */
752 public static function process_entry( $errors = '', $ajax = false ) {
753 $form_id = FrmAppHelper::get_post_param( 'form_id', '', 'absint' );
754
755 if ( FrmAppHelper::is_admin() || empty( $_POST ) || ! $form_id || ! isset( $_POST['item_key'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
756 return;
757 }
758
759 global $frm_vars;
760
761 $form = FrmForm::getOne( $form_id );
762
763 if ( ! $form ) {
764 return;
765 }
766
767 $is_preview = 'frm_forms_preview' === FrmAppHelper::simple_get( 'action' );
768
769 if ( $is_preview && FrmFormsHelper::should_block_preview( $form->form_key ) ) {
770 return;
771 }
772
773 $params = FrmForm::get_params( $form );
774
775 if ( ! isset( $frm_vars['form_params'] ) ) {
776 $frm_vars['form_params'] = array();
777 }
778 $frm_vars['form_params'][ $form->id ] = $params;
779
780 if ( isset( $frm_vars['created_entries'][ $form_id ] ) ) {
781 return;
782 }
783
784 // phpcs:ignore Universal.Operators.StrictComparisons
785 if ( $errors == '' && ! $ajax ) {
786 $errors = FrmEntryValidate::validate( wp_unslash( $_POST ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
787 }
788
789 /**
790 * Use this filter to add trigger actions and add errors after
791 * all other errors have been processed
792 *
793 * @since 2.0.6
794 */
795 $errors = apply_filters( 'frm_entries_before_create', $errors, $form );
796
797 $frm_vars['created_entries'][ $form_id ] = array( 'errors' => $errors );
798
799 if ( $errors ) {
800 return;
801 }
802
803 $_POST['frm_skip_cookie'] = 1;
804 $do_success = false;
805
806 if ( $params['action'] === 'create' && apply_filters( 'frm_continue_to_create', true, $form_id ) && ! isset( $frm_vars['created_entries'][ $form_id ]['entry_id'] ) ) {
807 $frm_vars['created_entries'][ $form_id ]['entry_id'] = FrmEntry::create( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
808
809 $params['id'] = $frm_vars['created_entries'][ $form_id ]['entry_id'];
810 $do_success = true;
811 }
812
813 do_action( 'frm_process_entry', $params, $errors, $form, array( 'ajax' => $ajax ) );
814
815 if ( $do_success ) {
816 FrmFormsController::maybe_trigger_redirect( $form, $params, array( 'ajax' => $ajax ) );
817 }
818 unset( $_POST['frm_skip_cookie'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
819 }
820
821 /**
822 * Escape url entities before redirect
823 *
824 * @since 3.0
825 *
826 * @param string $url
827 *
828 * @return string
829 */
830 public static function prepare_redirect_url( $url ) {
831 return str_replace( array( ' ', '[', ']', '|', '@' ), array( '%20', '%5B', '%5D', '%7C', '%40' ), $url );
832 }
833
834 /**
835 * Delete entry if redirected.
836 *
837 * @param string $url
838 * @param object $form
839 * @param array $atts
840 *
841 * @return string
842 */
843 public static function delete_entry_before_redirect( $url, $form, $atts ) {
844 self::_delete_entry( $atts['id'], $form );
845 return $url;
846 }
847
848 /**
849 * Delete entry if not redirected.
850 *
851 * @param array $atts
852 *
853 * @return void
854 */
855 public static function delete_entry_after_save( $atts ) {
856 self::_delete_entry( $atts['entry_id'], $atts['form'] );
857 }
858
859 /**
860 * Delete entry if not redirected.
861 *
862 * @param int $entry_id
863 * @param object $form
864 *
865 * @return void
866 */
867 private static function _delete_entry( $entry_id, $form ) {
868 if ( ! $form ) {
869 return;
870 }
871
872 FrmAppHelper::unserialize_or_decode( $form->options );
873
874 if ( empty( $form->options['no_save'] ) ) {
875 return;
876 }
877
878 self::unlink_post( $entry_id );
879 FrmEntry::destroy( $entry_id );
880 }
881
882 /**
883 * Unlink entry from post
884 *
885 * @param int $entry_id
886 *
887 * @return void
888 */
889 private static function unlink_post( $entry_id ) {
890 global $wpdb;
891 $wpdb->update( $wpdb->prefix . 'frm_items', array( 'post_id' => '' ), array( 'id' => $entry_id ) );
892 FrmEntry::clear_cache();
893 }
894
895 /**
896 * @param array $atts
897 *
898 * @return array|string
899 */
900 public static function show_entry_shortcode( $atts ) {
901 $defaults = array(
902 'id' => false,
903 'entry' => false,
904 'fields' => false,
905 'plain_text' => false,
906 'user_info' => false,
907 'include_blank' => false,
908 'default_email' => false,
909 'form_id' => false,
910 'format' => 'text',
911 'array_key' => 'key',
912 'direction' => 'ltr',
913 'font_size' => '',
914 'text_color' => '',
915 'border_width' => '',
916 'border_color' => '',
917 'bg_color' => '',
918 'alt_bg_color' => '',
919 'class' => '',
920 'clickable' => false,
921 'exclude_fields' => '',
922 'include_fields' => '',
923 'include_extras' => '',
924 'inline_style' => 1,
925 'table_style' => '',
926 // Return embedded fields as nested array.
927 'child_array' => false,
928 'line_breaks' => true,
929 'array_separator' => ', ',
930 );
931 $defaults = apply_filters( 'frm_show_entry_defaults', $defaults );
932 $atts = shortcode_atts( $defaults, $atts );
933
934 if ( $atts['default_email'] ) {
935 $shortcode_atts = array(
936 'format' => $atts['format'],
937 'plain_text' => $atts['plain_text'],
938 );
939 $entry_formatter = FrmEntryFactory::entry_shortcode_formatter_instance( $atts['form_id'], $shortcode_atts );
940 return $entry_formatter->content();
941 }
942
943 $entry_formatter = FrmEntryFactory::entry_formatter_instance( $atts );
944
945 return $entry_formatter->get_formatted_entry_values();
946 }
947
948 /**
949 * @param false|object $entry
950 *
951 * @return void
952 */
953 public static function entry_sidebar( $entry = false ) {
954 $data = array();
955 $id = 0;
956 $date_format = get_option( 'date_format' );
957 $time_format = get_option( 'time_format' );
958
959 if ( $entry ) {
960 $id = $entry->id;
961 $data = $entry->description;
962
963 if ( isset( $data['browser'] ) ) {
964 $browser = FrmEntriesHelper::get_browser( $data['browser'] );
965 }
966 /**
967 * Add or remove information in the entry sidebar.
968 *
969 * @since 5.5.2
970 *
971 * @param array $data
972 * @param array{entry:\stdClass} $entry
973 */
974 $data = apply_filters( 'frm_sidebar_data', $data, compact( 'entry' ) );
975 }
976
977 include FrmAppHelper::plugin_path() . '/classes/views/frm-entries/sidebar-shared.php';
978 }
979 }
980