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

980 lines 25.9 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' );
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' );
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
89 $form_id = FrmAppHelper::simple_get( 'form', 'absint', 0 );
90
91 if ( $form_id ) {
92 $query_args['form'] = $form_id;
93 }
94
95 return $query_args;
96 }
97
98 /**
99 * @since 2.05.07
100 *
101 * @return void
102 */
103 private static function load_manage_entries_hooks() {
104 if ( ! in_array( FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' ), array( 'edit', 'show', 'new', 'duplicate' ), true ) ) {
105 $menu_name = FrmAppHelper::get_menu_name();
106 $base = self::base_column_key( $menu_name );
107
108 add_filter( 'manage_' . $base . '_columns', 'FrmEntriesController::manage_columns' );
109 add_filter( 'get_user_option_' . self::hidden_column_key( $menu_name ), 'FrmEntriesController::hidden_columns' );
110 add_filter( 'manage_' . $base . '_sortable_columns', 'FrmEntriesController::sortable_columns' );
111 } else {
112 add_filter( 'screen_options_show_screen', self::class . '::remove_screen_options', 10, 2 );
113 }
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;
135 }
136
137 self::display_list();
138 return;
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 $show_screen = 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' ] = __( 'Entry creation date', 'formidable' );
186 $columns[ $form_id . '_updated_at' ] = __( 'Entry update date', 'formidable' );
187 self::maybe_add_ip_col( $form_id, $columns );
188
189 $frm_vars['cols'] = $columns;
190
191 $action = FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
192
193 if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) && in_array( $action, array( '', 'list', 'destroy' ) ) ) {
194 add_screen_option(
195 'per_page',
196 array(
197 'label' => esc_html__( 'Entries', 'formidable' ),
198 'default' => 20,
199 'option' => 'formidable_page_formidable_entries_per_page',
200 )
201 );
202 }
203
204 return $columns;
205 }
206
207 /**
208 * @param int|string $form_id
209 * @param array $columns
210 *
211 * @return void
212 */
213 private static function get_columns_for_form( $form_id, &$columns ) {
214 $form_cols = FrmField::get_all_for_form( $form_id, '', 'include' );
215
216 /**
217 * Allows changing fields in the Entries list table heading.
218 *
219 * @since 5.0.04
220 *
221 * @param array $fields Array of fields.
222 * @param array $args The arguments. Contains `form_id`.
223 */
224 $form_cols = apply_filters( 'frm_fields_in_entries_list_table', $form_cols, compact( 'form_id' ) );
225
226 foreach ( $form_cols as $form_col ) {
227 if ( FrmField::is_no_save_field( $form_col->type ) ) {
228 continue;
229 }
230
231 $has_child_fields = $form_col->type === 'form' && ! empty( $form_col->field_options['form_select'] );
232
233 if ( $has_child_fields ) {
234 self::add_subform_cols( $form_col, $form_id, $columns );
235 } else {
236 self::add_field_cols( $form_col, $form_id, $columns );
237 }
238 }
239 }
240
241 /**
242 * @since 3.01
243 *
244 * @param object $field The field object.
245 * @param int|string $form_id The form ID.
246 * @param array $columns The columns array.
247 *
248 * @return void
249 */
250 private static function add_subform_cols( $field, $form_id, &$columns ) {
251 $sub_form_cols = FrmField::get_all_for_form( $field->field_options['form_select'] );
252
253 if ( empty( $sub_form_cols ) ) {
254 return;
255 }
256
257 foreach ( $sub_form_cols as $k => $sub_form_col ) {
258 if ( FrmField::is_no_save_field( $sub_form_col->type ) ) {
259 unset( $sub_form_cols[ $k ] );
260 continue;
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 ( $field->form_id != $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' ), 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 if ( $meta_key != $this_page_name || $meta_value == $prev_value ) {
342 return $check;
343 }
344
345 if ( empty( $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 if ( $meta_key != $this_page_name ) {
370 return;
371 }
372
373 global $frm_vars;
374
375 if ( ! isset( $frm_vars['prev_hidden_cols'] ) || ! $frm_vars['prev_hidden_cols'] ) {
376 // Don't continue if there's no previous value.
377 return;
378 }
379
380 foreach ( $meta_value as $mk => $mv ) {
381 // Remove blank values.
382 if ( empty( $mv ) ) {
383 unset( $meta_value[ $mk ] );
384 }
385 }
386
387 $cur_form_prefix = reset( $meta_value );
388 $cur_form_prefix = explode( '_', $cur_form_prefix );
389 $cur_form_prefix = $cur_form_prefix[0];
390 $save = false;
391
392 foreach ( (array) $frm_vars['prev_hidden_cols'] as $prev_hidden ) {
393 if ( empty( $prev_hidden ) || in_array( $prev_hidden, $meta_value ) ) {
394 // Don't add blank cols or process included cols.
395 continue;
396 }
397
398 $form_prefix = explode( '_', $prev_hidden );
399 $form_prefix = $form_prefix[0];
400
401 if ( $form_prefix === $cur_form_prefix ) {
402 // Don't add back columns that are meant to be hidden.
403 continue;
404 }
405
406 $meta_value[] = $prev_hidden;
407 $save = true;
408 unset( $form_prefix );
409 }
410
411 if ( $save ) {
412 $user_id = get_current_user_id();
413 update_user_option( $user_id, $this_page_name, $meta_value, true );
414 }
415 }
416
417 /**
418 * @since 2.05.07
419 *
420 * @param string $menu_name
421 *
422 * @return string
423 */
424 private static function hidden_column_key( $menu_name = '' ) {
425 $base = self::base_column_key( $menu_name );
426
427 return 'manage' . $base . 'columnshidden';
428 }
429
430 /**
431 * @since 2.05.07
432 *
433 * @param string $menu_name
434 *
435 * @return string
436 */
437 private static function base_column_key( $menu_name = '' ) {
438 if ( empty( $menu_name ) ) {
439 $menu_name = FrmAppHelper::get_menu_name();
440 }
441
442 $unread_count = FrmEntriesHelper::get_visible_unread_inbox_count();
443
444 return sanitize_title( $menu_name ) . ( $unread_count ? '-' . $unread_count : '' ) . '_page_formidable-entries';
445 }
446
447 /**
448 * @param int $save
449 * @param string $option
450 * @param string $value
451 *
452 * @return int
453 */
454 public static function save_per_page( $save, $option, $value ) {
455 if ( $option === 'formidable_page_formidable_entries_per_page' ) {
456 $save = (int) $value;
457 }
458
459 return $save;
460 }
461
462 /**
463 * @return array
464 */
465 public static function sortable_columns() {
466 $form_id = FrmForm::get_current_form_id();
467 $fields = FrmField::get_all_for_form( $form_id );
468
469 $columns = array(
470 $form_id . '_id' => 'id',
471 $form_id . '_created_at' => 'created_at',
472 $form_id . '_updated_at' => 'updated_at',
473 $form_id . '_ip' => 'ip',
474 $form_id . '_item_key' => 'item_key',
475 $form_id . '_is_draft' => 'is_draft',
476 );
477
478 if ( ! $form_id ) {
479 $columns[ $form_id . '_user_id' ] = 'user_id';
480 $columns[ $form_id . '_name' ] = 'name';
481 $columns[ $form_id . '_form_id' ] = 'form_id';
482 }
483
484 foreach ( $fields as $field ) {
485 if ( self::field_supports_sorting( $field ) ) {
486 $columns[ $form_id . '_' . $field->field_key ] = 'meta_' . $field->id;
487 }
488 }
489
490 return $columns;
491 }
492
493 /**
494 * Can't sort on checkboxes because they are sorted serialized.
495 * Some post content can be sorted but not everything.
496 *
497 * @param stdClass $field
498 *
499 * @return bool
500 */
501 private static function field_supports_sorting( $field ) {
502 $is_sortable = 'checkbox' !== $field->type && empty( $field->field_options['post_field'] );
503 return apply_filters( 'frm_field_column_is_sortable', $is_sortable, $field );
504 }
505
506 /**
507 * @param mixed $result Option value from database for hidden columns in entries table.
508 *
509 * @return array
510 */
511 public static function hidden_columns( $result ) {
512 global $frm_vars;
513
514 if ( ! is_array( $result ) ) {
515 // Force an unexpected value to be an array.
516 // Since $result is a filtered option and gets saved to the database, it's possible it could be a string.
517 // Since this code expects an array it would break with a "Uncaught Error: [] operator not supported for strings" error.
518 $result = array();
519 }
520
521 $form_id = FrmForm::get_current_form_id();
522 $hidden = self::user_hidden_columns_for_form( $form_id, $result );
523 $i = isset( $frm_vars['cols'] ) ? count( $frm_vars['cols'] ) : 0;
524 $max_columns = 11;
525
526 if ( ! empty( $hidden ) ) {
527 $result = $hidden;
528 $i = $i - count( $result );
529 }
530
531 if ( $i <= $max_columns ) {
532 return $result;
533 }
534
535 self::remove_excess_cols( compact( 'i', 'max_columns', 'form_id' ), $result );
536
537 return $result;
538 }
539
540 /**
541 * @since 2.05.07
542 *
543 * @param int|string $form_id
544 * @param mixed $result
545 *
546 * @return array
547 */
548 private static function user_hidden_columns_for_form( $form_id, $result ) {
549 $hidden = array();
550
551 foreach ( (array) $result as $r ) {
552 if ( ! empty( $r ) ) {
553 list( $form_prefix, $field_key ) = explode( '_', $r );
554
555 if ( (int) $form_prefix === (int) $form_id ) {
556 $hidden[] = $r;
557 }
558
559 unset( $form_prefix );
560 }
561 }
562
563 return $hidden;
564 }
565
566 /**
567 * Remove some columns by default when there are too many
568 *
569 * @since 2.05.07
570 *
571 * @param array $atts
572 * @param array $result
573 *
574 * @return void
575 */
576 private static function remove_excess_cols( $atts, &$result ) {
577 global $frm_vars;
578
579 $remove_first = array(
580 $atts['form_id'] . '_item_key' => '',
581 $atts['form_id'] . '_id' => '',
582 );
583 $cols = $remove_first + array_reverse( $frm_vars['cols'], true );
584
585 $i = $atts['i'];
586
587 foreach ( $cols as $col_key => $col ) {
588 if ( $i <= $atts['max_columns'] ) {
589 break;
590 }
591
592 if ( empty( $result ) || ! in_array( $col_key, $result, true ) ) {
593 $result[] = $col_key;
594 --$i;
595 }
596
597 unset( $col_key, $col );
598 }
599 }
600
601 /**
602 * @param string $message
603 * @param array $errors
604 *
605 * @return void
606 */
607 public static function display_list( $message = '', $errors = array() ) {
608 global $wpdb, $frm_vars;
609
610 $form = FrmForm::maybe_get_current_form();
611 $params = FrmForm::get_admin_params( $form );
612
613 if ( $form ) {
614 $params['form'] = $form->id;
615 $frm_vars['current_form'] = $form;
616
617 self::get_delete_form_time( $form, $errors );
618 }
619
620 $table_class = apply_filters( 'frm_entries_list_class', 'FrmEntriesListHelper' );
621
622 $wp_list_table = new $table_class( array( 'params' => $params ) );
623
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_redirect( esc_url_raw( $url ) );
637 }
638 die();
639 }
640
641 if ( empty( $message ) && isset( $_GET['import-message'] ) ) {
642 $message = __( 'Your import is complete', 'formidable' );
643 }
644
645 require FrmAppHelper::plugin_path() . '/classes/views/frm-entries/list.php';
646 }
647
648 /**
649 * @param object $form
650 * @param array $errors
651 *
652 * @return void
653 */
654 private static function get_delete_form_time( $form, &$errors ) {
655 if ( 'trash' === $form->status ) {
656 $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
657 $time_to_delete = FrmAppHelper::human_time_diff( $delete_timestamp, ( $form->options['trash_time'] ?? time() ) );
658
659 /* translators: %1$s: Time string */
660 $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 );
661 }
662 }
663
664 /**
665 * Back End CRUD.
666 *
667 * @param int $id
668 *
669 * @return void
670 */
671 public static function show( $id = 0 ) {
672 FrmAppHelper::permission_check( 'frm_view_entries' );
673
674 if ( ! $id ) {
675 $id = FrmAppHelper::get_param( 'id', 0, 'get', 'absint' );
676
677 if ( ! $id ) {
678 $id = FrmAppHelper::get_param( 'item_id', 0, 'get', 'absint' );
679 }
680 }
681
682 $entry = FrmEntry::getOne( $id, true );
683
684 if ( ! $entry ) {
685 FrmAppController::show_error_modal(
686 array(
687 'title' => __( 'You can\'t view the entry', 'formidable' ),
688 'body' => __( 'You are trying to view an entry that does not exist', 'formidable' ),
689 'cancel_url' => admin_url( 'admin.php?page=formidable' ),
690 )
691 );
692 return;
693 }
694
695 $data = $entry->description;
696
697 if ( ! is_array( $data ) || ! isset( $data['referrer'] ) ) {
698 $data = array( 'referrer' => $data );
699 }
700
701 $fields = FrmField::get_all_for_form( $entry->form_id, '', 'include' );
702 $form = FrmForm::getOne( $entry->form_id );
703
704 include FrmAppHelper::plugin_path() . '/classes/views/frm-entries/show.php';
705 }
706
707 /**
708 * Destroy an entry from the admin page.
709 * 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.
710 *
711 * @return void
712 */
713 public static function destroy() {
714 $permission_error = FrmAppHelper::permission_nonce_error( 'frm_delete_entries', '_wpnonce', -1 );
715
716 if ( false !== $permission_error ) {
717 $error_args = array(
718 'title' => __( 'Verification failed', 'formidable' ),
719 'body' => $permission_error,
720 'cancel_url' => admin_url( 'admin.php?page=formidable-entries' ),
721 );
722 FrmAppController::show_error_modal( $error_args );
723 return;
724 }
725
726 $params = FrmForm::get_admin_params();
727
728 if ( isset( $params['keep_post'] ) && $params['keep_post'] ) {
729 self::unlink_post( $params['id'] );
730 }
731
732 $message = '';
733
734 if ( FrmEntry::destroy( $params['id'] ) ) {
735 $message = __( 'Entry was successfully deleted', 'formidable' );
736 }
737
738 self::display_list( $message );
739 }
740
741 /**
742 * @param array|string $errors
743 * @param bool $ajax
744 *
745 * @return void
746 */
747 public static function process_entry( $errors = '', $ajax = false ) {
748 $form_id = FrmAppHelper::get_post_param( 'form_id', '', 'absint' );
749
750 if ( FrmAppHelper::is_admin() || empty( $_POST ) || empty( $form_id ) || ! isset( $_POST['item_key'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
751 return;
752 }
753
754 global $frm_vars;
755
756 $form = FrmForm::getOne( $form_id );
757
758 if ( ! $form ) {
759 return;
760 }
761
762 $is_preview = 'frm_forms_preview' === FrmAppHelper::simple_get( 'action' );
763
764 if ( $is_preview && FrmFormsHelper::should_block_preview( $form->form_key ) ) {
765 return;
766 }
767
768 $params = FrmForm::get_params( $form );
769
770 if ( ! isset( $frm_vars['form_params'] ) ) {
771 $frm_vars['form_params'] = array();
772 }
773 $frm_vars['form_params'][ $form->id ] = $params;
774
775 if ( isset( $frm_vars['created_entries'][ $form_id ] ) ) {
776 return;
777 }
778
779 if ( $errors == '' && ! $ajax ) {
780 $errors = FrmEntryValidate::validate( wp_unslash( $_POST ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
781 }
782
783 /**
784 * Use this filter to add trigger actions and add errors after
785 * all other errors have been processed
786 *
787 * @since 2.0.6
788 */
789 $errors = apply_filters( 'frm_entries_before_create', $errors, $form );
790
791 $frm_vars['created_entries'][ $form_id ] = array( 'errors' => $errors );
792
793 if ( empty( $errors ) ) {
794 $_POST['frm_skip_cookie'] = 1;
795 $do_success = false;
796
797 if ( $params['action'] === 'create' ) {
798 if ( apply_filters( 'frm_continue_to_create', true, $form_id ) && ! isset( $frm_vars['created_entries'][ $form_id ]['entry_id'] ) ) {
799 $frm_vars['created_entries'][ $form_id ]['entry_id'] = FrmEntry::create( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
800
801 $params['id'] = $frm_vars['created_entries'][ $form_id ]['entry_id'];
802 $do_success = true;
803 }
804 }
805
806 do_action( 'frm_process_entry', $params, $errors, $form, array( 'ajax' => $ajax ) );
807
808 if ( $do_success ) {
809 FrmFormsController::maybe_trigger_redirect( $form, $params, array( 'ajax' => $ajax ) );
810 }
811 unset( $_POST['frm_skip_cookie'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
812 }
813 }
814
815 /**
816 * Escape url entities before redirect
817 *
818 * @since 3.0
819 *
820 * @param string $url
821 *
822 * @return string
823 */
824 public static function prepare_redirect_url( $url ) {
825 return str_replace( array( ' ', '[', ']', '|', '@' ), array( '%20', '%5B', '%5D', '%7C', '%40' ), $url );
826 }
827
828 /**
829 * Delete entry if redirected.
830 *
831 * @param string $url
832 * @param object $form
833 * @param array $atts
834 *
835 * @return string
836 */
837 public static function delete_entry_before_redirect( $url, $form, $atts ) {
838 self::_delete_entry( $atts['id'], $form );
839
840 return $url;
841 }
842
843 /**
844 * Delete entry if not redirected.
845 *
846 * @param array $atts
847 *
848 * @return void
849 */
850 public static function delete_entry_after_save( $atts ) {
851 self::_delete_entry( $atts['entry_id'], $atts['form'] );
852 }
853
854 /**
855 * Delete entry if not redirected.
856 *
857 * @param int $entry_id
858 * @param object $form
859 *
860 * @return void
861 */
862 private static function _delete_entry( $entry_id, $form ) {
863 if ( ! $form ) {
864 return;
865 }
866
867 FrmAppHelper::unserialize_or_decode( $form->options );
868
869 if ( isset( $form->options['no_save'] ) && $form->options['no_save'] ) {
870 self::unlink_post( $entry_id );
871 FrmEntry::destroy( $entry_id );
872 }
873 }
874
875 /**
876 * Unlink entry from post
877 *
878 * @param int $entry_id
879 *
880 * @return void
881 */
882 private static function unlink_post( $entry_id ) {
883 global $wpdb;
884 $wpdb->update( $wpdb->prefix . 'frm_items', array( 'post_id' => '' ), array( 'id' => $entry_id ) );
885 FrmEntry::clear_cache();
886 }
887
888 /**
889 * @param array $atts
890 *
891 * @return array|string
892 */
893 public static function show_entry_shortcode( $atts ) {
894 $defaults = array(
895 'id' => false,
896 'entry' => false,
897 'fields' => false,
898 'plain_text' => false,
899 'user_info' => false,
900 'include_blank' => false,
901 'default_email' => false,
902 'form_id' => false,
903 'format' => 'text',
904 'array_key' => 'key',
905 'direction' => 'ltr',
906 'font_size' => '',
907 'text_color' => '',
908 'border_width' => '',
909 'border_color' => '',
910 'bg_color' => '',
911 'alt_bg_color' => '',
912 'class' => '',
913 'clickable' => false,
914 'exclude_fields' => '',
915 'include_fields' => '',
916 'include_extras' => '',
917 'inline_style' => 1,
918 'table_style' => '',
919 // Return embedded fields as nested array.
920 'child_array' => false,
921 'line_breaks' => true,
922 'array_separator' => ', ',
923 );
924 $defaults = apply_filters( 'frm_show_entry_defaults', $defaults );
925
926 $atts = shortcode_atts( $defaults, $atts );
927
928 if ( $atts['default_email'] ) {
929 $shortcode_atts = array(
930 'format' => $atts['format'],
931 'plain_text' => $atts['plain_text'],
932 );
933
934 $entry_formatter = FrmEntryFactory::entry_shortcode_formatter_instance( $atts['form_id'], $shortcode_atts );
935 $formatted_entry = $entry_formatter->content();
936
937 } else {
938
939 $entry_formatter = FrmEntryFactory::entry_formatter_instance( $atts );
940 $formatted_entry = $entry_formatter->get_formatted_entry_values();
941
942 }
943
944 return $formatted_entry;
945 }
946
947 /**
948 * @param false|object $entry
949 *
950 * @return void
951 */
952 public static function entry_sidebar( $entry = false ) {
953 $data = array();
954 $id = 0;
955
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