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

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