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

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