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

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