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

2,959 lines 85.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 public static function form_classes( $form ) {
1536 if ( isset( $form->options['form_class'] ) ) {
1537 echo esc_attr( sanitize_text_field( $form->options['form_class'] ) );
1538 }
1539
1540 if ( ! empty( $form->options['js_validate'] ) ) {
1541 echo ' frm_js_validate ';
1542 self::add_js_validate_form_to_global_vars( $form );
1543 }
1544 }
1545
1546 /**
1547 * @since 5.0.03
1548 *
1549 * @param stdClass $form
1550 */
1551 public static function add_js_validate_form_to_global_vars( $form ) {
1552 global $frm_vars;
1553 if ( ! isset( $frm_vars['js_validate_forms'] ) ) {
1554 $frm_vars['js_validate_forms'] = array();
1555 }
1556 $frm_vars['js_validate_forms'][ $form->id ] = $form;
1557 }
1558
1559 public static function get_email_html() {
1560 FrmAppHelper::permission_check( 'frm_view_forms' );
1561 check_ajax_referer( 'frm_ajax', 'nonce' );
1562
1563 echo FrmEntriesController::show_entry_shortcode( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1564 array(
1565 'form_id' => FrmAppHelper::get_post_param( 'form_id', '', 'absint' ),
1566 'default_email' => true,
1567 'plain_text' => FrmAppHelper::get_post_param( 'plain_text', '', 'absint' ),
1568 )
1569 );
1570 wp_die();
1571 }
1572
1573 /**
1574 * @param string $content
1575 * @param stdClass|string|int $form
1576 * @param stdClass|string|int|false $entry
1577 * @return string
1578 */
1579 public static function filter_content( $content, $form, $entry = false ) {
1580 $content = self::replace_form_name_shortcodes( $content, $form );
1581
1582 self::get_entry_by_param( $entry );
1583 if ( ! $entry ) {
1584 return $content;
1585 }
1586
1587 if ( is_object( $form ) ) {
1588 $form = $form->id;
1589 }
1590
1591 $shortcodes = FrmFieldsHelper::get_shortcodes( $content, $form );
1592 $content = apply_filters( 'frm_replace_content_shortcodes', $content, $entry, $shortcodes );
1593
1594 return $content;
1595 }
1596
1597 /**
1598 * Replace any [form_name] shortcodes in a string.
1599 *
1600 * @since 5.5
1601 *
1602 * @param string $string
1603 * @param stdClass|string|int $form
1604 * @return string
1605 */
1606 public static function replace_form_name_shortcodes( $string, $form ) {
1607 if ( false === strpos( $string, '[form_name]' ) ) {
1608 return $string;
1609 }
1610
1611 if ( ! is_object( $form ) ) {
1612 $form = FrmForm::getOne( $form );
1613 }
1614
1615 $form_name = is_object( $form ) ? $form->name : '';
1616 return str_replace( '[form_name]', $form_name, $string );
1617 }
1618
1619 /**
1620 * @param stdClass|string|int|false $entry
1621 * @return void
1622 */
1623 private static function get_entry_by_param( &$entry ) {
1624 if ( ! $entry || ! is_object( $entry ) ) {
1625 if ( ! $entry || ! is_numeric( $entry ) ) {
1626 $entry = FrmAppHelper::get_post_param( 'id', false, 'sanitize_title' );
1627 }
1628
1629 FrmEntry::maybe_get_entry( $entry );
1630 }
1631 }
1632
1633 public static function replace_content_shortcodes( $content, $entry, $shortcodes ) {
1634 return FrmFieldsHelper::replace_content_shortcodes( $content, $entry, $shortcodes );
1635 }
1636
1637 public static function process_bulk_form_actions( $errors ) {
1638 if ( ! $_REQUEST ) {
1639 return $errors;
1640 }
1641
1642 $bulkaction = FrmAppHelper::get_param( 'action', '', 'get', 'sanitize_text_field' );
1643 if ( $bulkaction == - 1 ) {
1644 $bulkaction = FrmAppHelper::get_param( 'action2', '', 'get', 'sanitize_title' );
1645 }
1646
1647 if ( ! empty( $bulkaction ) && strpos( $bulkaction, 'bulk_' ) === 0 ) {
1648 FrmAppHelper::remove_get_action();
1649
1650 $bulkaction = str_replace( 'bulk_', '', $bulkaction );
1651 }
1652
1653 $ids = FrmAppHelper::get_param( 'item-action', '', 'get', 'sanitize_text_field' );
1654 if ( empty( $ids ) ) {
1655 $errors[] = __( 'No forms were specified', 'formidable' );
1656
1657 return $errors;
1658 }
1659
1660 $permission_error = FrmAppHelper::permission_nonce_error( '', '_wpnonce', 'bulk-toplevel_page_formidable' );
1661 if ( $permission_error !== false ) {
1662 $errors[] = $permission_error;
1663
1664 return $errors;
1665 }
1666
1667 if ( ! is_array( $ids ) ) {
1668 $ids = explode( ',', $ids );
1669 }
1670
1671 switch ( $bulkaction ) {
1672 case 'delete':
1673 $message = self::bulk_destroy( $ids );
1674 break;
1675 case 'trash':
1676 $message = self::bulk_trash( $ids );
1677 break;
1678 case 'untrash':
1679 $message = self::bulk_untrash( $ids );
1680 }
1681
1682 if ( isset( $message ) && ! empty( $message ) ) {
1683 $errors['message'] = $message;
1684 }
1685
1686 return $errors;
1687 }
1688
1689 public static function route() {
1690 $action = isset( $_REQUEST['frm_action'] ) ? 'frm_action' : 'action';
1691 $vars = array();
1692 FrmAppHelper::include_svg();
1693
1694 if ( isset( $_POST['frm_compact_fields'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1695 FrmAppHelper::permission_check( 'frm_edit_forms' );
1696
1697 // Javascript needs to be allowed in some field settings.
1698 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
1699 $json_vars = htmlspecialchars_decode( nl2br( str_replace( '&quot;', '"', wp_unslash( $_POST['frm_compact_fields'] ) ) ) );
1700 $json_vars = json_decode( $json_vars, true );
1701 if ( empty( $json_vars ) ) {
1702 // json decoding failed so we should return an error message.
1703 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
1704 if ( 'edit' == $action ) {
1705 $action = 'update';
1706 }
1707
1708 add_filter( 'frm_validate_form', 'FrmFormsController::json_error' );
1709 } else {
1710 $vars = FrmAppHelper::json_to_array( $json_vars );
1711 $action = $vars[ $action ];
1712 unset( $_REQUEST['frm_compact_fields'], $_POST['frm_compact_fields'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1713 $_REQUEST = array_merge( $_REQUEST, $vars ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1714 $_POST = array_merge( $_POST, $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1715 }
1716 } else {
1717 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
1718 if ( isset( $_REQUEST['delete_all'] ) ) {
1719 // Override the action for this page.
1720 $action = 'delete_all';
1721 }
1722 }
1723
1724 add_action( 'frm_load_form_hooks', 'FrmHooksController::trigger_load_form_hooks' );
1725 FrmAppHelper::trigger_hook_load( 'form' );
1726
1727 switch ( $action ) {
1728 case 'new':
1729 return self::new_form( $vars );
1730 case 'create':
1731 case 'edit':
1732 case 'update':
1733 case 'trash':
1734 case 'untrash':
1735 case 'destroy':
1736 case 'delete_all':
1737 case 'settings':
1738 case 'update_settings':
1739 return self::$action( $vars );
1740 case 'lite-reports':
1741 return self::no_reports( $vars );
1742 case 'views':
1743 return self::no_views( $vars );
1744 default:
1745 do_action( 'frm_form_action_' . $action );
1746 if ( apply_filters( 'frm_form_stop_action_' . $action, false ) ) {
1747 return;
1748 }
1749
1750 $action = FrmAppHelper::get_param( 'action', '', 'get', 'sanitize_text_field' );
1751 if ( $action == - 1 ) {
1752 $action = FrmAppHelper::get_param( 'action2', '', 'get', 'sanitize_title' );
1753 }
1754
1755 if ( strpos( $action, 'bulk_' ) === 0 ) {
1756 FrmAppHelper::remove_get_action();
1757
1758 self::list_form();
1759 return;
1760 }
1761
1762 $message = FrmAppHelper::get_param( 'message' );
1763 if ( 'form_duplicate_error' === $message ) {
1764 self::display_forms_list( array(), '', array( __( 'There was a problem duplicating the form', 'formidable' ) ) );
1765 return;
1766 }
1767
1768 self::display_forms_list();
1769
1770 return;
1771 }
1772 }
1773
1774 public static function json_error( $errors ) {
1775 $errors['json'] = __( 'Abnormal HTML characters prevented your form from saving correctly', 'formidable' );
1776
1777 return $errors;
1778 }
1779
1780 /**
1781 * Education for premium features.
1782 *
1783 * @since 4.05
1784 */
1785 public static function add_form_style_tab_options() {
1786 include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/add_form_style_options.php' );
1787 }
1788
1789 /**
1790 * Add education about views.
1791 *
1792 * @since 4.07
1793 */
1794 public static function no_views( $values = array() ) {
1795 FrmAppHelper::include_svg();
1796 $id = FrmAppHelper::get_param( 'form', '', 'get', 'absint' );
1797 $form = $id ? FrmForm::getOne( $id ) : false;
1798
1799 include FrmAppHelper::plugin_path() . '/classes/views/shared/views-info.php';
1800 }
1801
1802 /**
1803 * Add education about reports.
1804 *
1805 * @since 4.07
1806 */
1807 public static function no_reports( $values = array() ) {
1808 $id = FrmAppHelper::get_param( 'form', '', 'get', 'absint' );
1809 $form = $id ? FrmForm::getOne( $id ) : false;
1810
1811 include FrmAppHelper::plugin_path() . '/classes/views/shared/reports-info.php';
1812 }
1813
1814 /* FRONT-END FORMS */
1815 public static function admin_bar_css() {
1816 if ( is_admin() || ! current_user_can( 'frm_edit_forms' ) ) {
1817 return;
1818 }
1819
1820 self::move_menu_to_footer();
1821
1822 add_action( 'wp_before_admin_bar_render', 'FrmFormsController::admin_bar_configure' );
1823 FrmAppHelper::load_font_style();
1824 }
1825
1826 /**
1827 * @since 4.05.02
1828 */
1829 private static function move_menu_to_footer() {
1830 $settings = FrmAppHelper::get_settings();
1831 if ( empty( $settings->admin_bar ) ) {
1832 remove_action( 'wp_body_open', 'wp_admin_bar_render', 0 );
1833 }
1834 }
1835
1836 public static function admin_bar_configure() {
1837 global $frm_vars;
1838 if ( empty( $frm_vars['forms_loaded'] ) ) {
1839 return;
1840 }
1841
1842 $actions = array();
1843 foreach ( $frm_vars['forms_loaded'] as $form ) {
1844 if ( is_object( $form ) ) {
1845 $actions[ $form->id ] = $form->name;
1846 }
1847 unset( $form );
1848 }
1849
1850 if ( empty( $actions ) ) {
1851 return;
1852 }
1853
1854 self::add_menu_to_admin_bar();
1855 self::add_forms_to_admin_bar( $actions );
1856 }
1857
1858 /**
1859 * @since 2.05.07
1860 */
1861 public static function add_menu_to_admin_bar() {
1862 global $wp_admin_bar;
1863
1864 $wp_admin_bar->add_node(
1865 array(
1866 'id' => 'frm-forms',
1867 'title' => '<span class="ab-icon"></span><span class="ab-label">' . FrmAppHelper::get_menu_name() . '</span>',
1868 'href' => admin_url( 'admin.php?page=formidable' ),
1869 'meta' => array(
1870 'title' => FrmAppHelper::get_menu_name(),
1871 ),
1872 )
1873 );
1874 }
1875
1876 /**
1877 * @since 2.05.07
1878 */
1879 private static function add_forms_to_admin_bar( $actions ) {
1880 global $wp_admin_bar;
1881
1882 asort( $actions );
1883
1884 foreach ( $actions as $form_id => $name ) {
1885
1886 $wp_admin_bar->add_node(
1887 array(
1888 'parent' => 'frm-forms',
1889 'id' => 'edit_form_' . $form_id,
1890 'title' => empty( $name ) ? __( '(no title)', 'formidable' ) : $name,
1891 'href' => FrmForm::get_edit_link( $form_id ),
1892 )
1893 );
1894 }
1895 }
1896
1897 /**
1898 * The formidable shortcode
1899 *
1900 * @param array $atts The params from the shortcode.
1901 * @return string
1902 */
1903 public static function get_form_shortcode( $atts ) {
1904 global $frm_vars;
1905 if ( isset( $frm_vars['skip_shortcode'] ) && $frm_vars['skip_shortcode'] ) {
1906 $sc = '[formidable';
1907 $sc .= FrmAppHelper::array_to_html_params( $atts );
1908 return $sc . ']';
1909 }
1910
1911 $shortcode_atts = shortcode_atts(
1912 array(
1913 'id' => '',
1914 'key' => '',
1915 'title' => 'auto',
1916 'description' => 'auto',
1917 'readonly' => false,
1918 'entry_id' => false,
1919 'fields' => array(),
1920 'exclude_fields' => array(),
1921 'minimize' => false,
1922 ),
1923 $atts
1924 );
1925 do_action( 'formidable_shortcode_atts', $shortcode_atts, $atts );
1926
1927 return self::show_form( $shortcode_atts['id'], $shortcode_atts['key'], $shortcode_atts['title'], $shortcode_atts['description'], $atts );
1928 }
1929
1930 /**
1931 * @since 5.2.01
1932 *
1933 * @param string|int|false $id
1934 * @param string|false $key
1935 * @return stdClass|false
1936 */
1937 private static function maybe_get_form_by_id_or_key( $id, $key ) {
1938 if ( ! $id ) {
1939 $id = $key;
1940 }
1941 return self::maybe_get_form_to_show( $id );
1942 }
1943
1944 /**
1945 * @param string|int|false $id
1946 * @param string|false $key
1947 * @param string|int|bool $title may be 'auto', true, false, 'true', 'false', 'yes', '1', 1, '0', 0.
1948 * @param string|int|bool $description may be 'auto', true, false, 'true', 'false', 'yes', '1', 1, '0', 0.
1949 * @param array $atts
1950 * @return string
1951 */
1952 public static function show_form( $id = '', $key = '', $title = false, $description = false, $atts = array() ) {
1953 $form = self::maybe_get_form_by_id_or_key( $id, $key );
1954
1955 if ( ! $form ) {
1956 return __( 'Please select a valid form', 'formidable' );
1957 }
1958
1959 if ( 'auto' === $title ) {
1960 $title = ! empty( $form->options['show_title'] );
1961 }
1962
1963 if ( 'auto' === $description ) {
1964 $description = ! empty( $form->options['show_description'] );
1965 }
1966
1967 FrmAppController::maybe_update_styles();
1968
1969 add_action( 'frm_load_form_hooks', 'FrmHooksController::trigger_load_form_hooks' );
1970 FrmAppHelper::trigger_hook_load( 'form', $form );
1971
1972 $form = apply_filters( 'frm_pre_display_form', $form );
1973
1974 $frm_settings = FrmAppHelper::get_settings( array( 'current_form' => $form->id ) );
1975
1976 if ( self::is_viewable_draft_form( $form ) ) {
1977 // don't show a draft form on a page
1978 $form = __( 'Please select a valid form', 'formidable' );
1979 } elseif ( ! FrmForm::is_visible_to_user( $form ) ) {
1980 $form = do_shortcode( $frm_settings->login_msg );
1981 } else {
1982 do_action( 'frm_pre_get_form', $form );
1983 $form = self::get_form( $form, $title, $description, $atts );
1984
1985 /**
1986 * Use this shortcode to check for external shortcodes that may span
1987 * across multiple fields in the customizable HTML
1988 *
1989 * @since 2.0.8
1990 */
1991 $form = apply_filters( 'frm_filter_final_form', $form );
1992 }
1993
1994 return $form;
1995 }
1996
1997 /**
1998 * @param string|int|false $id
1999 * @return stdClass|false
2000 */
2001 private static function maybe_get_form_to_show( $id ) {
2002 $form = false;
2003
2004 if ( ! empty( $id ) ) { // form id or key is set
2005 $form = FrmForm::getOne( $id );
2006 if ( ! $form || $form->parent_form_id || $form->status === 'trash' ) {
2007 $form = false;
2008 }
2009 }
2010
2011 return $form;
2012 }
2013
2014 private static function is_viewable_draft_form( $form ) {
2015 return $form->status === 'draft' && current_user_can( 'frm_edit_forms' ) && ! FrmAppHelper::is_preview_page();
2016 }
2017
2018 public static function get_form( $form, $title, $description, $atts = array() ) {
2019 ob_start();
2020
2021 do_action( 'frm_before_get_form', $atts );
2022
2023 self::get_form_contents( $form, $title, $description, $atts );
2024 self::enqueue_scripts( FrmForm::get_params( $form ) );
2025
2026 $contents = ob_get_contents();
2027 ob_end_clean();
2028
2029 self::maybe_minimize_form( $atts, $contents );
2030
2031 return $contents;
2032 }
2033
2034 public static function enqueue_scripts( $params ) {
2035 do_action( 'frm_enqueue_form_scripts', $params );
2036 }
2037
2038 public static function get_form_contents( $form, $title, $description, $atts ) {
2039 $params = FrmForm::get_params( $form );
2040 $errors = self::get_saved_errors( $form, $params );
2041 $fields = FrmFieldsHelper::get_form_fields( $form->id, $errors );
2042 $reset = false;
2043 $pass_args = compact( 'form', 'fields', 'errors', 'title', 'description', 'reset' );
2044
2045 $pass_args['action'] = $params['action'];
2046 $handle_process_here = $params['action'] === 'create' && $params['posted_form_id'] == $form->id && $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing
2047
2048 if ( ! $handle_process_here ) {
2049 do_action( 'frm_display_form_action', $params, $fields, $form, $title, $description );
2050 if ( apply_filters( 'frm_continue_to_new', true, $form->id, $params['action'] ) ) {
2051 self::show_form_after_submit( $pass_args );
2052 }
2053 } elseif ( ! empty( $errors ) ) {
2054 self::show_form_after_submit( $pass_args );
2055
2056 } else {
2057
2058 do_action( 'frm_validate_form_creation', $params, $fields, $form, $title, $description );
2059
2060 if ( apply_filters( 'frm_continue_to_create', true, $form->id ) ) {
2061 $entry_id = self::just_created_entry( $form->id );
2062 $pass_args['entry_id'] = $entry_id;
2063 $pass_args['reset'] = true;
2064
2065 self::run_on_submit_actions( $pass_args );
2066
2067 do_action(
2068 'frm_after_entry_processed',
2069 array(
2070 'entry_id' => $entry_id,
2071 'form' => $form,
2072 )
2073 );
2074 }
2075 }
2076 }
2077
2078 /**
2079 * If the form was processed earlier (init), get the generated errors
2080 *
2081 * @since 2.05
2082 */
2083 private static function get_saved_errors( $form, $params ) {
2084 global $frm_vars;
2085
2086 if ( $params['posted_form_id'] == $form->id && $_POST && isset( $frm_vars['created_entries'][ $form->id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
2087 $errors = $frm_vars['created_entries'][ $form->id ]['errors'];
2088 } else {
2089 $errors = array();
2090 }
2091
2092 /**
2093 * Allows modifying the generated errors if the form was processed earlier.
2094 *
2095 * @since 5.2.03
2096 *
2097 * @param array $errors Errors data. Is empty array if no errors found.
2098 * @param array $params Form params. See {@see FrmForm::get_params()}.
2099 */
2100 return apply_filters( 'frm_saved_errors', $errors, $params );
2101 }
2102
2103 /**
2104 * @since 2.2.7
2105 */
2106 public static function just_created_entry( $form_id ) {
2107 global $frm_vars;
2108
2109 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;
2110 }
2111
2112 /**
2113 * Gets confirmation method.
2114 *
2115 * @since 3.0
2116 * @since 6.0 This method can return an array of met On Submit actions.
2117 *
2118 * @param array $atts {
2119 * Atts.
2120 *
2121 * @type object $form Form object.
2122 * @type int $entry_id Entry ID.
2123 * }
2124 * @return string|array
2125 */
2126 private static function get_confirmation_method( $atts ) {
2127 $action = FrmOnSubmitHelper::current_event( $atts );
2128 $opt = 'update' === $action ? 'edit_action' : 'success_action';
2129 $method = ( isset( $atts['form']->options[ $opt ] ) && ! empty( $atts['form']->options[ $opt ] ) ) ? $atts['form']->options[ $opt ] : 'message';
2130
2131 if ( ! empty( $atts['entry_id'] ) ) {
2132 $met_actions = self::get_met_on_submit_actions( $atts, $action );
2133 if ( $met_actions ) {
2134 $method = $met_actions;
2135 }
2136 }
2137
2138 $method = apply_filters( 'frm_success_filter', $method, $atts['form'], $action );
2139
2140 if ( $method != 'message' && ( ! $atts['entry_id'] || ! is_numeric( $atts['entry_id'] ) ) ) {
2141 $method = 'message';
2142 }
2143
2144 return $method;
2145 }
2146
2147 public static function maybe_trigger_redirect( $form, $params, $args ) {
2148 if ( ! isset( $params['id'] ) ) {
2149 global $frm_vars;
2150 $params['id'] = $frm_vars['created_entries'][ $form->id ]['entry_id'];
2151 }
2152
2153 $conf_method = self::get_confirmation_method(
2154 array(
2155 'form' => $form,
2156 'entry_id' => $params['id'],
2157 'action' => FrmOnSubmitHelper::current_event( $params ),
2158 )
2159 );
2160
2161 self::maybe_trigger_redirect_with_action( $conf_method, $form, $params, $args );
2162 }
2163
2164 /**
2165 * Maybe trigger redirect with the new Confirmation action.
2166 *
2167 * @since 6.1.1
2168 *
2169 * @param array|string $conf_method Array of confirmation actions or the action type string.
2170 * @param object $form Form object.
2171 * @param array $params See {@see FrmFormsController::maybe_trigger_redirect()}.
2172 * @param array $args See {@see FrmFormsController::maybe_trigger_redirect()}.
2173 */
2174 public static function maybe_trigger_redirect_with_action( $conf_method, $form, $params, $args ) {
2175 if ( is_array( $conf_method ) && 1 === count( $conf_method ) ) {
2176 if ( 'redirect' === FrmOnSubmitHelper::get_action_type( $conf_method[0] ) ) {
2177 $event = FrmOnSubmitHelper::current_event( $params );
2178 FrmOnSubmitHelper::populate_on_submit_data( $form->options, $conf_method[0], $event );
2179 $conf_method = 'redirect';
2180 }
2181 }
2182
2183 if ( 'redirect' === $conf_method ) {
2184 self::trigger_redirect( $form, $params, $args );
2185 }
2186 }
2187
2188 public static function trigger_redirect( $form, $params, $args ) {
2189 $success_args = array(
2190 'action' => $params['action'],
2191 'conf_method' => 'redirect',
2192 'form' => $form,
2193 'entry_id' => $params['id'],
2194 );
2195
2196 if ( isset( $args['ajax'] ) ) {
2197 $success_args['ajax'] = $args['ajax'];
2198 }
2199
2200 self::run_success_action( $success_args );
2201 }
2202
2203 /**
2204 * Used when the success action is not 'message'
2205 *
2206 * @since 2.05
2207 * @since 6.0 `$args['force_delay_redirect']` is added.
2208 *
2209 * @param array $args {
2210 * The args.
2211 *
2212 * @type string $conf_method The method.
2213 * @type object $form Form object.
2214 * @type int $entry_id Entry ID.
2215 * @type string $action The action event. Accepts `create` or `update`.
2216 * @type array $fields The array of fields.
2217 * @type int $force_delay_redirect Force to show the message before redirecting in case redirect method runs.
2218 * }
2219 */
2220 public static function run_success_action( $args ) {
2221 global $frm_vars;
2222 $extra_args = $args;
2223 unset( $extra_args['form'] );
2224
2225 do_action( 'frm_success_action', $args['conf_method'], $args['form'], $args['form']->options, $args['entry_id'], $extra_args );
2226
2227 $opt = ( ! isset( $args['action'] ) || $args['action'] === 'create' ) ? 'success' : 'edit';
2228
2229 $args['success_opt'] = $opt;
2230 $args['ajax'] = ! empty( $frm_vars['ajax'] );
2231
2232 if ( $args['conf_method'] === 'page' && is_numeric( $args['form']->options[ $opt . '_page_id' ] ) ) {
2233 self::load_page_after_submit( $args );
2234 } elseif ( $args['conf_method'] === 'redirect' ) {
2235 self::redirect_after_submit( $args );
2236 } else {
2237 self::show_message_after_save( $args );
2238 }
2239 }
2240
2241 /**
2242 * Gets met On Submit actions.
2243 *
2244 * @since 6.0
2245 *
2246 * @param array $args See {@see FrmFormsController::run_success_action()}.
2247 * @param string $event Form event. Default is `create`.
2248 * @return array Array of actions that meet the conditional logics.
2249 */
2250 public static function get_met_on_submit_actions( $args, $event = 'create' ) {
2251 if ( ! FrmOnSubmitHelper::form_has_migrated( $args['form'] ) ) {
2252 return array();
2253 }
2254
2255 $entry = FrmEntry::getOne( $args['entry_id'], true );
2256 $actions = FrmOnSubmitHelper::get_actions( $args['form']->id );
2257 $met_actions = array();
2258 $has_redirect = false;
2259
2260 foreach ( $actions as $action ) {
2261 if ( ! in_array( $event, $action->post_content['event'], true ) ) {
2262 continue;
2263 }
2264
2265 if ( FrmFormAction::action_conditions_met( $action, $entry ) ) {
2266 continue;
2267 }
2268
2269 if ( 'redirect' === FrmOnSubmitHelper::get_action_type( $action ) ) {
2270 if ( $has_redirect ) { // Do not process because we run the first redirect action only.
2271 continue;
2272 }
2273
2274 $has_redirect = true;
2275 }
2276
2277 $met_actions[] = $action;
2278 unset( $action );
2279 }
2280
2281 $args['event'] = $event;
2282
2283 /**
2284 * Filters the On Submit actions that meet the conditional logics.
2285 *
2286 * @since 6.0
2287 *
2288 * @param array $met_actions Actions that meet the conditional logics.
2289 * @param array $args See {@see FrmFormsController::run_success_action()}. `$args['event']` is also added.
2290 */
2291 $met_actions = apply_filters( 'frm_get_met_on_submit_actions', $met_actions, $args );
2292
2293 if ( empty( $met_actions ) ) {
2294 $met_actions = array( FrmOnSubmitHelper::get_fallback_action( $event ) );
2295 }
2296
2297 return $met_actions;
2298 }
2299
2300 /**
2301 * Runs On Submit actions.
2302 *
2303 * @since 6.0
2304 *
2305 * @param array $args See inside {@see FrmFormsController::get_form_contents()} method.
2306 */
2307 public static function run_on_submit_actions( $args ) {
2308 $args['conf_method'] = self::get_confirmation_method(
2309 array(
2310 'form' => $args['form'],
2311 'entry_id' => $args['entry_id'],
2312 'action' => FrmOnSubmitHelper::current_event( $args ),
2313 )
2314 );
2315 if ( ! is_array( $args['conf_method'] ) ) {
2316 self::run_success_action( $args );
2317 return;
2318 }
2319
2320 // If conf_method is an array, run On Submit actions.
2321 if ( ! $args['conf_method'] ) {
2322 // Use default message.
2323 FrmOnSubmitHelper::populate_on_submit_data( $args['form']->options );
2324 self::run_success_action( $args );
2325 } elseif ( 1 === count( $args['conf_method'] ) ) {
2326 FrmOnSubmitHelper::populate_on_submit_data( $args['form']->options, reset( $args['conf_method'] ) );
2327 $args['conf_method'] = $args['form']->options['success_action'];
2328 self::run_success_action( $args );
2329 } else {
2330 self::run_multi_on_submit_actions( $args );
2331 }
2332 }
2333
2334 /**
2335 * Runs multiple success actions.
2336 *
2337 * @since 6.0
2338 *
2339 * @param array $args See {@see FrmFormsController::run_success_action()}.
2340 */
2341 public static function run_multi_on_submit_actions( $args ) {
2342 $redirect_action = null;
2343 foreach ( $args['conf_method'] as $action ) {
2344 if ( 'redirect' === FrmOnSubmitHelper::get_action_type( $action ) ) {
2345 // We catch the redirect action to run it last.
2346 $redirect_action = $action;
2347 continue;
2348 }
2349
2350 self::run_single_on_submit_action( $args, $action );
2351
2352 unset( $action );
2353 }
2354
2355 if ( $redirect_action ) {
2356 // Show script to delay the redirection.
2357 $args['force_delay_redirect'] = true;
2358 self::run_single_on_submit_action( $args, $redirect_action );
2359 }
2360 }
2361
2362 /**
2363 * Runs single On Submit action.
2364 *
2365 * @since 6.0
2366 *
2367 * @param array $args See {@see FrmFormsController::run_success_action()}.
2368 * @param object $action On Submit action object.
2369 */
2370 public static function run_single_on_submit_action( $args, $action ) {
2371 $new_args = self::get_run_success_action_args( $args, $action );
2372 self::run_success_action( $new_args );
2373 }
2374
2375 /**
2376 * Gets run_success_action() args from the On Submit action.
2377 *
2378 * @since 6.0
2379 *
2380 * @param array $args See {@see FrmFormsController::run_success_action()}.
2381 * @param object $action On Submit action object.
2382 * @return array
2383 */
2384 private static function get_run_success_action_args( $args, $action ) {
2385 $new_args = $args;
2386
2387 FrmOnSubmitHelper::populate_on_submit_data( $new_args['form']->options, $action, $args['action'] );
2388
2389 $opt = 'update' === $args['action'] ? 'edit_' : 'success_';
2390
2391 $new_args['conf_method'] = $new_args['form']->options[ $opt . 'action' ];
2392
2393 /**
2394 * Filters the run success action args.
2395 *
2396 * @since 6.0
2397 *
2398 * @param array $new_args The new args.
2399 * @param array $args The old args. See {@see FrmFormsController::run_success_action()}.
2400 * @param object $action On Submit action object.
2401 */
2402 return apply_filters( 'frm_get_run_success_action_args', $new_args, $args, $action );
2403 }
2404
2405 /**
2406 * @since 3.0
2407 */
2408 private static function load_page_after_submit( $args ) {
2409 global $post;
2410 $opt = $args['success_opt'];
2411 if ( ! $post || $args['form']->options[ $opt . '_page_id' ] != $post->ID ) {
2412 $page = get_post( $args['form']->options[ $opt . '_page_id' ] );
2413 $old_post = $post;
2414 $post = $page;
2415 $content = apply_filters( 'frm_content', $page->post_content, $args['form'], $args['entry_id'] );
2416
2417 // Fix the On Submit page content doesn't show when previewing In theme.
2418 $has_preview_filter = has_filter( 'the_content', 'FrmFormsController::preview_content' );
2419
2420 if ( $has_preview_filter ) {
2421 remove_filter( 'the_content', 'FrmFormsController::preview_content', 9999 );
2422 }
2423
2424 echo apply_filters( 'the_content', $content ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2425
2426 if ( $has_preview_filter ) {
2427 add_filter( 'the_content', 'FrmFormsController::preview_content', 9999 );
2428 }
2429
2430 $post = $old_post;
2431 }
2432 }
2433
2434 /**
2435 * @since 3.0
2436 * @param array $args See {@see FrmFormsController::run_success_action()}.
2437 */
2438 private static function redirect_after_submit( $args ) {
2439 add_filter( 'frm_use_wpautop', '__return_false' );
2440
2441 $opt = $args['success_opt'];
2442 $success_url = trim( $args['form']->options[ $opt . '_url' ] );
2443 $success_url = apply_filters( 'frm_content', $success_url, $args['form'], $args['entry_id'] );
2444 $success_url = do_shortcode( $success_url );
2445
2446 $args['id'] = $args['entry_id'];
2447 FrmEntriesController::delete_entry_before_redirect( $success_url, $args['form'], $args );
2448
2449 add_filter( 'frm_redirect_url', 'FrmEntriesController::prepare_redirect_url' );
2450 $success_url = apply_filters( 'frm_redirect_url', $success_url, $args['form'], $args );
2451
2452 $doing_ajax = FrmAppHelper::doing_ajax();
2453
2454 if ( ! empty( $args['ajax'] ) && $doing_ajax && empty( $args['force_delay_redirect'] ) ) { // Is AJAX submit and there is just one Redirect action runs.
2455 echo json_encode( array( 'redirect' => $success_url ) );
2456 wp_die();
2457 }
2458
2459 if ( ! headers_sent() && empty( $args['force_delay_redirect'] ) ) { // Not AJAX submit, no headers sent, and there is just one Redirect action runs.
2460 wp_redirect( esc_url_raw( $success_url ) );
2461 die(); // do not use wp_die or redirect fails
2462 }
2463
2464 // Redirect with a delay.
2465 self::redirect_after_submit_using_js( $args + compact( 'success_url', 'doing_ajax' ) );
2466 }
2467
2468 /**
2469 * Redirects after submitting using JS. This is used when showing message before redirecting.
2470 *
2471 * @since 6.0
2472 *
2473 * @param array $args See {@see FrmFormsController::run_success_action()}.
2474 */
2475 private static function redirect_after_submit_using_js( $args ) {
2476 $success_msg = FrmOnSubmitHelper::get_default_redirect_msg();
2477 $redirect_msg = self::get_redirect_message( $args['success_url'], $success_msg, $args );
2478
2479 /**
2480 * Filters the delay time before redirecting when On Submit Redirect action is delayed.
2481 *
2482 * @since 6.0
2483 *
2484 * @param int $delay_time Delay time in miliseconds.
2485 */
2486 $delay_time = apply_filters( 'frm_redirect_delay_time', 8000 );
2487
2488 add_filter( 'frm_use_wpautop', '__return_true' );
2489
2490 echo FrmAppHelper::maybe_kses( $redirect_msg ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2491 echo '<script>';
2492 if ( empty( $args['doing_ajax'] ) ) { // Not AJAX submit, delay JS until window.load.
2493 echo 'window.onload=function(){';
2494 }
2495 echo 'setTimeout(function(){window.location="' . esc_url_raw( $args['success_url'] ) . '";}, ' . intval( $delay_time ) . ');';
2496 if ( empty( $args['doing_ajax'] ) ) {
2497 echo '};';
2498 }
2499 echo '</script>';
2500 }
2501
2502 /**
2503 * @since 3.0
2504 *
2505 * @param string $success_url
2506 * @param string $success_msg
2507 * @param array $args
2508 */
2509 private static function get_redirect_message( $success_url, $success_msg, $args ) {
2510 $redirect_msg = '<div class="' . esc_attr( FrmFormsHelper::get_form_style_class( $args['form'] ) ) . '"><div class="frm-redirect-msg" role="status">' . $success_msg . '<br/>' .
2511 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
2512 sprintf( __( '%1$sClick here%2$s if you are not automatically redirected.', 'formidable' ), '<a href="' . esc_url( $success_url ) . '">', '</a>' ) .
2513 '</div></div>';
2514
2515 $redirect_args = array(
2516 'entry_id' => $args['entry_id'],
2517 'form_id' => $args['form']->id,
2518 'form' => $args['form'],
2519 );
2520
2521 return apply_filters( 'frm_redirect_msg', $redirect_msg, $redirect_args );
2522 }
2523
2524 /**
2525 * Prepare to show the success message and empty form after submit
2526 *
2527 * @since 2.05
2528 */
2529 public static function show_message_after_save( $atts ) {
2530 $atts['message'] = self::prepare_submit_message( $atts['form'], $atts['entry_id'], $atts );
2531
2532 if ( ! isset( $atts['form']->options['show_form'] ) || $atts['form']->options['show_form'] ) {
2533 self::show_form_after_submit( $atts );
2534 } else {
2535 self::show_lone_success_messsage( $atts );
2536 }
2537 }
2538
2539 /**
2540 * Show an empty form
2541 *
2542 * @since 2.05
2543 */
2544 private static function show_form_after_submit( $args ) {
2545 self::fill_atts_for_form_display( $args );
2546
2547 $errors = $args['errors'];
2548 $message = $args['message'];
2549 $form = $args['form'];
2550 $title = $args['title'];
2551 $description = $args['description'];
2552
2553 if ( empty( $args['fields'] ) ) {
2554 $values = array(
2555 'custom_style' => FrmAppHelper::custom_style_value( array() ),
2556 );
2557 } else {
2558 $values = FrmEntriesHelper::setup_new_vars( $args['fields'], $form, $args['reset'] );
2559 }
2560 unset( $args );
2561
2562 $include_form_tag = apply_filters( 'frm_include_form_tag', true, $form );
2563
2564 $frm_settings = FrmAppHelper::get_settings();
2565 $submit = isset( $form->options['submit_value'] ) ? $form->options['submit_value'] : $frm_settings->submit_value;
2566
2567 global $frm_vars;
2568 self::maybe_load_css( $form, $values['custom_style'], $frm_vars['load_css'] );
2569
2570 $message_placement = self::message_placement( $form, $message );
2571
2572 include FrmAppHelper::plugin_path() . '/classes/views/frm-entries/new.php';
2573 }
2574
2575 /**
2576 * @return string - 'before', 'after', or 'submit'
2577 *
2578 * @since 4.05.02
2579 */
2580 private static function message_placement( $form, $message ) {
2581 $place = 'before';
2582
2583 if ( $message && isset( $form->options['form_class'] ) ) {
2584 if ( strpos( $form->options['form_class'], 'frm_below_success' ) !== false ) {
2585 $place = 'after';
2586 } elseif ( strpos( $form->options['form_class'], 'frm_inline_success' ) !== false ) {
2587 $place = 'submit';
2588 }
2589 }
2590
2591 /**
2592 * @return string - 'before' or 'after'
2593 *
2594 * @since 4.05.02
2595 */
2596 return apply_filters( 'frm_message_placement', $place, compact( 'form', 'message' ) );
2597 }
2598
2599 /**
2600 * Get all the values needed on the new.php entry page
2601 *
2602 * @since 2.05
2603 */
2604 private static function fill_atts_for_form_display( &$args ) {
2605 $defaults = array(
2606 'errors' => array(),
2607 'message' => '',
2608 'fields' => array(),
2609 'form' => array(),
2610 'title' => true,
2611 'description' => false,
2612 'reset' => false,
2613 );
2614 $args = wp_parse_args( $args, $defaults );
2615 }
2616
2617 /**
2618 * Show the success message without the form
2619 *
2620 * @since 2.05
2621 */
2622 private static function show_lone_success_messsage( $atts ) {
2623 global $frm_vars;
2624 $values = FrmEntriesHelper::setup_new_vars( $atts['fields'], $atts['form'], true );
2625 self::maybe_load_css( $atts['form'], $values['custom_style'], $frm_vars['load_css'] );
2626
2627 $include_extra_container = 'frm_forms' . FrmFormsHelper::get_form_style_class( $values );
2628
2629 $errors = array();
2630 $form = $atts['form'];
2631 $message = $atts['message'];
2632
2633 include( FrmAppHelper::plugin_path() . '/classes/views/frm-entries/errors.php' );
2634 }
2635
2636 /**
2637 * Prepare the success message before it's shown
2638 *
2639 * @since 2.05
2640 * @since 6.0.x Added the third parameter.
2641 *
2642 * @param object $form Form object.
2643 * @param int $entry_id Entry ID.
2644 * @param array $args See {@see FrmFormsController::run_success_action()}.
2645 * @return string
2646 */
2647 private static function prepare_submit_message( $form, $entry_id, $args = array() ) {
2648 $frm_settings = FrmAppHelper::get_settings( array( 'current_form' => $form->id ) );
2649 $opt = isset( $args['success_opt'] ) ? $args['success_opt'] : 'success';
2650
2651 if ( $entry_id && is_numeric( $entry_id ) ) {
2652 $message = isset( $form->options[ $opt . '_msg' ] ) ? $form->options[ $opt . '_msg' ] : $frm_settings->success_msg;
2653 $class = 'frm_message';
2654 } else {
2655 $message = $frm_settings->failed_msg;
2656 $class = FrmFormsHelper::form_error_class();
2657 }
2658
2659 $message = FrmFormsHelper::get_success_message( compact( 'message', 'form', 'entry_id', 'class' ) );
2660
2661 return apply_filters( 'frm_main_feedback', $message, $form, $entry_id );
2662 }
2663
2664 /**
2665 * @return void
2666 */
2667 public static function front_head() {
2668 $version = FrmAppHelper::plugin_version();
2669 $suffix = FrmAppHelper::js_suffix();
2670
2671 if ( ! empty( $suffix ) && self::has_combo_js_file() ) {
2672 wp_register_script( 'formidable', FrmAppHelper::plugin_url() . '/js/frm.min.js', array( 'jquery' ), $version, true );
2673 } else {
2674 wp_register_script( 'formidable', FrmAppHelper::plugin_url() . "/js/formidable{$suffix}.js", array( 'jquery' ), $version, true );
2675 }
2676
2677 add_filter( 'script_loader_tag', 'FrmFormsController::defer_script_loading', 10, 2 );
2678
2679 if ( FrmAppHelper::is_admin() ) {
2680 // don't load this in back-end
2681 return;
2682 }
2683
2684 FrmAppHelper::localize_script( 'front' );
2685 FrmStylesController::enqueue_css( 'register' );
2686 }
2687
2688 /**
2689 * @since 3.0
2690 */
2691 public static function has_combo_js_file() {
2692 return is_readable( FrmAppHelper::plugin_path() . '/js/frm.min.js' );
2693 }
2694
2695 public static function maybe_load_css( $form, $this_load, $global_load ) {
2696 $load_css = FrmForm::is_form_loaded( $form, $this_load, $global_load );
2697
2698 if ( ! $load_css ) {
2699 return;
2700 }
2701
2702 global $frm_vars;
2703 self::footer_js( 'header' );
2704 $frm_vars['css_loaded'] = true;
2705
2706 self::load_late_css();
2707 }
2708
2709 /**
2710 * If css is loaded only on applicable pages, include it before the form loads
2711 * to prevent a flash of unstyled form.
2712 *
2713 * @since 4.01
2714 *
2715 * @return void
2716 */
2717 private static function load_late_css() {
2718 $frm_settings = FrmAppHelper::get_settings();
2719 $late_css = $frm_settings->load_style === 'dynamic';
2720
2721 if ( ! $late_css || ! self::should_load_late() ) {
2722 return;
2723 }
2724
2725 global $wp_styles;
2726 if ( is_array( $wp_styles->queue ) && in_array( 'formidable', $wp_styles->queue, true ) ) {
2727 wp_print_styles( 'formidable' );
2728 }
2729 }
2730
2731 /**
2732 * Avoid late load if All in One SEO is active because it prevents CSS from loading entirely.
2733 *
2734 * @since 5.2.03
2735 *
2736 * @return bool
2737 */
2738 private static function should_load_late() {
2739 return ! function_exists( 'aioseo' );
2740 }
2741
2742 public static function defer_script_loading( $tag, $handle ) {
2743 if ( 'captcha-api' == $handle && ! strpos( $tag, 'defer' ) ) {
2744 $tag = str_replace( ' src', ' defer="defer" async="async" src', $tag );
2745 }
2746
2747 return $tag;
2748 }
2749
2750 public static function footer_js( $location = 'footer' ) {
2751 global $frm_vars;
2752
2753 FrmStylesController::enqueue_css();
2754
2755 if ( ! FrmAppHelper::is_admin() && $location != 'header' && ! empty( $frm_vars['forms_loaded'] ) ) {
2756 // load formidable js
2757 wp_enqueue_script( 'formidable' );
2758 }
2759 }
2760
2761 /**
2762 * @since 2.0.8
2763 */
2764 private static function maybe_minimize_form( $atts, &$content ) {
2765 // check if minimizing is turned on
2766 if ( self::is_minification_on( $atts ) ) {
2767 $content = str_replace( array( "\r\n", "\r", "\n", "\t", ' ' ), '', $content );
2768 }
2769 }
2770
2771 /**
2772 * @since 2.0.8
2773 * @return boolean
2774 */
2775 private static function is_minification_on( $atts ) {
2776 return isset( $atts['minimize'] ) && ! empty( $atts['minimize'] );
2777 }
2778
2779 /**
2780 * @since 5.0.16
2781 *
2782 * @return void
2783 */
2784 public static function landing_page_preview_option() {
2785 $dir = apply_filters( 'frm_landing_page_preview_option', false );
2786 if ( false === $dir || ! file_exists( $dir . 'landing-page-preview-option.php' ) ) {
2787 $dir = self::get_form_views_path();
2788 }
2789 include $dir . 'landing-page-preview-option.php';
2790 }
2791
2792 /**
2793 * @since 5.0.16
2794 *
2795 * @return string
2796 */
2797 private static function get_form_views_path() {
2798 return FrmAppHelper::plugin_path() . '/classes/views/frm-forms/';
2799 }
2800
2801 /**
2802 * Create a page with an embedded formidable Gutenberg block.
2803 *
2804 * @since 5.2
2805 *
2806 * @return never
2807 */
2808 public static function create_page_with_shortcode() {
2809 if ( ! current_user_can( 'publish_posts' ) ) {
2810 die( 0 );
2811 }
2812
2813 check_ajax_referer( 'frm_ajax', 'nonce' );
2814
2815 $type = FrmAppHelper::get_post_param( 'type', '', 'sanitize_text_field' );
2816 if ( ! $type || ! in_array( $type, array( 'form', 'view' ), true ) ) {
2817 die( 0 );
2818 }
2819
2820 $object_id = FrmAppHelper::get_post_param( 'object_id', '', 'absint' );
2821 if ( ! $object_id ) {
2822 die( 0 );
2823 }
2824
2825 $postarr = array( 'post_type' => 'page' );
2826
2827 if ( 'form' === $type ) {
2828 $postarr['post_content'] = self::get_page_shortcode_content_for_form( $object_id );
2829 } else {
2830 $postarr['post_content'] = apply_filters( 'frm_create_page_with_' . $type . '_shortcode_content', '', $object_id );
2831 }
2832
2833 $name = FrmAppHelper::get_post_param( 'name', '', 'sanitize_text_field' );
2834 if ( $name ) {
2835 $postarr['post_title'] = $name;
2836 }
2837
2838 $success = wp_insert_post( $postarr );
2839 if ( ! is_numeric( $success ) || ! $success ) {
2840 die( 0 );
2841 }
2842
2843 wp_send_json(
2844 array(
2845 'redirect' => get_edit_post_link( $success, 'redirect' ),
2846 )
2847 );
2848 }
2849
2850 /**
2851 * @since 5.3
2852 *
2853 * @param string $content
2854 * @param int $form_id
2855 * @return string
2856 */
2857 private static function get_page_shortcode_content_for_form( $form_id ) {
2858 $shortcode = '[formidable id="' . $form_id . '"]';
2859 $html_comment_start = '<!-- wp:formidable/simple-form {"formId":"' . $form_id . '"} -->';
2860 $html_comment_end = '<!-- /wp:formidable/simple-form -->';
2861 return $html_comment_start . '<div>' . $shortcode . '</div>' . $html_comment_end;
2862 }
2863
2864 /**
2865 * Get page dropdown for AJAX request for embedding form in an existing page.
2866 *
2867 * @return never
2868 */
2869 public static function get_page_dropdown() {
2870 if ( ! current_user_can( 'publish_posts' ) ) {
2871 die( 0 );
2872 }
2873
2874 check_ajax_referer( 'frm_ajax', 'nonce' );
2875
2876 $html = FrmAppHelper::clip(
2877 function() {
2878 FrmAppHelper::maybe_autocomplete_pages_options(
2879 array(
2880 'field_name' => 'frm_page_dropdown',
2881 'page_id' => '',
2882 'placeholder' => __( 'Select a Page', 'formidable' ),
2883 )
2884 );
2885 }
2886 );
2887 $post_type_object = get_post_type_object( 'page' );
2888 wp_send_json(
2889 array(
2890 'html' => $html,
2891 'edit_page_url' => admin_url( sprintf( $post_type_object->_edit_link . '&action=edit', 0 ) ),
2892 )
2893 );
2894 }
2895
2896 /**
2897 * @deprecated 4.0
2898 */
2899 public static function new_form( $values = array() ) {
2900 FrmDeprecated::new_form( $values );
2901 }
2902
2903 /**
2904 * @deprecated 4.0
2905 */
2906 public static function create( $values = array() ) {
2907 _deprecated_function( __METHOD__, '4.0', 'FrmFormsController::update' );
2908 self::update( $values );
2909 }
2910
2911 /**
2912 * @deprecated 1.07.05
2913 * @codeCoverageIgnore
2914 */
2915 public static function add_default_templates( $path, $default = true, $template = true ) {
2916 FrmDeprecated::add_default_templates( $path, $default, $template );
2917 }
2918
2919 /**
2920 * @deprecated 3.0
2921 * @codeCoverageIgnore
2922 */
2923 public static function bulk_create_template( $ids ) {
2924 return FrmDeprecated::bulk_create_template( $ids );
2925 }
2926
2927 /**
2928 * @deprecated 2.03
2929 * @codeCoverageIgnore
2930 */
2931 public static function register_pro_scripts() {
2932 FrmDeprecated::register_pro_scripts();
2933 }
2934
2935 /**
2936 * @deprecated 3.0
2937 * @codeCoverageIgnore
2938 */
2939 public static function edit_key() {
2940 FrmDeprecated::edit_key();
2941 }
2942
2943 /**
2944 * @deprecated 3.0
2945 * @codeCoverageIgnore
2946 */
2947 public static function edit_description() {
2948 FrmDeprecated::edit_description();
2949 }
2950
2951 /**
2952 * @deprecated 4.08
2953 * @since 3.06
2954 */
2955 public static function add_new() {
2956 _deprecated_function( __FUNCTION__, '4.08' );
2957 }
2958 }
2959