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

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

3,085 lines 89.1 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 FrmFormsController {
7
8 /**
9 * Track the form that opened the redirect URL in a new tab. This is used to check if we should show the default
10 * message in the currect tab.
11 *
12 * @since 6.2
13 *
14 * @var array Keys are form IDs and values are 1.
15 */
16 private static $redirected_in_new_tab = array();
17
18 public static function menu() {
19 $menu_label = __( 'Forms', 'formidable' );
20 if ( ! FrmAppHelper::pro_is_installed() ) {
21 $menu_label .= ' (Lite)';
22 }
23 add_submenu_page( 'formidable', 'Formidable | ' . $menu_label, $menu_label, 'frm_view_forms', 'formidable', 'FrmFormsController::route' );
24
25 self::maybe_load_listing_hooks();
26 }
27
28 public static function maybe_load_listing_hooks() {
29 if ( ! FrmAppHelper::on_form_listing_page() ) {
30 return;
31 }
32
33 add_filter( 'get_user_option_managetoplevel_page_formidablecolumnshidden', 'FrmFormsController::hidden_columns' );
34
35 add_filter( 'manage_toplevel_page_formidable_columns', 'FrmFormsController::get_columns', 0 );
36 add_filter( 'manage_toplevel_page_formidable_sortable_columns', 'FrmFormsController::get_sortable_columns' );
37 }
38
39 public static function head() {
40 if ( wp_is_mobile() ) {
41 wp_enqueue_script( 'jquery-touch-punch' );
42 }
43 }
44
45 public static function register_widgets() {
46 require_once FrmAppHelper::plugin_path() . '/classes/widgets/FrmShowForm.php';
47 register_widget( 'FrmShowForm' );
48 }
49
50 /**
51 * Show a message about conditional logic
52 *
53 * @since 4.06.03
54 */
55 public static function logic_tip() {
56 $images_url = FrmAppHelper::plugin_url() . '/images/';
57 $data_message = __( 'Only show the fields you need and create branching forms. Upgrade to get conditional logic and question branching.', 'formidable' );
58 $data_message .= ' <img src="' . esc_attr( $images_url ) . '/survey-logic.png" srcset="' . esc_attr( $images_url ) . 'survey-logic@2x.png 2x" alt="' . esc_attr__( 'Conditional Logic options', 'formidable' ) . '"/>';
59 echo '<a href="javascript:void(0)" class="frm_noallow frm_show_upgrade frm_add_logic_link frm-collapsed frm-flex-justify" data-upgrade="' . esc_attr__( 'Conditional Logic options', 'formidable' ) . '" data-message="' . esc_attr( $data_message ) . '" data-medium="builder" data-content="logic">';
60 esc_html_e( 'Conditional Logic', 'formidable' );
61 FrmAppHelper::icon_by_class( 'frmfont frm_arrowdown6_icon', array( 'aria-hidden' => 'true' ) );
62 echo '</a>';
63 }
64
65 /**
66 * By default, Divi processes form shortcodes on the edit post page.
67 * Now that won't do.
68 *
69 * @since 3.01
70 */
71 public static function prevent_divi_conflict( $shortcodes ) {
72 $shortcodes[] = 'formidable';
73
74 return $shortcodes;
75 }
76
77 /**
78 * @return void
79 */
80 public static function list_form() {
81 FrmAppHelper::permission_check( 'frm_view_forms' );
82
83 $message = '';
84 $params = FrmForm::list_page_params();
85 $errors = self::process_bulk_form_actions( array() );
86 if ( isset( $errors['message'] ) ) {
87 $message = $errors['message'];
88 unset( $errors['message'] );
89 }
90 $errors = apply_filters( 'frm_admin_list_form_action', $errors );
91
92 self::display_forms_list( $params, $message, $errors );
93 }
94
95 /**
96 * Create the default email action
97 *
98 * @since 2.02.11
99 *
100 * @param object|int $form
101 */
102 private static function create_default_email_action( $form ) {
103 FrmForm::maybe_get_form( $form );
104 $create_email = apply_filters( 'frm_create_default_email_action', true, $form );
105
106 if ( $create_email ) {
107 $action_control = FrmFormActionsController::get_form_actions( 'email' );
108 $action_control->create( $form->id );
109 }
110 }
111
112 /**
113 * Create the default On submit action
114 *
115 * @since 6.0.0
116 *
117 * @param object|int $form Form object or ID.
118 */
119 private static function create_default_on_submit_action( $form ) {
120 FrmForm::maybe_get_form( $form );
121
122 /**
123 * Enable or disable the default On Submit action.
124 *
125 * @since 6.0.0
126 *
127 * @param bool $create Set to `false` if you want to disable.
128 * @param object $form Form object.
129 */
130 $create = apply_filters( 'frm_create_default_on_submit_action', true, $form );
131
132 if ( $create ) {
133 $action_control = FrmFormActionsController::get_form_actions( FrmOnSubmitAction::$slug );
134 $action_control->create( $form->id );
135 }
136 }
137
138 public static function edit( $values = false ) {
139 FrmAppHelper::permission_check( 'frm_edit_forms' );
140
141 $id = isset( $values['id'] ) ? absint( $values['id'] ) : FrmAppHelper::get_param( 'id', '', 'get', 'absint' );
142
143 return self::get_edit_vars( $id );
144 }
145
146 public static function settings( $id = false, $message = '' ) {
147 FrmAppHelper::permission_check( 'frm_edit_forms' );
148
149 if ( ! $id || ! is_numeric( $id ) ) {
150 $id = FrmAppHelper::get_param( 'id', '', 'get', 'absint' );
151 }
152
153 FrmOnSubmitHelper::maybe_migrate_submit_settings_to_action( $id );
154
155 return self::get_settings_vars( $id, array(), $message );
156 }
157
158 public static function update_settings() {
159 FrmAppHelper::permission_check( 'frm_edit_forms' );
160
161 $id = FrmAppHelper::get_param( 'id', '', 'get', 'absint' );
162
163 $errors = FrmForm::validate( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
164 $warnings = FrmFormsHelper::check_for_warnings( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
165
166 if ( count( $errors ) > 0 ) {
167 return self::get_settings_vars( $id, $errors, compact( 'warnings' ) );
168 }
169
170 do_action( 'frm_before_update_form_settings', $id );
171
172 $antispam_was_on = self::antispam_was_on( $id );
173
174 FrmForm::update( $id, $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
175
176 $antispam_is_on = ! empty( $_POST['options']['antispam'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
177 if ( $antispam_is_on !== $antispam_was_on ) {
178 FrmAntiSpam::clear_caches();
179 }
180
181 $message = __( 'Settings Successfully Updated', 'formidable' );
182
183 return self::get_settings_vars( $id, array(), compact( 'message', 'warnings' ) );
184 }
185
186 /**
187 * @param int $form_id
188 * @return bool
189 */
190 private static function antispam_was_on( $form_id ) {
191 $form = FrmForm::getOne( $form_id );
192 return ! empty( $form->options['antispam'] );
193 }
194
195 public static function update( $values = array() ) {
196 if ( empty( $values ) ) {
197 $values = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing
198 }
199
200 // Set radio button and checkbox meta equal to "other" value.
201 if ( FrmAppHelper::pro_is_installed() ) {
202 $values = FrmProEntry::mod_other_vals( $values, 'back' );
203 }
204
205 $errors = FrmForm::validate( $values );
206 $permission_error = FrmAppHelper::permission_nonce_error( 'frm_edit_forms', 'frm_save_form', 'frm_save_form_nonce' );
207 if ( $permission_error !== false ) {
208 $errors['form'] = $permission_error;
209 }
210
211 $id = isset( $values['id'] ) ? absint( $values['id'] ) : FrmAppHelper::get_param( 'id', '', 'get', 'absint' );
212
213 if ( count( $errors ) > 0 ) {
214 return self::get_edit_vars( $id, $errors );
215 } else {
216 FrmForm::update( $id, $values );
217 $message = __( 'Form was successfully updated.', 'formidable' );
218
219 if ( self::is_too_long( $values ) ) {
220 $message .= '<br/> ' . sprintf(
221 /* translators: %1$s: Start link HTML, %2$s: end link HTML */
222 __( 'However, your form is very long and may be %1$sreaching server limits%2$s.', 'formidable' ),
223 '<a href="https://formidableforms.com/knowledgebase/i-have-a-long-form-why-did-the-options-at-the-end-of-the-form-stop-saving/?utm_source=WordPress&utm_medium=builder&utm_campaign=liteplugin" target="_blank" rel="noopener">',
224 '</a>'
225 );
226 }
227
228 if ( defined( 'DOING_AJAX' ) ) {
229 wp_die( FrmAppHelper::kses( $message, array( 'a' ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
230 }
231
232 return self::get_edit_vars( $id, array(), $message );
233 }
234 }
235
236 /**
237 * Check if the value at the end of the form was included.
238 * If it's missing, it means other values at the end of the form
239 * were likely not saved either.
240 *
241 * @since 3.06.01
242 */
243 private static function is_too_long( $values ) {
244 return ( ! isset( $values['frm_end'] ) ) || empty( $values['frm_end'] );
245 }
246
247 /**
248 * Redirect to the url for creating from a template
249 * Also delete the current form
250 *
251 * @since 2.0
252 * @deprecated 3.06
253 */
254 public static function _create_from_template() {
255 _deprecated_function( __FUNCTION__, '3.06' );
256
257 FrmAppHelper::permission_check( 'frm_edit_forms' );
258 check_ajax_referer( 'frm_ajax', 'nonce' );
259
260 $current_form = FrmAppHelper::get_param( 'this_form', '', 'get', 'absint' );
261 $template_id = FrmAppHelper::get_param( 'id', '', 'get', 'absint' );
262
263 if ( $current_form ) {
264 FrmForm::destroy( $current_form );
265 }
266
267 echo esc_url_raw( admin_url( 'admin.php?page=formidable&frm_action=duplicate&id=' . absint( $template_id ) ) );
268 wp_die();
269 }
270
271 public static function duplicate() {
272 FrmAppHelper::permission_check( 'frm_edit_forms' );
273 $nonce = FrmAppHelper::simple_get( '_wpnonce' );
274
275 if ( ! wp_verify_nonce( $nonce ) ) {
276 $frm_settings = FrmAppHelper::get_settings();
277 wp_die( esc_html( $frm_settings->admin_permission ) );
278 }
279
280 $params = FrmForm::list_page_params();
281 $form = FrmForm::duplicate( $params['id'], $params['template'], true );
282 $url = admin_url( 'admin.php?page=formidable' );
283 $message = 'form_duplicate_error';
284
285 if ( $form ) {
286 $new_template = FrmAppHelper::simple_get( 'new_template' ) ? '&new_template=true' : '';
287 $url = admin_url( 'admin.php?page=formidable&frm_action=edit&id=' . absint( $form ) . $new_template );
288 $message = 'form_duplicated';
289 }
290
291 $url .= '&message=' . $message;
292
293 wp_safe_redirect( $url );
294 exit();
295 }
296
297 /**
298 * @return string
299 */
300 public static function page_preview() {
301 $params = FrmForm::list_page_params();
302 if ( ! $params['form'] ) {
303 return;
304 }
305
306 $form = FrmForm::getOne( $params['form'] );
307 if ( $form ) {
308 return self::show_form( $form->id, '', 'auto', 'auto' );
309 }
310 }
311
312 /**
313 * @since 3.0
314 */
315 public static function show_page_preview() {
316 echo self::page_preview(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
317 }
318
319 /**
320 * @return void
321 */
322 public static function preview() {
323 do_action( 'frm_wp' );
324 FrmAppHelper::set_current_screen_and_hook_suffix();
325
326 global $frm_vars;
327 $frm_vars['preview'] = true;
328
329 $include_theme = FrmAppHelper::get_param( 'theme', '', 'get', 'absint' );
330 if ( $include_theme ) {
331 self::set_preview_query();
332 self::load_theme_preview();
333 } else {
334 self::load_direct_preview();
335 }
336
337 wp_die();
338 }
339
340 /**
341 * Set the page global to any available page (except for the Blog Page).
342 *
343 * @return void
344 */
345 private static function set_preview_query() {
346 $page_query = array(
347 'numberposts' => 1,
348 'orderby' => 'date',
349 'order' => 'ASC',
350 'post_type' => 'page',
351 );
352
353 $page_for_posts = get_option( 'page_for_posts' );
354 if ( is_numeric( $page_for_posts ) ) {
355 // Avoid querying for the "Posts Page" or "Blog Page" so we don't display 10 forms.
356 $page_query['post__not_in'] = array( $page_for_posts );
357 }
358
359 $random_page = get_posts( $page_query );
360 if ( ! $random_page ) {
361 return;
362 }
363
364 $random_page = reset( $random_page );
365 query_posts(
366 array(
367 'post_type' => 'page',
368 'page_id' => $random_page->ID,
369 )
370 );
371
372 // Fixes Pro issue #3004. Prevent an undefined $post object.
373 // Otherwise WordPress themes will trigger a warning "Attempt to read property "comment_count" on null".
374 self::set_post_global( $random_page );
375 }
376
377 /**
378 * Set the WP $post global object. Used for in-theme preview when defining a page.
379 *
380 * @since 5.5.2
381 *
382 * @param WP_Post $post
383 * @return void
384 */
385 private static function set_post_global( $page ) {
386 global $post;
387 $post = $page; // phpcs:ignore WordPress.WP.GlobalVariablesOverride
388 }
389
390 /**
391 * @since 3.0
392 */
393 private static function load_theme_preview() {
394 add_filter( 'wp_title', 'FrmFormsController::preview_title', 9999 );
395 add_filter( 'the_title', 'FrmFormsController::preview_page_title', 9999 );
396 add_filter( 'the_content', 'FrmFormsController::preview_content', 9999 );
397 add_action( 'loop_no_results', 'FrmFormsController::show_page_preview' );
398 add_filter( 'is_active_sidebar', '__return_false' );
399 FrmStylesController::enqueue_css( 'enqueue', true );
400
401 if ( false === get_template_part( 'page' ) ) {
402 if ( function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) {
403 add_filter( 'body_class', 'FrmFormsController::preview_block_theme_body_classnames' );
404 }
405 self::fallback_when_page_template_part_is_not_supported_by_theme();
406 }
407 }
408
409 /**
410 * Add padding to the body for block themes.
411 *
412 * @since 6.5.2
413 *
414 * @param array $classes The body classes list.
415 * @return array
416 */
417 public static function preview_block_theme_body_classnames( $classes ) {
418 $classes[] = 'has-global-padding';
419 return $classes;
420 }
421
422 /**
423 * Not every theme supports get_template_part( 'page' ).
424 * When this is not supported, false is returned, and we can handle a fallback.
425 */
426 private static function fallback_when_page_template_part_is_not_supported_by_theme() {
427 if ( have_posts() ) {
428 the_post();
429 get_header( '' );
430 // add some generic class names to the container to add some natural padding to the content.
431 // .entry-content catches the WordPress TwentyTwenty theme.
432 // .container catches Customizr content.
433 echo '<div class="container entry-content">';
434 the_content();
435 echo '</div>';
436 get_footer();
437 }
438 }
439
440 /**
441 * Set the page title for the theme preview page
442 *
443 * @since 3.0
444 */
445 public static function preview_page_title( $title ) {
446 if ( in_the_loop() ) {
447 $title = self::preview_title( $title );
448 }
449
450 return $title;
451 }
452
453 /**
454 * Set the page title for the theme preview page
455 *
456 * @since 3.0
457 */
458 public static function preview_title( $title ) {
459 return __( 'Form Preview', 'formidable' );
460 }
461
462 /**
463 * Set the page content for the theme preview page
464 *
465 * @since 3.0
466 */
467 public static function preview_content( $content ) {
468 if ( in_the_loop() ) {
469 $content = self::show_page_preview();
470 }
471
472 return $content;
473 }
474
475 /**
476 * @since 3.0
477 */
478 private static function load_direct_preview() {
479 header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
480
481 $key = FrmAppHelper::simple_get( 'form', 'sanitize_title' );
482 if ( $key == '' ) {
483 $key = FrmAppHelper::get_post_param( 'form', '', 'sanitize_title' );
484 }
485
486 $form = FrmForm::getAll( array( 'form_key' => $key ), '', 1 );
487 if ( empty( $form ) ) {
488 $form = FrmForm::getAll( array(), '', 1 );
489 }
490
491 require( FrmAppHelper::plugin_path() . '/classes/views/frm-entries/direct.php' );
492 }
493
494 public static function untrash() {
495 self::change_form_status( 'untrash' );
496 }
497
498 /**
499 * @param array $ids
500 * @return string
501 */
502 public static function bulk_untrash( $ids ) {
503 FrmAppHelper::permission_check( 'frm_edit_forms' );
504
505 $count = FrmForm::set_status( $ids, 'published' );
506
507 if ( ! $count ) {
508 // Don't show "0 forms restored" on refresh.
509 return '';
510 }
511
512 /* translators: %1$s: Number of forms */
513 $message = sprintf( _n( '%1$s form restored from the Trash.', '%1$s forms restored from the Trash.', $count, 'formidable' ), $count );
514
515 return $message;
516 }
517
518 /**
519 * @since 3.06
520 */
521 public static function ajax_trash() {
522 FrmAppHelper::permission_check( 'frm_delete_forms' );
523 check_ajax_referer( 'frm_ajax', 'nonce' );
524 $form_id = FrmAppHelper::get_param( 'id', '', 'post', 'absint' );
525 FrmForm::set_status( $form_id, 'trash' );
526 wp_die();
527 }
528
529 public static function trash() {
530 self::change_form_status( 'trash' );
531 }
532
533 /**
534 * @param string $status
535 *
536 * @return void
537 */
538 public static function change_form_status( $status ) {
539 $available_status = array(
540 'untrash' => array(
541 'permission' => 'frm_edit_forms',
542 'new_status' => 'published',
543 ),
544 'trash' => array(
545 'permission' => 'frm_delete_forms',
546 'new_status' => 'trash',
547 ),
548 );
549
550 if ( ! isset( $available_status[ $status ] ) ) {
551 return;
552 }
553
554 FrmAppHelper::permission_check( $available_status[ $status ]['permission'] );
555
556 $params = FrmForm::list_page_params();
557
558 //check nonce url
559 check_admin_referer( $status . '_form_' . $params['id'] );
560
561 $count = 0;
562 if ( FrmForm::set_status( $params['id'], $available_status[ $status ]['new_status'] ) ) {
563 $count ++;
564 }
565
566 $form_type = FrmAppHelper::get_simple_request(
567 array(
568 'param' => 'form_type',
569 'type' => 'request',
570 )
571 );
572
573 /* translators: %1$s: Number of forms */
574 $available_status['untrash']['message'] = sprintf( _n( '%1$s form restored from the Trash.', '%1$s forms restored from the Trash.', $count, 'formidable' ), $count );
575
576 /* translators: %1$s: Number of forms, %2$s: Start link HTML, %3$s: End link HTML */
577 $available_status['trash']['message'] = sprintf( _n( '%1$s form moved to the Trash. %2$sUndo%3$s', '%1$s forms moved to the Trash. %2$sUndo%3$s', $count, 'formidable' ), $count, '<a href="' . esc_url( wp_nonce_url( '?page=formidable&frm_action=untrash&form_type=' . $form_type . '&id=' . $params['id'], 'untrash_form_' . $params['id'] ) ) . '">', '</a>' );
578
579 $message = $available_status[ $status ]['message'];
580
581 self::display_forms_list( $params, $message );
582 }
583
584 public static function bulk_trash( $ids ) {
585 FrmAppHelper::permission_check( 'frm_delete_forms' );
586
587 $count = 0;
588 foreach ( $ids as $id ) {
589 if ( FrmForm::trash( $id ) ) {
590 $count ++;
591 }
592 }
593
594 $current_page = FrmAppHelper::get_simple_request(
595 array(
596 'param' => 'form_type',
597 'type' => 'request',
598 )
599 );
600 $message = sprintf(
601 /* translators: %1$s: Number of forms, %2$s: Start link HTML, %3$s: End link HTML */
602 _n( '%1$s form moved to the Trash. %2$sUndo%3$s', '%1$s forms moved to the Trash. %2$sUndo%3$s', $count, 'formidable' ),
603 $count,
604 '<a href="' . esc_url( wp_nonce_url( '?page=formidable&frm_action=list&action=bulk_untrash&form_type=' . $current_page . '&item-action=' . implode( ',', $ids ), 'bulk-toplevel_page_formidable' ) ) . '">',
605 '</a>'
606 );
607
608 return $message;
609 }
610
611 public static function destroy() {
612 FrmAppHelper::permission_check( 'frm_delete_forms' );
613
614 $params = FrmForm::list_page_params();
615
616 // Check nonce url.
617 check_admin_referer( 'destroy_form_' . $params['id'] );
618
619 $count = 0;
620 if ( FrmForm::destroy( $params['id'] ) ) {
621 $count ++;
622 }
623
624 /* translators: %1$s: Number of forms */
625 $message = sprintf( _n( '%1$s Form Permanently Deleted', '%1$s Forms Permanently Deleted', $count, 'formidable' ), $count );
626
627 self::display_forms_list( $params, $message );
628 }
629
630 public static function bulk_destroy( $ids ) {
631 FrmAppHelper::permission_check( 'frm_delete_forms' );
632
633 $count = 0;
634 foreach ( $ids as $id ) {
635 $d = FrmForm::destroy( $id );
636 if ( $d ) {
637 $count ++;
638 }
639 }
640
641 /* translators: %1$s: Number of forms */
642 $message = sprintf( _n( '%1$s form permanently deleted.', '%1$s forms permanently deleted.', $count, 'formidable' ), $count );
643
644 return $message;
645 }
646
647 private static function delete_all() {
648 // Check nonce url.
649 $permission_error = FrmAppHelper::permission_nonce_error( 'frm_delete_forms', '_wpnonce', 'bulk-toplevel_page_formidable' );
650 if ( $permission_error !== false ) {
651 self::display_forms_list( array(), '', array( $permission_error ) );
652
653 return;
654 }
655
656 $count = FrmForm::scheduled_delete( time() );
657
658 /* translators: %1$s: Number of forms */
659 $message = sprintf( _n( '%1$s form permanently deleted.', '%1$s forms permanently deleted.', $count, 'formidable' ), $count );
660
661 self::display_forms_list( array(), $message );
662 }
663
664 /**
665 * Create a new form from the modal.
666 *
667 * @since 4.0
668 */
669 public static function build_new_form() {
670 FrmAppHelper::permission_check( 'frm_edit_forms' );
671 check_ajax_referer( 'frm_ajax', 'nonce' );
672
673 $new_values = self::get_modal_values();
674 $new_values['form_key'] = $new_values['name'];
675 $new_values['options'] = array(
676 'antispam' => 1,
677 'on_submit_migrated' => 1,
678 );
679
680 /**
681 * Allows changing form values before creating from the modal.
682 *
683 * @since 5.4
684 *
685 * @param array $values Form values.
686 */
687 $new_values = apply_filters( 'frm_new_form_values', $new_values );
688
689 $form_id = FrmForm::create( $new_values );
690 /**
691 * @since 5.3
692 *
693 * @param int $form_id
694 */
695 do_action( 'frm_build_new_form', $form_id );
696
697 self::create_default_on_submit_action( $form_id );
698 self::create_default_email_action( $form_id );
699
700 $response = array(
701 'redirect' => FrmForm::get_edit_link( $form_id ) . '&new_template=true',
702 );
703
704 echo wp_json_encode( $response );
705 wp_die();
706 }
707
708 /**
709 * Before creating a new form, get the name and description from the modal.
710 *
711 * @since 4.0
712 */
713 public static function get_modal_values() {
714 $name = FrmAppHelper::get_param( 'name', '', 'post', 'sanitize_text_field' );
715 $desc = FrmAppHelper::get_param( 'desc', '', 'post', 'sanitize_textarea_field' );
716
717 return array(
718 'name' => $name,
719 'description' => $desc,
720 );
721 }
722
723 /**
724 * Inserts Formidable button
725 * Hook exists since 2.5.0
726 *
727 * @since 2.0.15
728 */
729 public static function insert_form_button() {
730 if ( current_user_can( 'frm_view_forms' ) ) {
731 FrmAppHelper::load_admin_wide_js();
732 $menu_name = FrmAppHelper::get_menu_name();
733 $icon = apply_filters( 'frm_media_icon', FrmAppHelper::svg_logo() );
734 echo '<a href="#TB_inline?width=50&height=50&inlineId=frm_insert_form" class="thickbox button add_media frm_insert_form" title="' . esc_attr__( 'Add forms and content', 'formidable' ) . '">' .
735 FrmAppHelper::kses( $icon, 'all' ) . // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
736 ' ' . esc_html( $menu_name ) . '</a>';
737 }
738 }
739
740 /**
741 * @return void
742 */
743 public static function insert_form_popup() {
744 if ( ! self::should_insert_form_popup() ) {
745 return;
746 }
747
748 FrmAppHelper::load_admin_wide_js();
749
750 $shortcodes = array(
751 'formidable' => array(
752 'name' => __( 'Form', 'formidable' ),
753 'label' => __( 'Insert a Form', 'formidable' ),
754 ),
755 );
756 $shortcodes = apply_filters( 'frm_popup_shortcodes', $shortcodes );
757
758 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/insert_form_popup.php';
759
760 if ( FrmAppHelper::is_form_builder_page() && ! class_exists( '_WP_Editors', false ) ) {
761 // initialize a wysiwyg so we have usable settings defined in tinyMCEPreInit.mceInit
762 require ABSPATH . WPINC . '/class-wp-editor.php';
763 ?>
764 <div class="frm_hidden">
765 <?php wp_editor( '', 'frm_description_placeholder', array() ); ?>
766 </div>
767 <?php
768 }
769 }
770
771 /**
772 * Check the page being loaded, determine if this is a page that should include the form popup.
773 *
774 * @since 5.0.14
775 *
776 * @return bool
777 */
778 private static function should_insert_form_popup() {
779 if ( FrmAppHelper::is_form_builder_page() ) {
780 return true;
781 }
782 $page = basename( FrmAppHelper::get_server_value( 'PHP_SELF' ) );
783 return in_array( $page, array( 'post.php', 'page.php', 'page-new.php', 'post-new.php' ), true );
784 }
785
786 public static function get_shortcode_opts() {
787 FrmAppHelper::permission_check( 'frm_view_forms' );
788 check_ajax_referer( 'frm_ajax', 'nonce' );
789
790 $shortcode = FrmAppHelper::get_post_param( 'shortcode', '', 'sanitize_text_field' );
791 if ( empty( $shortcode ) ) {
792 wp_die();
793 }
794
795 echo '<div id="sc-opts-' . esc_attr( $shortcode ) . '" class="frm_shortcode_option">';
796 echo '<input type="radio" name="frmsc" value="' . esc_attr( $shortcode ) . '" id="sc-' . esc_attr( $shortcode ) . '" class="frm_hidden" />';
797
798 $form_id = '';
799 $opts = array();
800 switch ( $shortcode ) {
801 case 'formidable':
802 $opts = array(
803 'form_id' => 'id',
804 'title' => array(
805 'val' => 1,
806 'label' => __( 'Display form title', 'formidable' ),
807 ),
808 'description' => array(
809 'val' => 1,
810 'label' => __( 'Display form description', 'formidable' ),
811 ),
812 'minimize' => array(
813 'val' => 1,
814 'label' => __( 'Minimize form HTML', 'formidable' ),
815 ),
816 );
817 }
818 $opts = apply_filters( 'frm_sc_popup_opts', $opts, $shortcode );
819
820 if ( isset( $opts['form_id'] ) && is_string( $opts['form_id'] ) ) {
821 // allow other shortcodes to use the required form id option
822 $form_id = $opts['form_id'];
823 unset( $opts['form_id'] );
824 }
825
826 include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/shortcode_opts.php' );
827
828 echo '</div>';
829
830 wp_die();
831 }
832
833 /**
834 * Display list of forms in a table.
835 *
836 * @param array $params
837 * @param string $message
838 * @param array $errors
839 * @return void
840 */
841 public static function display_forms_list( $params = array(), $message = '', $errors = array() ) {
842 FrmAppHelper::permission_check( 'frm_view_forms' );
843
844 global $wpdb, $frm_vars;
845
846 if ( ! $params ) {
847 $params = FrmForm::list_page_params();
848 }
849
850 /**
851 * @since 5.3.1
852 *
853 * @param string $table_class Class name for List Helper.
854 */
855 $table_class = apply_filters( 'frm_forms_list_class', 'FrmFormsListHelper' );
856 $wp_list_table = new $table_class( compact( 'params' ) );
857
858 $pagenum = $wp_list_table->get_pagenum();
859
860 $wp_list_table->prepare_items();
861
862 $total_pages = $wp_list_table->get_pagination_arg( 'total_pages' );
863 if ( $pagenum > $total_pages && $total_pages > 0 ) {
864 wp_redirect( esc_url_raw( add_query_arg( 'paged', $total_pages ) ) );
865 die();
866 }
867
868 require FrmAppHelper::plugin_path() . '/classes/views/frm-forms/list.php';
869 }
870
871 /**
872 * @param array<string,string> $columns
873 * @return array<string,string>
874 */
875 public static function get_columns( $columns ) {
876 $columns['cb'] = '<input type="checkbox" />';
877 $columns['name'] = esc_html__( 'Form Title', 'formidable' );
878 $columns['entries'] = esc_html__( 'Entries', 'formidable' );
879 $columns['id'] = 'ID';
880 $columns['form_key'] = esc_html__( 'Key', 'formidable' );
881 $columns['shortcode'] = esc_html__( 'Actions', 'formidable' );
882 $columns['created_at'] = esc_html__( 'Date', 'formidable' );
883
884 add_screen_option(
885 'per_page',
886 array(
887 'label' => __( 'Forms', 'formidable' ),
888 'default' => 20,
889 'option' => 'formidable_page_formidable_per_page',
890 )
891 );
892
893 return $columns;
894 }
895
896 public static function get_sortable_columns() {
897 return array(
898 'id' => 'id',
899 'name' => 'name',
900 'description' => 'description',
901 'form_key' => 'form_key',
902 'created_at' => 'created_at',
903 );
904 }
905
906 /**
907 * @param mixed $hidden_columns
908 * @return array
909 */
910 public static function hidden_columns( $hidden_columns ) {
911 if ( ! is_array( $hidden_columns ) ) {
912 $hidden_columns = array();
913 }
914
915 $type = FrmAppHelper::get_simple_request(
916 array(
917 'param' => 'form_type',
918 'type' => 'request',
919 )
920 );
921
922 if ( $type === 'template' ) {
923 $hidden_columns[] = 'id';
924 $hidden_columns[] = 'form_key';
925 }
926
927 return $hidden_columns;
928 }
929
930 public static function save_per_page( $save, $option, $value ) {
931 if ( $option == 'formidable_page_formidable_per_page' ) {
932 $save = (int) $value;
933 }
934
935 return $save;
936 }
937
938 private static function get_edit_vars( $id, $errors = array(), $message = '', $create_link = false ) {
939 global $frm_vars;
940
941 $form = FrmForm::getOne( $id );
942 $error_args = array(
943 'title' => __( 'You can\'t edit the form', 'formidable' ),
944 'body' => __( 'You are trying to edit a form that does not exist', 'formidable' ),
945 'cancel_url' => admin_url( 'admin.php?page=formidable' ),
946 'continue_url' => add_query_arg(
947 array(
948 'page' => 'formidable',
949 )
950 ),
951 );
952 if ( ! $form ) {
953 FrmAppController::show_error_modal( $error_args );
954 return;
955 }
956
957 if ( 'trash' === $form->status ) {
958 $error_args['body'] = __( 'The form you\'re trying to edit is in trash. You must restore it first before you can make changes', 'formidable' );
959 $error_args['continue_url'] = add_query_arg(
960 array(
961 'page' => 'formidable',
962 '_wpnonce' => wp_create_nonce( 'untrash_form_' . $id ),
963 'form_type' => 'trash',
964 'frm_action' => 'untrash',
965 'id' => $id,
966 )
967 );
968 $error_args['continue_text'] = __( 'Restore form', 'formidable' );
969 FrmAppController::show_error_modal( $error_args );
970 return;
971 }
972
973 if ( $form->parent_form_id ) {
974 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
975 wp_die( sprintf( esc_html__( 'You are trying to edit a child form. Please edit from %1$shere%2$s', 'formidable' ), '<a href="' . esc_url( FrmForm::get_edit_link( $form->parent_form_id ) ) . '">', '</a>' ) );
976 }
977
978 $frm_field_selection = FrmField::field_selection();
979
980 $fields = FrmField::get_all_for_form( $form->id );
981
982 // Automatically add end section fields if they don't exist (2.0 migration).
983 $reset_fields = false;
984 FrmFormsHelper::auto_add_end_section_fields( $form, $fields, $reset_fields );
985
986 if ( $reset_fields ) {
987 $fields = FrmField::get_all_for_form( $form->id, '', 'exclude' );
988 }
989
990 unset( $reset_fields );
991
992 $args = array( 'parent_form_id' => $form->id );
993 $values = FrmAppHelper::setup_edit_vars( $form, 'forms', '', true, array(), $args );
994
995 /**
996 * Allows modifying the list of fields in the form builder.
997 *
998 * @since 5.0.04
999 *
1000 * @param object[] $fields Array of fields.
1001 * @param array $args The arguments. Contains `form`.
1002 */
1003 $values['fields'] = apply_filters( 'frm_fields_in_form_builder', $fields, compact( 'form' ) );
1004
1005 $edit_message = __( 'Form was successfully updated.', 'formidable' );
1006 if ( $form->is_template && $message == $edit_message ) {
1007 $message = __( 'Template was successfully updated.', 'formidable' );
1008 }
1009
1010 self::maybe_update_form_builder_message( $message );
1011
1012 $all_templates = FrmForm::getAll( array( 'is_template' => 1 ), 'name' );
1013 $has_fields = isset( $values['fields'] ) && ! empty( $values['fields'] );
1014
1015 if ( defined( 'DOING_AJAX' ) ) {
1016 wp_die();
1017 } else {
1018 require( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/edit.php' );
1019 }
1020 }
1021
1022 public static function update_form_builder_fields( $fields, $form ) {
1023 foreach ( $fields as $field ) {
1024 $field->do_not_include_icons = true;
1025 }
1026 return $fields;
1027 }
1028
1029 public static function maybe_update_form_builder_message( &$message ) {
1030 if ( 'form_duplicated' === FrmAppHelper::simple_get( 'message' ) ) {
1031 $message = __( 'Form was Successfully Copied', 'formidable' );
1032 }
1033 }
1034
1035 public static function get_settings_vars( $id, $errors = array(), $args = array() ) {
1036 FrmAppHelper::permission_check( 'frm_edit_forms' );
1037
1038 global $frm_vars;
1039
1040 if ( ! is_array( $args ) ) {
1041 // For reverse compatibility.
1042 $args = array(
1043 'message' => $args,
1044 );
1045 }
1046
1047 $defaults = array(
1048 'message' => '',
1049 'warnings' => array(),
1050 );
1051 $args = array_merge( $defaults, $args );
1052 $message = $args['message'];
1053 $warnings = $args['warnings'];
1054
1055 $form = FrmForm::getOne( $id );
1056 $fields = FrmField::get_all_for_form( $id );
1057 $values = FrmAppHelper::setup_edit_vars( $form, 'forms', $fields, true );
1058
1059 /**
1060 * Allows changing fields in the form settings.
1061 *
1062 * @since 5.0.04
1063 *
1064 * @param array $fields Array of fields.
1065 * @param array $args The arguments. Contains `form`.
1066 */
1067 $values['fields'] = apply_filters( 'frm_fields_in_settings', $values['fields'], compact( 'form' ) );
1068
1069 self::clean_submit_html( $values );
1070
1071 $sections = self::get_settings_tabs( $values );
1072 $current = FrmAppHelper::simple_get( 't', 'sanitize_title', 'advanced_settings' );
1073
1074 require( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/settings.php' );
1075 }
1076
1077 /**
1078 * @since 4.0
1079 */
1080 public static function form_publish_button( $atts ) {
1081 $values = $atts['values'];
1082 include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/_publish_box.php' );
1083 }
1084
1085 /**
1086 * Get a list of all the settings tabs for the form settings page.
1087 *
1088 * @since 4.0
1089 *
1090 * @param array $values
1091 * @return array
1092 */
1093 private static function get_settings_tabs( $values ) {
1094 $sections = array(
1095 'advanced' => array(
1096 'name' => __( 'General', 'formidable' ),
1097 'title' => __( 'General Form Settings', 'formidable' ),
1098 'function' => array( __CLASS__, 'advanced_settings' ),
1099 'icon' => 'frm_icon_font frm_settings_icon',
1100 ),
1101 'email' => array(
1102 'name' => __( 'Actions & Notifications', 'formidable' ),
1103 'function' => array( 'FrmFormActionsController', 'email_settings' ),
1104 'id' => 'frm_notification_settings',
1105 'icon' => 'frm_icon_font frm_mail_bulk_icon',
1106 ),
1107 'permissions' => array(
1108 'name' => __( 'Form Permissions', 'formidable' ),
1109 'icon' => 'frm_icon_font frm_lock_icon',
1110 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1111 'data' => array(
1112 'medium' => 'permissions',
1113 'upgrade' => __( 'Form Permissions', 'formidable' ),
1114 'message' => __( 'Allow editing, protect forms and files, limit entries, and save drafts. Upgrade to get form and entry permissions.', 'formidable' ),
1115 'screenshot' => 'permissions.png',
1116 ),
1117 ),
1118 'scheduling' => array(
1119 'name' => __( 'Form Scheduling', 'formidable' ),
1120 'icon' => 'frm_icon_font frm_calendar_icon',
1121 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1122 'data' => array(
1123 'medium' => 'scheduling',
1124 'upgrade' => __( 'Form scheduling settings', 'formidable' ),
1125 'screenshot' => 'scheduling.png',
1126 ),
1127 ),
1128 'buttons' => array(
1129 'name' => __( 'Buttons', 'formidable' ),
1130 'class' => __CLASS__,
1131 'function' => 'buttons_settings',
1132 'icon' => 'frm_icon_font frm_button_icon',
1133 ),
1134 'landing' => array(
1135 'name' => __( 'Form Landing Page', 'formidable' ),
1136 'icon' => 'frm_icon_font frm_file_text_icon',
1137 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1138 'data' => FrmAppHelper::get_landing_page_upgrade_data_params(),
1139 ),
1140 'chat' => array(
1141 'name' => __( 'Conversational Forms', 'formidable' ),
1142 'icon' => 'frm_icon_font frm_chat_forms_icon',
1143 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1144 'data' => FrmAppHelper::get_upgrade_data_params(
1145 'chat',
1146 array(
1147 'upgrade' => __( 'Conversational Forms', 'formidable' ),
1148 'message' => __( 'Ask one question at a time for automated conversations.', 'formidable' ),
1149 'screenshot' => 'chat.png',
1150 )
1151 ),
1152 ),
1153 'abandonment' => array(
1154 'name' => __( 'Form Abandonment', 'formidable' ),
1155 'icon' => 'frm_icon_font frm_abandoned_icon',
1156 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1157 'data' => FrmAppHelper::get_upgrade_data_params(
1158 'abandonment',
1159 array(
1160 'upgrade' => __( 'Form abandonment settings', 'formidable' ),
1161 'message' => __( 'Unlock the power of data capture to boost lead generation and master the art of form optimization.', 'formidable' ),
1162 'screenshot' => 'abandonment.png',
1163 )
1164 ),
1165 ),
1166 'html' => array(
1167 'name' => __( 'Customize HTML', 'formidable' ),
1168 'class' => __CLASS__,
1169 'function' => 'html_settings',
1170 'icon' => 'frm_icon_font frm_code_icon',
1171 ),
1172 );
1173
1174 foreach ( array( 'landing', 'chat', 'abandonment' ) as $feature ) {
1175 if ( ! FrmAppHelper::show_new_feature( $feature ) ) {
1176 unset( $sections[ $feature ] );
1177 }
1178 }
1179
1180 $sections = apply_filters( 'frm_add_form_settings_section', $sections, $values );
1181
1182 if ( FrmAppHelper::pro_is_installed() && ! FrmAppHelper::meets_min_pro_version( '4.0' ) ) {
1183 // Prevent settings from showing in 2 spots.
1184 unset( $sections['permissions'], $sections['scheduling'] );
1185 }
1186
1187 foreach ( $sections as $key => $section ) {
1188 $defaults = array(
1189 'html_class' => '',
1190 'name' => ucfirst( $key ),
1191 'icon' => 'frm_icon_font frm_settings_icon',
1192 );
1193
1194 $section = array_merge( $defaults, $section );
1195
1196 if ( ! isset( $section['anchor'] ) ) {
1197 $section['anchor'] = $key;
1198 }
1199 $section['anchor'] .= '_settings';
1200
1201 if ( ! isset( $section['title'] ) ) {
1202 $section['title'] = $section['name'];
1203 }
1204
1205 if ( ! isset( $section['id'] ) ) {
1206 $section['id'] = $section['anchor'];
1207 }
1208
1209 $sections[ $key ] = $section;
1210 }
1211
1212 return $sections;
1213 }
1214
1215 /**
1216 * @since 4.0
1217 *
1218 * @param array $values
1219 */
1220 public static function advanced_settings( $values ) {
1221 $first_h3 = 'frm_first_h3';
1222
1223 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/settings-advanced.php';
1224 }
1225
1226 /**
1227 * @param array $values
1228 */
1229 public static function render_spam_settings( $values ) {
1230 if ( function_exists( 'akismet_http_post' ) ) {
1231 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/spam-settings/akismet.php';
1232 }
1233 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/spam-settings/honeypot.php';
1234 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/spam-settings/antispam.php';
1235 }
1236
1237 /**
1238 * @since 4.0
1239 *
1240 * @param array $values
1241 */
1242 public static function buttons_settings( $values ) {
1243 $styles = apply_filters( 'frm_get_style_opts', array() );
1244
1245 $frm_settings = FrmAppHelper::get_settings();
1246 $no_global_style = $frm_settings->load_style === 'none';
1247
1248 include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/settings-buttons.php' );
1249 }
1250
1251 /**
1252 * @since 4.0
1253 *
1254 * @param array $values
1255 */
1256 public static function html_settings( $values ) {
1257 include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/settings-html.php' );
1258 }
1259
1260 /**
1261 * Replace old Submit Button href with new href to avoid errors in Chrome
1262 *
1263 * @since 2.03.08
1264 *
1265 * @param array|boolean $values
1266 */
1267 private static function clean_submit_html( &$values ) {
1268 if ( is_array( $values ) && isset( $values['submit_html'] ) ) {
1269 $values['submit_html'] = str_replace( 'javascript:void(0)', '#', $values['submit_html'] );
1270 }
1271 }
1272
1273 /**
1274 * Updates classes used in submit and prev buttons to avoid conflict with twenty twenty-one theme.
1275 *
1276 * @param array $classes
1277 *
1278 * @return array
1279 */
1280 public static function update_button_classes( $classes ) {
1281 if ( function_exists( 'twenty_twenty_one_setup' ) ) {
1282 $classes[] = 'has-text-color has-background';
1283 }
1284
1285 return $classes;
1286 }
1287
1288 public static function mb_tags_box( $form_id, $class = '' ) {
1289 $fields = FrmField::get_all_for_form( $form_id, '', 'include' );
1290
1291 /**
1292 * Allows modifying the list of fields in the tags box.
1293 *
1294 * @since 5.0.04
1295 *
1296 * @param array $fields The list of fields.
1297 * @param array $args The arguments. Contains `form_id`.
1298 */
1299 $fields = apply_filters( 'frm_fields_in_tags_box', $fields, compact( 'form_id' ) );
1300 $linked_forms = array();
1301 $col = 'one';
1302 $settings_tab = FrmAppHelper::is_admin_page( 'formidable' ) ? true : false;
1303
1304 $cond_shortcodes = apply_filters( 'frm_conditional_shortcodes', array() );
1305 $entry_shortcodes = self::get_shortcode_helpers( $settings_tab );
1306
1307 $advanced_helpers = self::advanced_helpers( compact( 'fields', 'form_id' ) );
1308
1309 include( FrmAppHelper::plugin_path() . '/classes/views/shared/mb_adv_info.php' );
1310 }
1311
1312 /**
1313 * @since 3.04.01
1314 */
1315 private static function advanced_helpers( $atts ) {
1316 $advanced_helpers = array(
1317 'default' => array(
1318 'heading' => __( 'Customize field values with the following parameters.', 'formidable' ),
1319 'codes' => self::get_advanced_shortcodes(),
1320 ),
1321 );
1322
1323 $user_fields = self::user_shortcodes();
1324 if ( ! empty( $user_fields ) ) {
1325 $user_helpers = array();
1326 foreach ( $user_fields as $uk => $uf ) {
1327 $user_helpers[ '|user_id| show="' . $uk . '"' ] = $uf;
1328 unset( $uk, $uf );
1329 }
1330
1331 $advanced_helpers['user_id'] = array(
1332 'codes' => $user_helpers,
1333 );
1334 }
1335
1336 /**
1337 * Add extra helper shortcodes on the Advanced tab in form settings and views
1338 *
1339 * @since 3.04.01
1340 *
1341 * @param array $advanced_helpers
1342 * @param array $atts - Includes fields and form_id
1343 */
1344 return apply_filters( 'frm_advanced_helpers', $advanced_helpers, $atts );
1345 }
1346
1347 /**
1348 * Get an array of the options to display in the advanced tab
1349 * of the customization panel
1350 *
1351 * @since 2.0.6
1352 */
1353 private static function get_advanced_shortcodes() {
1354 $adv_shortcodes = array(
1355 'x sep=", "' => array(
1356 'label' => __( 'Separator', 'formidable' ),
1357 'title' => __( 'Use a different separator for checkbox fields', 'formidable' ),
1358 ),
1359 'x format="d-m-Y"' => array(
1360 'label' => __( 'Date Format', 'formidable' ),
1361 ),
1362 'x show="field_label"' => array(
1363 'label' => __( 'Field Label', 'formidable' ),
1364 ),
1365 'x wpautop=0' => array(
1366 'label' => __( 'No Auto P', 'formidable' ),
1367 'title' => __( 'Do not automatically add any paragraphs or line breaks', 'formidable' ),
1368 ),
1369 );
1370 $adv_shortcodes = apply_filters( 'frm_advanced_shortcodes', $adv_shortcodes );
1371
1372 // __( 'Leave blank instead of defaulting to User Login', 'formidable' ) : blank=1
1373
1374 return $adv_shortcodes;
1375 }
1376
1377 /**
1378 * @since 3.04.01
1379 */
1380 private static function user_shortcodes() {
1381 $options = array(
1382 'ID' => __( 'User ID', 'formidable' ),
1383 'first_name' => __( 'First Name', 'formidable' ),
1384 'last_name' => __( 'Last Name', 'formidable' ),
1385 'display_name' => __( 'Display Name', 'formidable' ),
1386 'user_login' => __( 'User Login', 'formidable' ),
1387 'user_email' => __( 'Email', 'formidable' ),
1388 'avatar' => __( 'Avatar', 'formidable' ),
1389 'author_link' => __( 'Author Link', 'formidable' ),
1390 );
1391
1392 return apply_filters( 'frm_user_shortcodes', $options );
1393 }
1394
1395 /**
1396 * Get an array of the helper shortcodes to display in the customization panel
1397 *
1398 * @since 2.0.6
1399 */
1400 private static function get_shortcode_helpers( $settings_tab ) {
1401 $entry_shortcodes = array(
1402 'id' => __( 'Entry ID', 'formidable' ),
1403 'key' => __( 'Entry Key', 'formidable' ),
1404 'post_id' => __( 'Post ID', 'formidable' ),
1405 'ip' => __( 'User IP', 'formidable' ),
1406 'created-at' => __( 'Entry created', 'formidable' ),
1407 'updated-at' => __( 'Entry updated', 'formidable' ),
1408 '' => '',
1409 'siteurl' => __( 'Site URL', 'formidable' ),
1410 'sitename' => __( 'Site Name', 'formidable' ),
1411 );
1412
1413 if ( ! FrmAppHelper::pro_is_installed() ) {
1414 unset( $entry_shortcodes['post_id'] );
1415 }
1416
1417 if ( $settings_tab ) {
1418 $entry_shortcodes['default-message'] = __( 'Default Msg', 'formidable' );
1419 $entry_shortcodes['default-html'] = __( 'Default HTML', 'formidable' );
1420 $entry_shortcodes['default-plain'] = __( 'Default Plain', 'formidable' );
1421 $entry_shortcodes['form_name'] = __( 'Form Name', 'formidable' );
1422 }
1423
1424 /**
1425 * Use this hook to add or remove buttons in the helpers section
1426 * in the customization panel
1427 *
1428 * @since 2.0.6
1429 */
1430 $entry_shortcodes = apply_filters( 'frm_helper_shortcodes', $entry_shortcodes, $settings_tab );
1431
1432 return $entry_shortcodes;
1433 }
1434
1435 /**
1436 * Insert the form class setting into the form.
1437 *
1438 * @param stdClass $form
1439 * @return void
1440 */
1441 public static function form_classes( $form ) {
1442 if ( isset( $form->options['form_class'] ) ) {
1443 echo esc_attr( sanitize_text_field( $form->options['form_class'] ) );
1444 }
1445
1446 if ( ! empty( $form->options['js_validate'] ) ) {
1447 echo ' frm_js_validate ';
1448 self::add_js_validate_form_to_global_vars( $form );
1449 }
1450
1451 if ( ! FrmFormsHelper::should_use_pro_for_ajax_submit() && FrmForm::is_ajax_on( $form ) ) {
1452 echo ' frm_ajax_submit ';
1453 }
1454 }
1455
1456 /**
1457 * @since 5.0.03
1458 *
1459 * @param stdClass $form
1460 */
1461 public static function add_js_validate_form_to_global_vars( $form ) {
1462 global $frm_vars;
1463 if ( ! isset( $frm_vars['js_validate_forms'] ) ) {
1464 $frm_vars['js_validate_forms'] = array();
1465 }
1466 $frm_vars['js_validate_forms'][ $form->id ] = $form;
1467 }
1468
1469 public static function get_email_html() {
1470 FrmAppHelper::permission_check( 'frm_view_forms' );
1471 check_ajax_referer( 'frm_ajax', 'nonce' );
1472
1473 echo FrmEntriesController::show_entry_shortcode( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1474 array(
1475 'form_id' => FrmAppHelper::get_post_param( 'form_id', '', 'absint' ),
1476 'default_email' => true,
1477 'plain_text' => FrmAppHelper::get_post_param( 'plain_text', '', 'absint' ),
1478 )
1479 );
1480 wp_die();
1481 }
1482
1483 /**
1484 * @param string $content
1485 * @param stdClass|string|int $form
1486 * @param stdClass|string|int|false $entry
1487 * @return string
1488 */
1489 public static function filter_content( $content, $form, $entry = false ) {
1490 $content = self::replace_form_name_shortcodes( $content, $form );
1491
1492 self::get_entry_by_param( $entry );
1493 if ( ! $entry ) {
1494 return $content;
1495 }
1496
1497 if ( is_object( $form ) ) {
1498 $form = $form->id;
1499 }
1500
1501 $shortcodes = FrmFieldsHelper::get_shortcodes( $content, $form );
1502 $content = apply_filters( 'frm_replace_content_shortcodes', $content, $entry, $shortcodes );
1503
1504 return $content;
1505 }
1506
1507 /**
1508 * Replace any [form_name] shortcodes in a string.
1509 *
1510 * @since 5.5
1511 *
1512 * @param string|array $string
1513 * @param stdClass|string|int $form
1514 * @return string|array
1515 */
1516 public static function replace_form_name_shortcodes( $string, $form ) {
1517 if ( ! is_string( $string ) ) {
1518 return $string;
1519 }
1520
1521 if ( false === strpos( $string, '[form_name]' ) ) {
1522 return $string;
1523 }
1524
1525 if ( ! is_object( $form ) ) {
1526 $form = FrmForm::getOne( $form );
1527 }
1528
1529 $form_name = is_object( $form ) ? $form->name : '';
1530 return str_replace( '[form_name]', $form_name, $string );
1531 }
1532
1533 /**
1534 * @param stdClass|string|int|false $entry
1535 * @return void
1536 */
1537 private static function get_entry_by_param( &$entry ) {
1538 if ( ! $entry || ! is_object( $entry ) ) {
1539 if ( ! $entry || ! is_numeric( $entry ) ) {
1540 $entry = FrmAppHelper::get_post_param( 'id', false, 'sanitize_title' );
1541 }
1542
1543 FrmEntry::maybe_get_entry( $entry );
1544 }
1545 }
1546
1547 public static function replace_content_shortcodes( $content, $entry, $shortcodes ) {
1548 return FrmFieldsHelper::replace_content_shortcodes( $content, $entry, $shortcodes );
1549 }
1550
1551 public static function process_bulk_form_actions( $errors ) {
1552 if ( ! $_REQUEST ) {
1553 return $errors;
1554 }
1555
1556 $bulkaction = FrmAppHelper::get_param( 'action', '', 'get', 'sanitize_text_field' );
1557 if ( $bulkaction == - 1 ) {
1558 $bulkaction = FrmAppHelper::get_param( 'action2', '', 'get', 'sanitize_title' );
1559 }
1560
1561 if ( ! empty( $bulkaction ) && strpos( $bulkaction, 'bulk_' ) === 0 ) {
1562 FrmAppHelper::remove_get_action();
1563
1564 $bulkaction = str_replace( 'bulk_', '', $bulkaction );
1565 }
1566
1567 $ids = FrmAppHelper::get_param( 'item-action', '', 'get', 'sanitize_text_field' );
1568 if ( empty( $ids ) ) {
1569 $errors[] = __( 'No forms were specified', 'formidable' );
1570
1571 return $errors;
1572 }
1573
1574 $permission_error = FrmAppHelper::permission_nonce_error( '', '_wpnonce', 'bulk-toplevel_page_formidable' );
1575 if ( $permission_error !== false ) {
1576 $errors[] = $permission_error;
1577
1578 return $errors;
1579 }
1580
1581 if ( ! is_array( $ids ) ) {
1582 $ids = explode( ',', $ids );
1583 }
1584
1585 switch ( $bulkaction ) {
1586 case 'delete':
1587 $message = self::bulk_destroy( $ids );
1588 break;
1589 case 'trash':
1590 $message = self::bulk_trash( $ids );
1591 break;
1592 case 'untrash':
1593 $message = self::bulk_untrash( $ids );
1594 }
1595
1596 if ( isset( $message ) && ! empty( $message ) ) {
1597 $errors['message'] = $message;
1598 }
1599
1600 return $errors;
1601 }
1602
1603 public static function route() {
1604 $action = isset( $_REQUEST['frm_action'] ) ? 'frm_action' : 'action';
1605 $vars = array();
1606 FrmAppHelper::include_svg();
1607
1608 if ( isset( $_POST['frm_compact_fields'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1609 FrmAppHelper::permission_check( 'frm_edit_forms' );
1610
1611 // Javascript needs to be allowed in some field settings.
1612 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
1613 $json_vars = htmlspecialchars_decode( nl2br( str_replace( '&quot;', '"', wp_unslash( $_POST['frm_compact_fields'] ) ) ) );
1614 $json_vars = json_decode( $json_vars, true );
1615 if ( empty( $json_vars ) ) {
1616 // json decoding failed so we should return an error message.
1617 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
1618 if ( 'edit' == $action ) {
1619 $action = 'update';
1620 }
1621
1622 add_filter( 'frm_validate_form', 'FrmFormsController::json_error' );
1623 } else {
1624 $vars = FrmAppHelper::json_to_array( $json_vars );
1625 $action = $vars[ $action ];
1626 unset( $_REQUEST['frm_compact_fields'], $_POST['frm_compact_fields'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1627 $_REQUEST = array_merge( $_REQUEST, $vars ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1628 $_POST = array_merge( $_POST, $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1629 }
1630 } else {
1631 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
1632 if ( isset( $_REQUEST['delete_all'] ) ) {
1633 // Override the action for this page.
1634 $action = 'delete_all';
1635 }
1636 }
1637
1638 add_action( 'frm_load_form_hooks', 'FrmHooksController::trigger_load_form_hooks' );
1639 FrmAppHelper::trigger_hook_load( 'form' );
1640
1641 switch ( $action ) {
1642 case 'new':
1643 return self::new_form( $vars );
1644 case 'create':
1645 case 'edit':
1646 case 'update':
1647 case 'trash':
1648 case 'untrash':
1649 case 'destroy':
1650 case 'delete_all':
1651 case 'settings':
1652 case 'update_settings':
1653 return self::$action( $vars );
1654 case 'lite-reports':
1655 return self::no_reports( $vars );
1656 case 'views':
1657 return self::no_views( $vars );
1658 default:
1659 do_action( 'frm_form_action_' . $action );
1660 if ( apply_filters( 'frm_form_stop_action_' . $action, false ) ) {
1661 return;
1662 }
1663
1664 $action = FrmAppHelper::get_param( 'action', '', 'get', 'sanitize_text_field' );
1665 if ( $action == - 1 ) {
1666 $action = FrmAppHelper::get_param( 'action2', '', 'get', 'sanitize_title' );
1667 }
1668
1669 if ( strpos( $action, 'bulk_' ) === 0 ) {
1670 FrmAppHelper::remove_get_action();
1671
1672 self::list_form();
1673 return;
1674 }
1675
1676 $message = FrmAppHelper::get_param( 'message' );
1677 if ( 'form_duplicate_error' === $message ) {
1678 self::display_forms_list( array(), '', array( __( 'There was a problem duplicating the form', 'formidable' ) ) );
1679 return;
1680 }
1681
1682 self::display_forms_list();
1683
1684 return;
1685 }
1686 }
1687
1688 /**
1689 * Rename a form.
1690 *
1691 * Handles the AJAX request for renaming a form.
1692 *
1693 * @since 6.7
1694 *
1695 * @return void
1696 */
1697 public static function rename_form() {
1698 // Check permission and nonce
1699 FrmAppHelper::permission_check( 'frm_edit_forms' );
1700 check_ajax_referer( 'frm_ajax', 'nonce' );
1701
1702 // Get posted data
1703 $form_id = FrmAppHelper::get_post_param( 'form_id', '', 'absint' );
1704 $name = FrmAppHelper::get_post_param( 'form_name', '', 'sanitize_text_field' );
1705
1706 // Update the form name and form key.
1707 $form_key = FrmAppHelper::get_unique_key( sanitize_title( $name ), 'frm_forms', 'form_key' );
1708 FrmForm::update( $form_id, compact( 'name', 'form_key' ) );
1709
1710 wp_send_json_success( compact( 'form_key' ) );
1711 }
1712
1713 public static function json_error( $errors ) {
1714 $errors['json'] = __( 'Abnormal HTML characters prevented your form from saving correctly', 'formidable' );
1715
1716 return $errors;
1717 }
1718
1719 /**
1720 * Education for premium features.
1721 *
1722 * @since 4.05
1723 */
1724 public static function add_form_style_tab_options() {
1725 include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/add_form_style_options.php' );
1726 }
1727
1728 /**
1729 * Add education about views.
1730 *
1731 * @since 4.07
1732 */
1733 public static function no_views( $values = array() ) {
1734 FrmAppHelper::include_svg();
1735 $id = FrmAppHelper::get_param( 'form', '', 'get', 'absint' );
1736 $form = $id ? FrmForm::getOne( $id ) : false;
1737
1738 include FrmAppHelper::plugin_path() . '/classes/views/shared/views-info.php';
1739 }
1740
1741 /**
1742 * Add education about reports.
1743 *
1744 * @since 4.07
1745 */
1746 public static function no_reports( $values = array() ) {
1747 $id = FrmAppHelper::get_param( 'form', '', 'get', 'absint' );
1748 $form = $id ? FrmForm::getOne( $id ) : false;
1749
1750 include FrmAppHelper::plugin_path() . '/classes/views/shared/reports-info.php';
1751 }
1752
1753 /* FRONT-END FORMS */
1754 public static function admin_bar_css() {
1755 if ( is_admin() || ! current_user_can( 'frm_edit_forms' ) ) {
1756 return;
1757 }
1758
1759 self::move_menu_to_footer();
1760
1761 add_action( 'wp_before_admin_bar_render', 'FrmFormsController::admin_bar_configure' );
1762 FrmAppHelper::load_font_style();
1763 }
1764
1765 /**
1766 * @since 4.05.02
1767 */
1768 private static function move_menu_to_footer() {
1769 $settings = FrmAppHelper::get_settings();
1770 if ( empty( $settings->admin_bar ) ) {
1771 remove_action( 'wp_body_open', 'wp_admin_bar_render', 0 );
1772 }
1773 }
1774
1775 public static function admin_bar_configure() {
1776 global $frm_vars;
1777 if ( empty( $frm_vars['forms_loaded'] ) ) {
1778 return;
1779 }
1780
1781 $actions = array();
1782 foreach ( $frm_vars['forms_loaded'] as $form ) {
1783 if ( is_object( $form ) ) {
1784 $actions[ $form->id ] = $form->name;
1785 }
1786 unset( $form );
1787 }
1788
1789 if ( empty( $actions ) ) {
1790 return;
1791 }
1792
1793 self::add_menu_to_admin_bar();
1794 self::add_forms_to_admin_bar( $actions );
1795 }
1796
1797 /**
1798 * @since 2.05.07
1799 */
1800 public static function add_menu_to_admin_bar() {
1801 global $wp_admin_bar;
1802
1803 $wp_admin_bar->add_node(
1804 array(
1805 'id' => 'frm-forms',
1806 'title' => '<span class="ab-icon"></span><span class="ab-label">' . FrmAppHelper::get_menu_name() . '</span>',
1807 'href' => admin_url( 'admin.php?page=formidable' ),
1808 'meta' => array(
1809 'title' => FrmAppHelper::get_menu_name(),
1810 ),
1811 )
1812 );
1813 }
1814
1815 /**
1816 * @since 2.05.07
1817 */
1818 private static function add_forms_to_admin_bar( $actions ) {
1819 global $wp_admin_bar;
1820
1821 asort( $actions );
1822
1823 foreach ( $actions as $form_id => $name ) {
1824
1825 $wp_admin_bar->add_node(
1826 array(
1827 'parent' => 'frm-forms',
1828 'id' => 'edit_form_' . $form_id,
1829 'title' => empty( $name ) ? __( '(no title)', 'formidable' ) : $name,
1830 'href' => FrmForm::get_edit_link( $form_id ),
1831 )
1832 );
1833 }
1834 }
1835
1836 /**
1837 * The formidable shortcode
1838 *
1839 * @param array $atts The params from the shortcode.
1840 * @return string
1841 */
1842 public static function get_form_shortcode( $atts ) {
1843 global $frm_vars;
1844 if ( isset( $frm_vars['skip_shortcode'] ) && $frm_vars['skip_shortcode'] ) {
1845 $sc = '[formidable';
1846 $sc .= FrmAppHelper::array_to_html_params( $atts );
1847 return $sc . ']';
1848 }
1849
1850 $shortcode_atts = shortcode_atts(
1851 array(
1852 'id' => '',
1853 'key' => '',
1854 'title' => 'auto',
1855 'description' => 'auto',
1856 'readonly' => false,
1857 'entry_id' => false,
1858 'fields' => array(),
1859 'exclude_fields' => array(),
1860 'minimize' => false,
1861 ),
1862 $atts
1863 );
1864 do_action( 'formidable_shortcode_atts', $shortcode_atts, $atts );
1865
1866 return self::show_form( $shortcode_atts['id'], $shortcode_atts['key'], $shortcode_atts['title'], $shortcode_atts['description'], $atts );
1867 }
1868
1869 /**
1870 * @since 5.2.01
1871 *
1872 * @param string|int|false $id
1873 * @param string|false $key
1874 * @return stdClass|false
1875 */
1876 private static function maybe_get_form_by_id_or_key( $id, $key ) {
1877 if ( ! $id ) {
1878 $id = $key;
1879 }
1880 return self::maybe_get_form_to_show( $id );
1881 }
1882
1883 /**
1884 * @param string|int|false $id
1885 * @param string|false $key
1886 * @param string|int|bool $title may be 'auto', true, false, 'true', 'false', 'yes', '1', 1, '0', 0.
1887 * @param string|int|bool $description may be 'auto', true, false, 'true', 'false', 'yes', '1', 1, '0', 0.
1888 * @param array $atts
1889 * @return string
1890 */
1891 public static function show_form( $id = '', $key = '', $title = false, $description = false, $atts = array() ) {
1892 $form = self::maybe_get_form_by_id_or_key( $id, $key );
1893
1894 if ( ! $form ) {
1895 return __( 'Please select a valid form', 'formidable' );
1896 }
1897
1898 if ( 'auto' === $title ) {
1899 $title = ! empty( $form->options['show_title'] );
1900 }
1901
1902 if ( 'auto' === $description ) {
1903 $description = ! empty( $form->options['show_description'] );
1904 }
1905
1906 FrmAppController::maybe_update_styles();
1907
1908 add_action( 'frm_load_form_hooks', 'FrmHooksController::trigger_load_form_hooks' );
1909 FrmAppHelper::trigger_hook_load( 'form', $form );
1910
1911 $form = apply_filters( 'frm_pre_display_form', $form );
1912
1913 $frm_settings = FrmAppHelper::get_settings( array( 'current_form' => $form->id ) );
1914
1915 if ( self::is_viewable_draft_form( $form ) ) {
1916 // don't show a draft form on a page
1917 $form = __( 'Please select a valid form', 'formidable' );
1918 } elseif ( ! FrmForm::is_visible_to_user( $form ) ) {
1919 $form = do_shortcode( $frm_settings->login_msg );
1920 } else {
1921 do_action( 'frm_pre_get_form', $form );
1922 $form = self::get_form( $form, $title, $description, $atts );
1923
1924 /**
1925 * Use this shortcode to check for external shortcodes that may span
1926 * across multiple fields in the customizable HTML
1927 *
1928 * @since 2.0.8
1929 */
1930 $form = apply_filters( 'frm_filter_final_form', $form );
1931 }
1932
1933 return $form;
1934 }
1935
1936 /**
1937 * @param string|int|false $id
1938 * @return stdClass|false
1939 */
1940 private static function maybe_get_form_to_show( $id ) {
1941 $form = false;
1942
1943 if ( ! empty( $id ) ) { // form id or key is set
1944 $form = FrmForm::getOne( $id );
1945 if ( ! $form || $form->parent_form_id || $form->status === 'trash' ) {
1946 $form = false;
1947 }
1948 }
1949
1950 return $form;
1951 }
1952
1953 private static function is_viewable_draft_form( $form ) {
1954 return $form->status === 'draft' && current_user_can( 'frm_edit_forms' ) && ! FrmAppHelper::is_preview_page();
1955 }
1956
1957 public static function get_form( $form, $title, $description, $atts = array() ) {
1958 ob_start();
1959
1960 do_action( 'frm_before_get_form', $atts );
1961
1962 self::get_form_contents( $form, $title, $description, $atts );
1963 self::enqueue_scripts( FrmForm::get_params( $form ) );
1964
1965 $contents = ob_get_contents();
1966 ob_end_clean();
1967
1968 self::maybe_minimize_form( $atts, $contents );
1969
1970 return $contents;
1971 }
1972
1973 public static function enqueue_scripts( $params ) {
1974 do_action( 'frm_enqueue_form_scripts', $params );
1975 }
1976
1977 public static function get_form_contents( $form, $title, $description, $atts ) {
1978 $params = FrmForm::get_params( $form );
1979 $errors = self::get_saved_errors( $form, $params );
1980 $fields = FrmFieldsHelper::get_form_fields( $form->id, $errors );
1981 $reset = false;
1982 $pass_args = compact( 'form', 'fields', 'errors', 'title', 'description', 'reset' );
1983
1984 $pass_args['action'] = $params['action'];
1985 $handle_process_here = $params['action'] === 'create' && $params['posted_form_id'] == $form->id && $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing
1986
1987 if ( ! $handle_process_here ) {
1988 FrmFormState::set_initial_value( 'title', $title );
1989 FrmFormState::set_initial_value( 'description', $description );
1990
1991 do_action( 'frm_display_form_action', $params, $fields, $form, $title, $description );
1992 if ( apply_filters( 'frm_continue_to_new', true, $form->id, $params['action'] ) ) {
1993 self::show_form_after_submit( $pass_args );
1994 }
1995 } elseif ( ! empty( $errors ) ) {
1996 self::show_form_after_submit( $pass_args );
1997
1998 } else {
1999
2000 do_action( 'frm_validate_form_creation', $params, $fields, $form, $title, $description );
2001
2002 if ( apply_filters( 'frm_continue_to_create', true, $form->id ) ) {
2003 $entry_id = self::just_created_entry( $form->id );
2004 $pass_args['entry_id'] = $entry_id;
2005 $pass_args['reset'] = true;
2006
2007 self::run_on_submit_actions( $pass_args );
2008
2009 do_action(
2010 'frm_after_entry_processed',
2011 array(
2012 'entry_id' => $entry_id,
2013 'form' => $form,
2014 )
2015 );
2016 }
2017 }
2018 }
2019
2020 /**
2021 * If the form was processed earlier (init), get the generated errors
2022 *
2023 * @since 2.05
2024 */
2025 private static function get_saved_errors( $form, $params ) {
2026 global $frm_vars;
2027
2028 if ( $params['posted_form_id'] == $form->id && $_POST && isset( $frm_vars['created_entries'][ $form->id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
2029 $errors = $frm_vars['created_entries'][ $form->id ]['errors'];
2030 } else {
2031 $errors = array();
2032 }
2033
2034 /**
2035 * Allows modifying the generated errors if the form was processed earlier.
2036 *
2037 * @since 5.2.03
2038 *
2039 * @param array $errors Errors data. Is empty array if no errors found.
2040 * @param array $params Form params. See {@see FrmForm::get_params()}.
2041 */
2042 return apply_filters( 'frm_saved_errors', $errors, $params );
2043 }
2044
2045 /**
2046 * @since 2.2.7
2047 */
2048 public static function just_created_entry( $form_id ) {
2049 global $frm_vars;
2050
2051 return ( isset( $frm_vars['created_entries'] ) && isset( $frm_vars['created_entries'][ $form_id ] ) && isset( $frm_vars['created_entries'][ $form_id ]['entry_id'] ) ) ? $frm_vars['created_entries'][ $form_id ]['entry_id'] : 0;
2052 }
2053
2054 /**
2055 * Gets confirmation method.
2056 *
2057 * @since 3.0
2058 * @since 6.0 This method can return an array of met On Submit actions.
2059 *
2060 * @param array $atts {
2061 * Atts.
2062 *
2063 * @type object $form Form object.
2064 * @type int $entry_id Entry ID.
2065 * }
2066 * @return string|array
2067 */
2068 private static function get_confirmation_method( $atts ) {
2069 $action = FrmOnSubmitHelper::current_event( $atts );
2070 $opt = 'update' === $action ? 'edit_action' : 'success_action';
2071 $method = ( isset( $atts['form']->options[ $opt ] ) && ! empty( $atts['form']->options[ $opt ] ) ) ? $atts['form']->options[ $opt ] : 'message';
2072
2073 if ( ! empty( $atts['entry_id'] ) ) {
2074 $met_actions = self::get_met_on_submit_actions( $atts, $action );
2075 if ( $met_actions ) {
2076 $method = $met_actions;
2077 }
2078 }
2079
2080 $method = apply_filters( 'frm_success_filter', $method, $atts['form'], $action );
2081
2082 if ( $method != 'message' && ( ! $atts['entry_id'] || ! is_numeric( $atts['entry_id'] ) ) ) {
2083 $method = 'message';
2084 }
2085
2086 return $method;
2087 }
2088
2089 public static function maybe_trigger_redirect( $form, $params, $args ) {
2090 if ( ! isset( $params['id'] ) ) {
2091 global $frm_vars;
2092 $params['id'] = $frm_vars['created_entries'][ $form->id ]['entry_id'];
2093 }
2094
2095 $conf_method = self::get_confirmation_method(
2096 array(
2097 'form' => $form,
2098 'entry_id' => $params['id'],
2099 'action' => FrmOnSubmitHelper::current_event( $params ),
2100 )
2101 );
2102
2103 self::maybe_trigger_redirect_with_action( $conf_method, $form, $params, $args );
2104 }
2105
2106 /**
2107 * Maybe trigger redirect with the new Confirmation action.
2108 *
2109 * @since 6.1.1
2110 *
2111 * @param array|string $conf_method Array of confirmation actions or the action type string.
2112 * @param object $form Form object.
2113 * @param array $params See {@see FrmFormsController::maybe_trigger_redirect()}.
2114 * @param array $args See {@see FrmFormsController::maybe_trigger_redirect()}.
2115 */
2116 public static function maybe_trigger_redirect_with_action( $conf_method, $form, $params, $args ) {
2117 if ( is_array( $conf_method ) && 1 === count( $conf_method ) ) {
2118 if ( 'redirect' === FrmOnSubmitHelper::get_action_type( $conf_method[0] ) ) {
2119 $event = FrmOnSubmitHelper::current_event( $params );
2120 FrmOnSubmitHelper::populate_on_submit_data( $form->options, $conf_method[0], $event );
2121 $conf_method = 'redirect';
2122 }
2123 }
2124
2125 if ( 'redirect' === $conf_method ) {
2126 self::trigger_redirect( $form, $params, $args );
2127 }
2128 }
2129
2130 public static function trigger_redirect( $form, $params, $args ) {
2131 $success_args = array(
2132 'action' => $params['action'],
2133 'conf_method' => 'redirect',
2134 'form' => $form,
2135 'entry_id' => $params['id'],
2136 );
2137
2138 if ( isset( $args['ajax'] ) ) {
2139 $success_args['ajax'] = $args['ajax'];
2140 }
2141
2142 self::run_success_action( $success_args );
2143 }
2144
2145 /**
2146 * Used when the success action is not 'message'
2147 *
2148 * @since 2.05
2149 * @since 6.0 `$args['force_delay_redirect']` is added.
2150 *
2151 * @param array $args {
2152 * The args.
2153 *
2154 * @type string $conf_method The method.
2155 * @type object $form Form object.
2156 * @type int $entry_id Entry ID.
2157 * @type string $action The action event. Accepts `create` or `update`.
2158 * @type array $fields The array of fields.
2159 * @type int $force_delay_redirect Force to show the message before redirecting in case redirect method runs.
2160 * }
2161 */
2162 public static function run_success_action( $args ) {
2163 global $frm_vars;
2164 $extra_args = $args;
2165 unset( $extra_args['form'] );
2166
2167 do_action( 'frm_success_action', $args['conf_method'], $args['form'], $args['form']->options, $args['entry_id'], $extra_args );
2168
2169 $opt = ( ! isset( $args['action'] ) || $args['action'] === 'create' ) ? 'success' : 'edit';
2170
2171 $args['success_opt'] = $opt;
2172 $args['ajax'] = ! empty( $frm_vars['ajax'] );
2173
2174 if ( $args['conf_method'] === 'page' && is_numeric( $args['form']->options[ $opt . '_page_id' ] ) ) {
2175 self::load_page_after_submit( $args );
2176 } elseif ( $args['conf_method'] === 'redirect' ) {
2177 self::redirect_after_submit( $args );
2178 } else {
2179 self::show_message_after_save( $args );
2180 }
2181 }
2182
2183 /**
2184 * Gets met On Submit actions.
2185 *
2186 * @since 6.0
2187 *
2188 * @param array $args See {@see FrmFormsController::run_success_action()}.
2189 * @param string $event Form event. Default is `create`.
2190 * @return array Array of actions that meet the conditional logics.
2191 */
2192 public static function get_met_on_submit_actions( $args, $event = 'create' ) {
2193 if ( ! FrmOnSubmitHelper::form_has_migrated( $args['form'] ) ) {
2194 return array();
2195 }
2196
2197 // If a redirect action has already opened the URL in a new tab, we show the default message in the currect tab.
2198 if ( ! empty( self::$redirected_in_new_tab[ $args['form']->id ] ) ) {
2199 return array( FrmOnSubmitHelper::get_fallback_action_after_open_in_new_tab( $event ) );
2200 }
2201
2202 $entry = FrmEntry::getOne( $args['entry_id'], true );
2203 $actions = FrmOnSubmitHelper::get_actions( $args['form']->id );
2204 $met_actions = array();
2205 $has_redirect = false;
2206
2207 foreach ( $actions as $action ) {
2208 if ( ! in_array( $event, $action->post_content['event'], true ) ) {
2209 continue;
2210 }
2211
2212 if ( FrmFormAction::action_conditions_met( $action, $entry ) ) {
2213 continue;
2214 }
2215
2216 $action_type = FrmOnSubmitHelper::get_action_type( $action );
2217
2218 if ( 'redirect' === $action_type ) {
2219 if ( $has_redirect ) { // Do not process because we run the first redirect action only.
2220 continue;
2221 }
2222 }
2223
2224 if ( ! self::is_valid_on_submit_action( $action, $args, $event ) ) {
2225 continue;
2226 }
2227
2228 if ( 'redirect' === $action_type ) {
2229 $has_redirect = true;
2230 }
2231
2232 $met_actions[] = $action;
2233 unset( $action );
2234 }
2235
2236 $args['event'] = $event;
2237
2238 /**
2239 * Filters the On Submit actions that meet the conditional logics.
2240 *
2241 * @since 6.0
2242 *
2243 * @param array $met_actions Actions that meet the conditional logics.
2244 * @param array $args See {@see FrmFormsController::run_success_action()}. `$args['event']` is also added.
2245 */
2246 $met_actions = apply_filters( 'frm_get_met_on_submit_actions', $met_actions, $args );
2247
2248 if ( empty( $met_actions ) ) {
2249 $met_actions = array( FrmOnSubmitHelper::get_fallback_action( $event ) );
2250 }
2251
2252 return $met_actions;
2253 }
2254
2255 /**
2256 * Checks if a Confirmation action has the valid data.
2257 *
2258 * @since 6.1.2
2259 *
2260 * @param object $action Form action object.
2261 * @param array $args See {@see FrmFormsController::run_success_action()}.
2262 * @param string $event Form event. Default is `create`.
2263 * @return bool
2264 */
2265 private static function is_valid_on_submit_action( $action, $args, $event = 'create' ) {
2266 $action_type = FrmOnSubmitHelper::get_action_type( $action );
2267
2268 if ( 'redirect' === $action_type ) {
2269 // Run through frm_redirect_url filter. This is used for the valid action check.
2270 $action->post_content['success_url'] = apply_filters(
2271 'frm_redirect_url',
2272 $action->post_content['success_url'],
2273 $args['form'],
2274 $args + array( 'action' => $event )
2275 );
2276
2277 return ! empty( $action->post_content['success_url'] );
2278 }
2279
2280 if ( 'page' === $action_type ) {
2281 if ( empty( $action->post_content['success_page_id'] ) ) {
2282 return false;
2283 }
2284
2285 $page = get_post( $action->post_content['success_page_id'] );
2286 if ( ! $page || 'trash' === $page->post_status ) {
2287 return false;
2288 }
2289 }
2290
2291 return true;
2292 }
2293
2294 /**
2295 * Runs On Submit actions.
2296 *
2297 * @since 6.0
2298 *
2299 * @param array $args See inside {@see FrmFormsController::get_form_contents()} method.
2300 */
2301 public static function run_on_submit_actions( $args ) {
2302 $args['conf_method'] = self::get_confirmation_method(
2303 array(
2304 'form' => $args['form'],
2305 'entry_id' => $args['entry_id'],
2306 'action' => FrmOnSubmitHelper::current_event( $args ),
2307 )
2308 );
2309 if ( ! is_array( $args['conf_method'] ) ) {
2310 self::run_success_action( $args );
2311 return;
2312 }
2313
2314 // If conf_method is an array, run On Submit actions.
2315 if ( ! $args['conf_method'] ) {
2316 // Use default message.
2317 FrmOnSubmitHelper::populate_on_submit_data( $args['form']->options );
2318 self::run_success_action( $args );
2319 } elseif ( 1 === count( $args['conf_method'] ) ) {
2320 FrmOnSubmitHelper::populate_on_submit_data( $args['form']->options, reset( $args['conf_method'] ) );
2321 $args['conf_method'] = $args['form']->options['success_action'];
2322 self::run_success_action( $args );
2323 } else {
2324 self::run_multi_on_submit_actions( $args );
2325 }
2326 }
2327
2328 /**
2329 * Runs multiple success actions.
2330 *
2331 * @since 6.0
2332 *
2333 * @param array $args See {@see FrmFormsController::run_success_action()}.
2334 */
2335 public static function run_multi_on_submit_actions( $args ) {
2336 $redirect_action = null;
2337 foreach ( $args['conf_method'] as $action ) {
2338 if ( 'redirect' === FrmOnSubmitHelper::get_action_type( $action ) ) {
2339 // We catch the redirect action to run it last.
2340 $redirect_action = $action;
2341 continue;
2342 }
2343
2344 self::run_single_on_submit_action( $args, $action );
2345
2346 unset( $action );
2347 }
2348
2349 if ( $redirect_action ) {
2350 // Show script to delay the redirection.
2351 $args['force_delay_redirect'] = true;
2352 self::run_single_on_submit_action( $args, $redirect_action );
2353 }
2354 }
2355
2356 /**
2357 * Runs single On Submit action.
2358 *
2359 * @since 6.0
2360 *
2361 * @param array $args See {@see FrmFormsController::run_success_action()}.
2362 * @param object $action On Submit action object.
2363 */
2364 public static function run_single_on_submit_action( $args, $action ) {
2365 $new_args = self::get_run_success_action_args( $args, $action );
2366 self::run_success_action( $new_args );
2367 }
2368
2369 /**
2370 * Gets run_success_action() args from the On Submit action.
2371 *
2372 * @since 6.0
2373 *
2374 * @param array $args See {@see FrmFormsController::run_success_action()}.
2375 * @param object $action On Submit action object.
2376 * @return array
2377 */
2378 private static function get_run_success_action_args( $args, $action ) {
2379 $new_args = $args;
2380
2381 FrmOnSubmitHelper::populate_on_submit_data( $new_args['form']->options, $action, $args['action'] );
2382
2383 $opt = 'update' === $args['action'] ? 'edit_' : 'success_';
2384
2385 $new_args['conf_method'] = $new_args['form']->options[ $opt . 'action' ];
2386
2387 /**
2388 * Filters the run success action args.
2389 *
2390 * @since 6.0
2391 *
2392 * @param array $new_args The new args.
2393 * @param array $args The old args. See {@see FrmFormsController::run_success_action()}.
2394 * @param object $action On Submit action object.
2395 */
2396 return apply_filters( 'frm_get_run_success_action_args', $new_args, $args, $action );
2397 }
2398
2399 /**
2400 * @since 3.0
2401 */
2402 private static function load_page_after_submit( $args ) {
2403 global $post;
2404 $opt = $args['success_opt'];
2405 if ( ! $post || $args['form']->options[ $opt . '_page_id' ] != $post->ID ) {
2406 $page = get_post( $args['form']->options[ $opt . '_page_id' ] );
2407 $old_post = $post;
2408 $post = $page;
2409 $content = apply_filters( 'frm_content', $page->post_content, $args['form'], $args['entry_id'] );
2410
2411 // Fix the On Submit page content doesn't show when previewing In theme.
2412 $has_preview_filter = has_filter( 'the_content', 'FrmFormsController::preview_content' );
2413
2414 if ( $has_preview_filter ) {
2415 remove_filter( 'the_content', 'FrmFormsController::preview_content', 9999 );
2416 }
2417
2418 echo apply_filters( 'the_content', $content ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2419
2420 if ( $has_preview_filter ) {
2421 add_filter( 'the_content', 'FrmFormsController::preview_content', 9999 );
2422 }
2423
2424 $post = $old_post;
2425 }
2426 }
2427
2428 /**
2429 * @since 3.0
2430 * @param array $args See {@see FrmFormsController::run_success_action()}.
2431 */
2432 private static function redirect_after_submit( $args ) {
2433 add_filter( 'frm_use_wpautop', '__return_false' );
2434
2435 $opt = $args['success_opt'];
2436 $success_url = trim( $args['form']->options[ $opt . '_url' ] );
2437 $success_url = apply_filters( 'frm_content', $success_url, $args['form'], $args['entry_id'] );
2438 $success_url = do_shortcode( $success_url );
2439
2440 $args['id'] = $args['entry_id'];
2441 FrmEntriesController::delete_entry_before_redirect( $success_url, $args['form'], $args );
2442
2443 add_filter( 'frm_redirect_url', 'FrmEntriesController::prepare_redirect_url' );
2444 $success_url = apply_filters( 'frm_redirect_url', $success_url, $args['form'], $args );
2445
2446 $doing_ajax = FrmAppHelper::doing_ajax();
2447
2448 if ( ! empty( $args['ajax'] ) && $doing_ajax && empty( $args['force_delay_redirect'] ) ) { // Is AJAX submit and there is just one Redirect action runs.
2449 echo json_encode( self::get_ajax_redirect_response_data( $args + compact( 'success_url' ) ) );
2450 wp_die();
2451 }
2452
2453 if ( ! headers_sent() && empty( $args['force_delay_redirect'] ) ) { // Not AJAX submit, no headers sent, and there is just one Redirect action runs.
2454 if ( ! empty( $args['form']->options['open_in_new_tab'] ) ) {
2455 self::print_open_in_new_tab_js_with_fallback_handler( $success_url, $args );
2456 self::$redirected_in_new_tab[ $args['form']->id ] = 1;
2457 return;
2458 }
2459
2460 wp_redirect( esc_url_raw( $success_url ) );
2461 die(); // do not use wp_die or redirect fails
2462 }
2463
2464 // Redirect with a delay.
2465 self::redirect_after_submit_using_js( $args + compact( 'success_url', 'doing_ajax' ) );
2466 }
2467
2468 /**
2469 * Prints open in new tab js with fallback handler.
2470 *
2471 * @since 6.3.1
2472 *
2473 * @param string $success_url Success URL.
2474 * @param array $args See {@see FrmFormsController::redirect_after_submit()}.
2475 */
2476 private static function print_open_in_new_tab_js_with_fallback_handler( $success_url, $args ) {
2477 echo '<script>var newTab = window.open("' . esc_url_raw( $success_url ) . '", "_blank");';
2478 echo 'if ( ! newTab ) {';
2479
2480 $data = array(
2481 'formId' => intval( $args['form']->id ),
2482 'message' => self::get_redirect_fallback_message( $success_url, $args ),
2483 );
2484 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2485 echo 'frmShowNewTabFallback = ' . FrmAppHelper::maybe_json_encode( $data ) . ';';
2486 echo '}</script>';
2487 }
2488
2489 /**
2490 * Gets response data for redirect action when AJAX submitting.
2491 *
2492 * @since 6.3.1
2493 *
2494 * @param array $args See {@see FrmFormsController::run_success_action()}.
2495 * @return array
2496 */
2497 private static function get_ajax_redirect_response_data( $args ) {
2498 $response_data = array( 'redirect' => $args['success_url'] );
2499
2500 if ( ! empty( $args['form']->options['open_in_new_tab'] ) ) {
2501 $response_data['openInNewTab'] = 1;
2502
2503 $args['message'] = FrmOnSubmitHelper::get_default_new_tab_msg();
2504
2505 $args['form']->options['success_msg'] = $args['message'];
2506 $args['form']->options['edit_msg'] = $args['message'];
2507 if ( ! isset( $args['fields'] ) ) {
2508 $args['fields'] = FrmField::get_all_for_form( $args['form']->id );
2509 }
2510
2511 $args['message'] = self::prepare_submit_message( $args['form'], $args['entry_id'], $args );
2512
2513 ob_start();
2514 self::show_lone_success_messsage( $args );
2515 $response_data['content'] = ob_get_clean();
2516
2517 $response_data['fallbackMsg'] = self::get_redirect_fallback_message( $args['success_url'], $args );
2518 }
2519
2520 return $response_data;
2521 }
2522
2523 /**
2524 * Redirects after submitting using JS. This is used when showing message before redirecting.
2525 *
2526 * @since 6.0
2527 *
2528 * @param array $args See {@see FrmFormsController::run_success_action()}.
2529 */
2530 private static function redirect_after_submit_using_js( $args ) {
2531 $success_msg = FrmOnSubmitHelper::get_default_redirect_msg();
2532 $redirect_msg = self::get_redirect_message( $args['success_url'], $success_msg, $args );
2533 $success_url = esc_url_raw( $args['success_url'] );
2534
2535 /**
2536 * Filters the delay time before redirecting when On Submit Redirect action is delayed.
2537 *
2538 * @since 6.0
2539 *
2540 * @param int $delay_time Delay time in miliseconds.
2541 */
2542 $delay_time = apply_filters( 'frm_redirect_delay_time', 8000 );
2543
2544 if ( ! empty( $args['form']->options['open_in_new_tab'] ) ) {
2545 $redirect_js = 'window.open("' . $success_url . '", "_blank")';
2546 } else {
2547 $redirect_js = 'window.location="' . $success_url . '";';
2548 }
2549
2550 add_filter( 'frm_use_wpautop', '__return_true' );
2551
2552 echo FrmAppHelper::maybe_kses( $redirect_msg ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2553 echo '<script>';
2554 if ( empty( $args['doing_ajax'] ) ) { // Not AJAX submit, delay JS until window.load.
2555 echo 'window.onload=function(){';
2556 }
2557 echo 'setTimeout(function(){' . $redirect_js . '}, ' . intval( $delay_time ) . ');'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2558 if ( empty( $args['doing_ajax'] ) ) {
2559 echo '};';
2560 }
2561 echo '</script>';
2562 }
2563
2564 /**
2565 * @since 3.0
2566 *
2567 * @param string $success_url
2568 * @param string $success_msg
2569 * @param array $args
2570 */
2571 private static function get_redirect_message( $success_url, $success_msg, $args ) {
2572 $redirect_msg = '<div class="' . esc_attr( FrmFormsHelper::get_form_style_class( $args['form'] ) ) . '"><div class="frm-redirect-msg" role="status">' . $success_msg . '<br/>' .
2573 self::get_redirect_fallback_message( $success_url, $args ) .
2574 '</div></div>';
2575
2576 $redirect_args = array(
2577 'entry_id' => $args['entry_id'],
2578 'form_id' => $args['form']->id,
2579 'form' => $args['form'],
2580 );
2581
2582 return apply_filters( 'frm_redirect_msg', $redirect_msg, $redirect_args );
2583 }
2584
2585 /**
2586 * Gets fallback message when redirecting failed.
2587 *
2588 * @since 6.3.1
2589 *
2590 * @param string $success_url Redirect URL.
2591 * @param array $args Contains `form` object.
2592 * @return string
2593 */
2594 private static function get_redirect_fallback_message( $success_url, $args ) {
2595 $target = '';
2596 if ( ! empty( $args['form']->options['open_in_new_tab'] ) ) {
2597 $target = ' target="_blank"';
2598 }
2599
2600 return sprintf(
2601 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
2602 __( '%1$sClick here%2$s if you are not automatically redirected.', 'formidable' ),
2603 '<a href="' . esc_url( $success_url ) . '"' . $target . '>',
2604 '</a>'
2605 );
2606 }
2607
2608 /**
2609 * Prepare to show the success message and empty form after submit
2610 *
2611 * @since 2.05
2612 */
2613 public static function show_message_after_save( $atts ) {
2614 $atts['message'] = self::prepare_submit_message( $atts['form'], $atts['entry_id'], $atts );
2615
2616 if ( ! isset( $atts['form']->options['show_form'] ) || $atts['form']->options['show_form'] ) {
2617 if ( isset( $atts['action'] ) && 'update' === $atts['action'] && is_callable( array( 'FrmProEntriesController', 'show_front_end_form_with_entry' ) ) ) {
2618 $entry = FrmEntry::getOne( $atts['entry_id'] );
2619 if ( $entry ) {
2620 // This is copied from the Pro plugin.
2621 $atts['conf_message'] = FrmProEntriesController::confirmation( 'message', $atts['form'], $atts['form']->options, $entry->id, $atts );
2622 $atts['show_form'] = FrmProEntriesController::is_form_displayed_after_edit( $atts['form'] );
2623 FrmProEntriesController::show_front_end_form_with_entry( $entry, $atts );
2624 }
2625 } else {
2626 self::show_form_after_submit( $atts );
2627 }
2628 } else {
2629 self::show_lone_success_messsage( $atts );
2630 }
2631 }
2632
2633 /**
2634 * Show an empty form
2635 *
2636 * @since 2.05
2637 */
2638 private static function show_form_after_submit( $args ) {
2639 self::fill_atts_for_form_display( $args );
2640
2641 $errors = $args['errors'];
2642 $message = $args['message'];
2643 $form = $args['form'];
2644 $title = $args['title'];
2645 $description = $args['description'];
2646
2647 if ( empty( $args['fields'] ) ) {
2648 $values = array(
2649 'custom_style' => FrmAppHelper::custom_style_value( array() ),
2650 );
2651 } else {
2652 $values = FrmEntriesHelper::setup_new_vars( $args['fields'], $form, $args['reset'] );
2653 }
2654 unset( $args );
2655
2656 $include_form_tag = apply_filters( 'frm_include_form_tag', true, $form );
2657
2658 $frm_settings = FrmAppHelper::get_settings();
2659 $submit = isset( $form->options['submit_value'] ) ? $form->options['submit_value'] : $frm_settings->submit_value;
2660
2661 global $frm_vars;
2662 self::maybe_load_css( $form, $values['custom_style'], $frm_vars['load_css'] );
2663
2664 $message_placement = self::message_placement( $form, $message );
2665
2666 include FrmAppHelper::plugin_path() . '/classes/views/frm-entries/new.php';
2667 }
2668
2669 /**
2670 * @return string - 'before', 'after', or 'submit'
2671 *
2672 * @since 4.05.02
2673 */
2674 private static function message_placement( $form, $message ) {
2675 $place = 'before';
2676
2677 if ( $message && isset( $form->options['form_class'] ) ) {
2678 if ( strpos( $form->options['form_class'], 'frm_below_success' ) !== false ) {
2679 $place = 'after';
2680 } elseif ( strpos( $form->options['form_class'], 'frm_inline_success' ) !== false ) {
2681 $place = 'submit';
2682 }
2683 }
2684
2685 /**
2686 * @return string - 'before' or 'after'
2687 *
2688 * @since 4.05.02
2689 */
2690 return apply_filters( 'frm_message_placement', $place, compact( 'form', 'message' ) );
2691 }
2692
2693 /**
2694 * Get all the values needed on the new.php entry page
2695 *
2696 * @since 2.05
2697 */
2698 private static function fill_atts_for_form_display( &$args ) {
2699 if ( ! isset( $args['title'] ) && isset( $args['show_title'] ) ) {
2700 $args['title'] = $args['show_title'];
2701 }
2702
2703 if ( ! isset( $args['description'] ) && isset( $args['show_description'] ) ) {
2704 $args['description'] = $args['show_description'];
2705 }
2706
2707 $defaults = array(
2708 'errors' => array(),
2709 'message' => '',
2710 'fields' => array(),
2711 'form' => array(),
2712 'title' => true,
2713 'description' => false,
2714 'reset' => false,
2715 );
2716 $args = wp_parse_args( $args, $defaults );
2717 }
2718
2719 /**
2720 * Show the success message without the form
2721 *
2722 * @since 2.05
2723 */
2724 private static function show_lone_success_messsage( $atts ) {
2725 global $frm_vars;
2726 $values = FrmEntriesHelper::setup_new_vars( $atts['fields'], $atts['form'], true );
2727 self::maybe_load_css( $atts['form'], $values['custom_style'], $frm_vars['load_css'] );
2728
2729 $include_extra_container = 'frm_forms' . FrmFormsHelper::get_form_style_class( $values );
2730
2731 $errors = array();
2732 $form = $atts['form'];
2733 $message = $atts['message'];
2734
2735 include( FrmAppHelper::plugin_path() . '/classes/views/frm-entries/errors.php' );
2736 }
2737
2738 /**
2739 * Prepare the success message before it's shown
2740 *
2741 * @since 2.05
2742 * @since 6.0.x Added the third parameter.
2743 *
2744 * @param object $form Form object.
2745 * @param int $entry_id Entry ID.
2746 * @param array $args See {@see FrmFormsController::run_success_action()}.
2747 * @return string
2748 */
2749 private static function prepare_submit_message( $form, $entry_id, $args = array() ) {
2750 $frm_settings = FrmAppHelper::get_settings( array( 'current_form' => $form->id ) );
2751 $opt = isset( $args['success_opt'] ) ? $args['success_opt'] : 'success';
2752
2753 if ( $entry_id && is_numeric( $entry_id ) ) {
2754 $message = isset( $form->options[ $opt . '_msg' ] ) ? $form->options[ $opt . '_msg' ] : $frm_settings->success_msg;
2755 $class = 'frm_message';
2756 } else {
2757 $message = $frm_settings->failed_msg;
2758 $class = FrmFormsHelper::form_error_class();
2759 }
2760
2761 $message = FrmFormsHelper::get_success_message( compact( 'message', 'form', 'entry_id', 'class' ) );
2762
2763 return apply_filters( 'frm_main_feedback', $message, $form, $entry_id );
2764 }
2765
2766 /**
2767 * @return void
2768 */
2769 public static function front_head() {
2770 $version = FrmAppHelper::plugin_version();
2771 $suffix = FrmAppHelper::js_suffix();
2772
2773 if ( ! empty( $suffix ) && self::has_combo_js_file() ) {
2774 wp_register_script( 'formidable', FrmAppHelper::plugin_url() . '/js/frm.min.js', array( 'jquery' ), $version, true );
2775 } else {
2776 wp_register_script( 'formidable', FrmAppHelper::plugin_url() . "/js/formidable{$suffix}.js", array( 'jquery' ), $version, true );
2777 }
2778
2779 add_filter( 'script_loader_tag', 'FrmFormsController::defer_script_loading', 10, 2 );
2780
2781 if ( FrmAppHelper::is_admin() ) {
2782 // don't load this in back-end
2783 return;
2784 }
2785
2786 FrmAppHelper::localize_script( 'front' );
2787 FrmStylesController::enqueue_css( 'register' );
2788 }
2789
2790 /**
2791 * @since 3.0
2792 */
2793 public static function has_combo_js_file() {
2794 return is_readable( FrmAppHelper::plugin_path() . '/js/frm.min.js' );
2795 }
2796
2797 public static function maybe_load_css( $form, $this_load, $global_load ) {
2798 $load_css = FrmForm::is_form_loaded( $form, $this_load, $global_load );
2799
2800 if ( ! $load_css ) {
2801 return;
2802 }
2803
2804 global $frm_vars;
2805 self::footer_js( 'header' );
2806 $frm_vars['css_loaded'] = true;
2807
2808 self::load_late_css();
2809 }
2810
2811 /**
2812 * If css is loaded only on applicable pages, include it before the form loads
2813 * to prevent a flash of unstyled form.
2814 *
2815 * @since 4.01
2816 *
2817 * @return void
2818 */
2819 private static function load_late_css() {
2820 $frm_settings = FrmAppHelper::get_settings();
2821 $late_css = $frm_settings->load_style === 'dynamic';
2822
2823 if ( ! $late_css || ! self::should_load_late() ) {
2824 return;
2825 }
2826
2827 global $wp_styles;
2828 if ( is_array( $wp_styles->queue ) && in_array( 'formidable', $wp_styles->queue, true ) ) {
2829 wp_print_styles( 'formidable' );
2830 }
2831 }
2832
2833 /**
2834 * Avoid late load if All in One SEO is active because it prevents CSS from loading entirely.
2835 *
2836 * @since 5.2.03
2837 *
2838 * @return bool
2839 */
2840 private static function should_load_late() {
2841 return ! function_exists( 'aioseo' );
2842 }
2843
2844 public static function defer_script_loading( $tag, $handle ) {
2845 if ( 'captcha-api' == $handle && ! strpos( $tag, 'defer' ) ) {
2846 $tag = str_replace( ' src', ' defer="defer" async="async" src', $tag );
2847 }
2848
2849 return $tag;
2850 }
2851
2852 public static function footer_js( $location = 'footer' ) {
2853 global $frm_vars;
2854
2855 FrmStylesController::enqueue_css();
2856
2857 if ( ! FrmAppHelper::is_admin() && $location != 'header' && ! empty( $frm_vars['forms_loaded'] ) ) {
2858 // load formidable js
2859 wp_enqueue_script( 'formidable' );
2860 }
2861 }
2862
2863 /**
2864 * @since 2.0.8
2865 */
2866 private static function maybe_minimize_form( $atts, &$content ) {
2867 // check if minimizing is turned on
2868 if ( self::is_minification_on( $atts ) ) {
2869 $content = str_replace( array( "\r\n", "\r", "\n", "\t", ' ' ), '', $content );
2870 }
2871 }
2872
2873 /**
2874 * @since 2.0.8
2875 * @return boolean
2876 */
2877 private static function is_minification_on( $atts ) {
2878 return isset( $atts['minimize'] ) && ! empty( $atts['minimize'] );
2879 }
2880
2881 /**
2882 * @since 5.0.16
2883 *
2884 * @return void
2885 */
2886 public static function landing_page_preview_option() {
2887 $dir = apply_filters( 'frm_landing_page_preview_option', false );
2888 if ( false === $dir || ! file_exists( $dir . 'landing-page-preview-option.php' ) ) {
2889 $dir = self::get_form_views_path();
2890 }
2891 include $dir . 'landing-page-preview-option.php';
2892 }
2893
2894 /**
2895 * @since 5.0.16
2896 *
2897 * @return string
2898 */
2899 private static function get_form_views_path() {
2900 return FrmAppHelper::plugin_path() . '/classes/views/frm-forms/';
2901 }
2902
2903 /**
2904 * Create a page with an embedded formidable Gutenberg block.
2905 *
2906 * @since 5.2
2907 *
2908 * @return never
2909 */
2910 public static function create_page_with_shortcode() {
2911 if ( ! current_user_can( 'publish_posts' ) ) {
2912 die( 0 );
2913 }
2914
2915 check_ajax_referer( 'frm_ajax', 'nonce' );
2916
2917 $type = FrmAppHelper::get_post_param( 'type', '', 'sanitize_text_field' );
2918 if ( ! $type || ! in_array( $type, array( 'form', 'view' ), true ) ) {
2919 die( 0 );
2920 }
2921
2922 $object_id = FrmAppHelper::get_post_param( 'object_id', '', 'absint' );
2923 if ( ! $object_id ) {
2924 die( 0 );
2925 }
2926
2927 $postarr = array( 'post_type' => 'page' );
2928
2929 if ( 'form' === $type ) {
2930 $postarr['post_content'] = self::get_page_shortcode_content_for_form( $object_id );
2931 } else {
2932 $postarr['post_content'] = apply_filters( 'frm_create_page_with_' . $type . '_shortcode_content', '', $object_id );
2933 }
2934
2935 $name = FrmAppHelper::get_post_param( 'name', '', 'sanitize_text_field' );
2936 if ( $name ) {
2937 $postarr['post_title'] = $name;
2938 }
2939
2940 $success = wp_insert_post( $postarr );
2941 if ( ! is_numeric( $success ) || ! $success ) {
2942 die( 0 );
2943 }
2944
2945 wp_send_json(
2946 array(
2947 'redirect' => get_edit_post_link( $success, 'redirect' ),
2948 )
2949 );
2950 }
2951
2952 /**
2953 * @since 5.3
2954 *
2955 * @param string $content
2956 * @param int $form_id
2957 * @return string
2958 */
2959 private static function get_page_shortcode_content_for_form( $form_id ) {
2960 $shortcode = '[formidable id="' . $form_id . '"]';
2961 $html_comment_start = '<!-- wp:formidable/simple-form {"formId":"' . $form_id . '"} -->';
2962 $html_comment_end = '<!-- /wp:formidable/simple-form -->';
2963 return $html_comment_start . '<div>' . $shortcode . '</div>' . $html_comment_end;
2964 }
2965
2966 /**
2967 * Get page dropdown for AJAX request for embedding form in an existing page.
2968 *
2969 * @return never
2970 */
2971 public static function get_page_dropdown() {
2972 if ( ! current_user_can( 'publish_posts' ) ) {
2973 die( 0 );
2974 }
2975
2976 check_ajax_referer( 'frm_ajax', 'nonce' );
2977
2978 $html = FrmAppHelper::clip(
2979 function() {
2980 FrmAppHelper::maybe_autocomplete_pages_options(
2981 array(
2982 'field_name' => 'frm_page_dropdown',
2983 'page_id' => '',
2984 'placeholder' => __( 'Select a Page', 'formidable' ),
2985 )
2986 );
2987 }
2988 );
2989 $post_type_object = get_post_type_object( 'page' );
2990 wp_send_json(
2991 array(
2992 'html' => $html,
2993 'edit_page_url' => admin_url( sprintf( $post_type_object->_edit_link . '&action=edit', 0 ) ),
2994 )
2995 );
2996 }
2997
2998 /**
2999 * @deprecated 4.0
3000 */
3001 public static function new_form( $values = array() ) {
3002 FrmDeprecated::new_form( $values );
3003 }
3004
3005 /**
3006 * @deprecated 4.0
3007 */
3008 public static function create( $values = array() ) {
3009 _deprecated_function( __METHOD__, '4.0', 'FrmFormsController::update' );
3010 self::update( $values );
3011 }
3012
3013 /**
3014 * @deprecated 3.0
3015 * @codeCoverageIgnore
3016 */
3017 public static function bulk_create_template( $ids ) {
3018 return FrmDeprecated::bulk_create_template( $ids );
3019 }
3020
3021 /**
3022 * @deprecated 3.0
3023 * @codeCoverageIgnore
3024 */
3025 public static function edit_key() {
3026 FrmDeprecated::edit_key();
3027 }
3028
3029 /**
3030 * @deprecated 3.0
3031 * @codeCoverageIgnore
3032 */
3033 public static function edit_description() {
3034 FrmDeprecated::edit_description();
3035 }
3036
3037 /**
3038 * @deprecated 4.08
3039 * @since 3.06
3040 */
3041 public static function add_new() {
3042 _deprecated_function( __FUNCTION__, '4.08' );
3043 }
3044
3045 /**
3046 * Create a custom template from a form
3047 *
3048 * @since 3.06
3049 * @deprecated x.x
3050 */
3051 public static function build_template() {
3052 _deprecated_function( __METHOD__, 'x.x' );
3053 }
3054
3055 /**
3056 * @deprecated x.x
3057 *
3058 * @return bool
3059 */
3060 public static function expired() {
3061 _deprecated_function( __METHOD__, 'x.x' );
3062 return FrmAddonsController::is_license_expired();
3063 }
3064
3065 /**
3066 * Get data from api before rendering it so that we can flag the modal as expired
3067 *
3068 * @deprecated x.x
3069 *
3070 * @return void
3071 */
3072 public static function before_list_templates() {
3073 _deprecated_function( __METHOD__, 'x.x' );
3074 }
3075
3076 /**
3077 * @deprecated x.x
3078 *
3079 * @return void
3080 */
3081 public static function list_templates() {
3082 _deprecated_function( __METHOD__, 'x.x' );
3083 }
3084 }
3085