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

2,569 lines 73.6 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 maybe_update_form_builder_message( &$message ) {
1075 if ( 'form_duplicated' === FrmAppHelper::simple_get( 'message' ) ) {
1076 $message = __( 'Form was Successfully Copied', 'formidable' );
1077 }
1078 }
1079
1080 public static function get_settings_vars( $id, $errors = array(), $args = array() ) {
1081 FrmAppHelper::permission_check( 'frm_edit_forms' );
1082
1083 global $frm_vars;
1084
1085 if ( ! is_array( $args ) ) {
1086 // For reverse compatibility.
1087 $args = array(
1088 'message' => $args,
1089 );
1090 }
1091
1092 $defaults = array(
1093 'message' => '',
1094 'warnings' => array(),
1095 );
1096 $args = array_merge( $defaults, $args );
1097 $message = $args['message'];
1098 $warnings = $args['warnings'];
1099
1100 $form = FrmForm::getOne( $id );
1101 $fields = FrmField::get_all_for_form( $id );
1102 $values = FrmAppHelper::setup_edit_vars( $form, 'forms', $fields, true );
1103
1104 /**
1105 * Allows changing fields in the form settings.
1106 *
1107 * @since 5.0.04
1108 *
1109 * @param array $fields Array of fields.
1110 * @param array $args The arguments. Contains `form`.
1111 */
1112 $values['fields'] = apply_filters( 'frm_fields_in_settings', $values['fields'], compact( 'form' ) );
1113
1114 self::clean_submit_html( $values );
1115
1116 $sections = self::get_settings_tabs( $values );
1117 $current = FrmAppHelper::simple_get( 't', 'sanitize_title', 'advanced_settings' );
1118
1119 require( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/settings.php' );
1120 }
1121
1122 /**
1123 * @since 4.0
1124 */
1125 public static function form_publish_button( $atts ) {
1126 $values = $atts['values'];
1127 include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/_publish_box.php' );
1128 }
1129
1130 /**
1131 * Get a list of all the settings tabs for the form settings page.
1132 *
1133 * @since 4.0
1134 *
1135 * @param array $values
1136 * @return array
1137 */
1138 private static function get_settings_tabs( $values ) {
1139 $sections = array(
1140 'advanced' => array(
1141 'name' => __( 'General', 'formidable' ),
1142 'title' => __( 'General Form Settings', 'formidable' ),
1143 'function' => array( __CLASS__, 'advanced_settings' ),
1144 'icon' => 'frm_icon_font frm_settings_icon',
1145 ),
1146 'email' => array(
1147 'name' => __( 'Actions & Notifications', 'formidable' ),
1148 'function' => array( 'FrmFormActionsController', 'email_settings' ),
1149 'id' => 'frm_notification_settings',
1150 'icon' => 'frm_icon_font frm_mail_bulk_icon',
1151 ),
1152 'permissions' => array(
1153 'name' => __( 'Form Permissions', 'formidable' ),
1154 'icon' => 'frm_icon_font frm_lock_icon',
1155 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1156 'data' => array(
1157 'medium' => 'permissions',
1158 'upgrade' => __( 'Form Permissions', 'formidable' ),
1159 'message' => __( 'Allow editing, protect forms and files, limit entries, and save drafts. Upgrade to get form and entry permissions.', 'formidable' ),
1160 'screenshot' => 'permissions.png',
1161 ),
1162 ),
1163 'scheduling' => array(
1164 'name' => __( 'Form Scheduling', 'formidable' ),
1165 'icon' => 'frm_icon_font frm_calendar_icon',
1166 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1167 'data' => array(
1168 'medium' => 'scheduling',
1169 'upgrade' => __( 'Form scheduling settings', 'formidable' ),
1170 'screenshot' => 'scheduling.png',
1171 ),
1172 ),
1173 'buttons' => array(
1174 'name' => __( 'Styling & Buttons', 'formidable' ),
1175 'class' => __CLASS__,
1176 'function' => 'buttons_settings',
1177 'icon' => 'frm_icon_font frm_pallet_icon',
1178 ),
1179 'landing' => array(
1180 'name' => __( 'Form Landing Page', 'formidable' ),
1181 'icon' => 'frm_icon_font frm_file_text_icon',
1182 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1183 'data' => FrmAppHelper::get_landing_page_upgrade_data_params(),
1184 ),
1185 'chat' => array(
1186 'name' => __( 'Conversational Forms', 'formidable' ),
1187 'icon' => 'frm_icon_font frm_chat_forms_icon',
1188 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1189 'data' => FrmAppHelper::get_upgrade_data_params(
1190 'chat',
1191 array(
1192 'upgrade' => __( 'Conversational Forms', 'formidable' ),
1193 'message' => __( 'Ask one question at a time for automated conversations.', 'formidable' ),
1194 'screenshot' => 'chat.png',
1195 )
1196 ),
1197 ),
1198 'html' => array(
1199 'name' => __( 'Customize HTML', 'formidable' ),
1200 'class' => __CLASS__,
1201 'function' => 'html_settings',
1202 'icon' => 'frm_icon_font frm_code_icon',
1203 ),
1204 );
1205
1206 foreach ( array( 'landing', 'chat' ) as $feature ) {
1207 if ( ! FrmAppHelper::show_new_feature( $feature ) ) {
1208 unset( $sections[ $feature ] );
1209 }
1210 }
1211
1212 $sections = apply_filters( 'frm_add_form_settings_section', $sections, $values );
1213
1214 if ( FrmAppHelper::pro_is_installed() && ! FrmAppHelper::meets_min_pro_version( '4.0' ) ) {
1215 // Prevent settings from showing in 2 spots.
1216 unset( $sections['permissions'], $sections['scheduling'] );
1217 }
1218
1219 foreach ( $sections as $key => $section ) {
1220 $defaults = array(
1221 'html_class' => '',
1222 'name' => ucfirst( $key ),
1223 'icon' => 'frm_icon_font frm_settings_icon',
1224 );
1225
1226 $section = array_merge( $defaults, $section );
1227
1228 if ( ! isset( $section['anchor'] ) ) {
1229 $section['anchor'] = $key;
1230 }
1231 $section['anchor'] .= '_settings';
1232
1233 if ( ! isset( $section['title'] ) ) {
1234 $section['title'] = $section['name'];
1235 }
1236
1237 if ( ! isset( $section['id'] ) ) {
1238 $section['id'] = $section['anchor'];
1239 }
1240
1241 $sections[ $key ] = $section;
1242 }
1243
1244 return $sections;
1245 }
1246
1247 /**
1248 * @since 4.0
1249 *
1250 * @param array $values
1251 */
1252 public static function advanced_settings( $values ) {
1253 $first_h3 = 'frm_first_h3';
1254
1255 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/settings-advanced.php';
1256 }
1257
1258 /**
1259 * @param array $values
1260 */
1261 private static function render_spam_settings( $values ) {
1262 if ( function_exists( 'akismet_http_post' ) ) {
1263 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/spam-settings/akismet.php';
1264 }
1265 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/spam-settings/honeypot.php';
1266 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/spam-settings/antispam.php';
1267 }
1268
1269 /**
1270 * @since 4.0
1271 *
1272 * @param array $values
1273 */
1274 public static function buttons_settings( $values ) {
1275 $styles = apply_filters( 'frm_get_style_opts', array() );
1276
1277 $frm_settings = FrmAppHelper::get_settings();
1278 $no_global_style = $frm_settings->load_style === 'none';
1279
1280 include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/settings-buttons.php' );
1281 }
1282
1283 /**
1284 * @since 4.0
1285 *
1286 * @param array $values
1287 */
1288 public static function html_settings( $values ) {
1289 include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/settings-html.php' );
1290 }
1291
1292 /**
1293 * Replace old Submit Button href with new href to avoid errors in Chrome
1294 *
1295 * @since 2.03.08
1296 *
1297 * @param array|boolean $values
1298 */
1299 private static function clean_submit_html( &$values ) {
1300 if ( is_array( $values ) && isset( $values['submit_html'] ) ) {
1301 $values['submit_html'] = str_replace( 'javascript:void(0)', '#', $values['submit_html'] );
1302 }
1303 }
1304
1305 public static function mb_tags_box( $form_id, $class = '' ) {
1306 $fields = FrmField::get_all_for_form( $form_id, '', 'include' );
1307
1308 /**
1309 * Allows modifying the list of fields in the tags box.
1310 *
1311 * @since 5.0.04
1312 *
1313 * @param array $fields The list of fields.
1314 * @param array $args The arguments. Contains `form_id`.
1315 */
1316 $fields = apply_filters( 'frm_fields_in_tags_box', $fields, compact( 'form_id' ) );
1317 $linked_forms = array();
1318 $col = 'one';
1319 $settings_tab = FrmAppHelper::is_admin_page( 'formidable' ) ? true : false;
1320
1321 $cond_shortcodes = apply_filters( 'frm_conditional_shortcodes', array() );
1322 $entry_shortcodes = self::get_shortcode_helpers( $settings_tab );
1323
1324 $advanced_helpers = self::advanced_helpers( compact( 'fields', 'form_id' ) );
1325
1326 include( FrmAppHelper::plugin_path() . '/classes/views/shared/mb_adv_info.php' );
1327 }
1328
1329 /**
1330 * @since 3.04.01
1331 */
1332 private static function advanced_helpers( $atts ) {
1333 $advanced_helpers = array(
1334 'default' => array(
1335 'heading' => __( 'Customize field values with the following parameters.', 'formidable' ),
1336 'codes' => self::get_advanced_shortcodes(),
1337 ),
1338 );
1339
1340 $user_fields = self::user_shortcodes();
1341 if ( ! empty( $user_fields ) ) {
1342 $user_helpers = array();
1343 foreach ( $user_fields as $uk => $uf ) {
1344 $user_helpers[ '|user_id| show="' . $uk . '"' ] = $uf;
1345 unset( $uk, $uf );
1346 }
1347
1348 $advanced_helpers['user_id'] = array(
1349 'codes' => $user_helpers,
1350 );
1351 }
1352
1353 /**
1354 * Add extra helper shortcodes on the Advanced tab in form settings and views
1355 *
1356 * @since 3.04.01
1357 *
1358 * @param array $advanced_helpers
1359 * @param array $atts - Includes fields and form_id
1360 */
1361 return apply_filters( 'frm_advanced_helpers', $advanced_helpers, $atts );
1362 }
1363
1364 /**
1365 * Get an array of the options to display in the advanced tab
1366 * of the customization panel
1367 *
1368 * @since 2.0.6
1369 */
1370 private static function get_advanced_shortcodes() {
1371 $adv_shortcodes = array(
1372 'x sep=", "' => array(
1373 'label' => __( 'Separator', 'formidable' ),
1374 'title' => __( 'Use a different separator for checkbox fields', 'formidable' ),
1375 ),
1376 'x format="d-m-Y"' => array(
1377 'label' => __( 'Date Format', 'formidable' ),
1378 ),
1379 'x show="field_label"' => array(
1380 'label' => __( 'Field Label', 'formidable' ),
1381 ),
1382 'x wpautop=0' => array(
1383 'label' => __( 'No Auto P', 'formidable' ),
1384 'title' => __( 'Do not automatically add any paragraphs or line breaks', 'formidable' ),
1385 ),
1386 );
1387 $adv_shortcodes = apply_filters( 'frm_advanced_shortcodes', $adv_shortcodes );
1388
1389 // __( 'Leave blank instead of defaulting to User Login', 'formidable' ) : blank=1
1390
1391 return $adv_shortcodes;
1392 }
1393
1394 /**
1395 * @since 3.04.01
1396 */
1397 private static function user_shortcodes() {
1398 $options = array(
1399 'ID' => __( 'User ID', 'formidable' ),
1400 'first_name' => __( 'First Name', 'formidable' ),
1401 'last_name' => __( 'Last Name', 'formidable' ),
1402 'display_name' => __( 'Display Name', 'formidable' ),
1403 'user_login' => __( 'User Login', 'formidable' ),
1404 'user_email' => __( 'Email', 'formidable' ),
1405 'avatar' => __( 'Avatar', 'formidable' ),
1406 'author_link' => __( 'Author Link', 'formidable' ),
1407 );
1408
1409 return apply_filters( 'frm_user_shortcodes', $options );
1410 }
1411
1412 /**
1413 * Get an array of the helper shortcodes to display in the customization panel
1414 *
1415 * @since 2.0.6
1416 */
1417 private static function get_shortcode_helpers( $settings_tab ) {
1418 $entry_shortcodes = array(
1419 'id' => __( 'Entry ID', 'formidable' ),
1420 'key' => __( 'Entry Key', 'formidable' ),
1421 'post_id' => __( 'Post ID', 'formidable' ),
1422 'ip' => __( 'User IP', 'formidable' ),
1423 'created-at' => __( 'Entry created', 'formidable' ),
1424 'updated-at' => __( 'Entry updated', 'formidable' ),
1425 '' => '',
1426 'siteurl' => __( 'Site URL', 'formidable' ),
1427 'sitename' => __( 'Site Name', 'formidable' ),
1428 );
1429
1430 if ( ! FrmAppHelper::pro_is_installed() ) {
1431 unset( $entry_shortcodes['post_id'] );
1432 }
1433
1434 if ( $settings_tab ) {
1435 $entry_shortcodes['default-message'] = __( 'Default Msg', 'formidable' );
1436 $entry_shortcodes['default-html'] = __( 'Default HTML', 'formidable' );
1437 $entry_shortcodes['default-plain'] = __( 'Default Plain', 'formidable' );
1438 }
1439
1440 /**
1441 * Use this hook to add or remove buttons in the helpers section
1442 * in the customization panel
1443 *
1444 * @since 2.0.6
1445 */
1446 $entry_shortcodes = apply_filters( 'frm_helper_shortcodes', $entry_shortcodes, $settings_tab );
1447
1448 return $entry_shortcodes;
1449 }
1450
1451 /**
1452 * Insert the form class setting into the form
1453 */
1454 public static function form_classes( $form ) {
1455 if ( isset( $form->options['form_class'] ) ) {
1456 echo esc_attr( sanitize_text_field( $form->options['form_class'] ) );
1457 }
1458
1459 if ( ! empty( $form->options['js_validate'] ) ) {
1460 echo ' frm_js_validate ';
1461 self::add_js_validate_form_to_global_vars( $form );
1462 }
1463 }
1464
1465 /**
1466 * @since 5.0.03
1467 *
1468 * @param stdClass $form
1469 */
1470 public static function add_js_validate_form_to_global_vars( $form ) {
1471 global $frm_vars;
1472 if ( ! isset( $frm_vars['js_validate_forms'] ) ) {
1473 $frm_vars['js_validate_forms'] = array();
1474 }
1475 $frm_vars['js_validate_forms'][ $form->id ] = $form;
1476 }
1477
1478 public static function get_email_html() {
1479 FrmAppHelper::permission_check( 'frm_view_forms' );
1480 check_ajax_referer( 'frm_ajax', 'nonce' );
1481
1482 echo FrmEntriesController::show_entry_shortcode( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1483 array(
1484 'form_id' => FrmAppHelper::get_post_param( 'form_id', '', 'absint' ),
1485 'default_email' => true,
1486 'plain_text' => FrmAppHelper::get_post_param( 'plain_text', '', 'absint' ),
1487 )
1488 );
1489 wp_die();
1490 }
1491
1492 public static function filter_content( $content, $form, $entry = false ) {
1493 self::get_entry_by_param( $entry );
1494 if ( ! $entry ) {
1495 return $content;
1496 }
1497
1498 if ( is_object( $form ) ) {
1499 $form = $form->id;
1500 }
1501
1502 $shortcodes = FrmFieldsHelper::get_shortcodes( $content, $form );
1503 $content = apply_filters( 'frm_replace_content_shortcodes', $content, $entry, $shortcodes );
1504
1505 return $content;
1506 }
1507
1508 private static function get_entry_by_param( &$entry ) {
1509 if ( ! $entry || ! is_object( $entry ) ) {
1510 if ( ! $entry || ! is_numeric( $entry ) ) {
1511 $entry = FrmAppHelper::get_post_param( 'id', false, 'sanitize_title' );
1512 }
1513
1514 FrmEntry::maybe_get_entry( $entry );
1515 }
1516 }
1517
1518 public static function replace_content_shortcodes( $content, $entry, $shortcodes ) {
1519 return FrmFieldsHelper::replace_content_shortcodes( $content, $entry, $shortcodes );
1520 }
1521
1522 public static function process_bulk_form_actions( $errors ) {
1523 if ( ! $_REQUEST ) {
1524 return $errors;
1525 }
1526
1527 $bulkaction = FrmAppHelper::get_param( 'action', '', 'get', 'sanitize_text_field' );
1528 if ( $bulkaction == - 1 ) {
1529 $bulkaction = FrmAppHelper::get_param( 'action2', '', 'get', 'sanitize_title' );
1530 }
1531
1532 if ( ! empty( $bulkaction ) && strpos( $bulkaction, 'bulk_' ) === 0 ) {
1533 FrmAppHelper::remove_get_action();
1534
1535 $bulkaction = str_replace( 'bulk_', '', $bulkaction );
1536 }
1537
1538 $ids = FrmAppHelper::get_param( 'item-action', '', 'get', 'sanitize_text_field' );
1539 if ( empty( $ids ) ) {
1540 $errors[] = __( 'No forms were specified', 'formidable' );
1541
1542 return $errors;
1543 }
1544
1545 $permission_error = FrmAppHelper::permission_nonce_error( '', '_wpnonce', 'bulk-toplevel_page_formidable' );
1546 if ( $permission_error !== false ) {
1547 $errors[] = $permission_error;
1548
1549 return $errors;
1550 }
1551
1552 if ( ! is_array( $ids ) ) {
1553 $ids = explode( ',', $ids );
1554 }
1555
1556 switch ( $bulkaction ) {
1557 case 'delete':
1558 $message = self::bulk_destroy( $ids );
1559 break;
1560 case 'trash':
1561 $message = self::bulk_trash( $ids );
1562 break;
1563 case 'untrash':
1564 $message = self::bulk_untrash( $ids );
1565 }
1566
1567 if ( isset( $message ) && ! empty( $message ) ) {
1568 $errors['message'] = $message;
1569 }
1570
1571 return $errors;
1572 }
1573
1574 public static function route() {
1575 $action = isset( $_REQUEST['frm_action'] ) ? 'frm_action' : 'action';
1576 $vars = array();
1577 FrmAppHelper::include_svg();
1578
1579 if ( isset( $_POST['frm_compact_fields'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1580 FrmAppHelper::permission_check( 'frm_edit_forms' );
1581
1582 // Javascript needs to be allowed in some field settings.
1583 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
1584 $json_vars = htmlspecialchars_decode( nl2br( str_replace( '&quot;', '"', wp_unslash( $_POST['frm_compact_fields'] ) ) ) );
1585 $json_vars = json_decode( $json_vars, true );
1586 if ( empty( $json_vars ) ) {
1587 // json decoding failed so we should return an error message.
1588 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
1589 if ( 'edit' == $action ) {
1590 $action = 'update';
1591 }
1592
1593 add_filter( 'frm_validate_form', 'FrmFormsController::json_error' );
1594 } else {
1595 $vars = FrmAppHelper::json_to_array( $json_vars );
1596 $action = $vars[ $action ];
1597 unset( $_REQUEST['frm_compact_fields'], $_POST['frm_compact_fields'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1598 $_REQUEST = array_merge( $_REQUEST, $vars ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1599 $_POST = array_merge( $_POST, $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1600 }
1601 } else {
1602 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
1603 if ( isset( $_REQUEST['delete_all'] ) ) {
1604 // Override the action for this page.
1605 $action = 'delete_all';
1606 }
1607 }
1608
1609 add_action( 'frm_load_form_hooks', 'FrmHooksController::trigger_load_form_hooks' );
1610 FrmAppHelper::trigger_hook_load( 'form' );
1611
1612 switch ( $action ) {
1613 case 'new':
1614 return self::new_form( $vars );
1615 case 'create':
1616 case 'edit':
1617 case 'update':
1618 case 'trash':
1619 case 'untrash':
1620 case 'destroy':
1621 case 'delete_all':
1622 case 'settings':
1623 case 'update_settings':
1624 return self::$action( $vars );
1625 case 'lite-reports':
1626 return self::no_reports( $vars );
1627 case 'views':
1628 return self::no_views( $vars );
1629 default:
1630 do_action( 'frm_form_action_' . $action );
1631 if ( apply_filters( 'frm_form_stop_action_' . $action, false ) ) {
1632 return;
1633 }
1634
1635 $action = FrmAppHelper::get_param( 'action', '', 'get', 'sanitize_text_field' );
1636 if ( $action == - 1 ) {
1637 $action = FrmAppHelper::get_param( 'action2', '', 'get', 'sanitize_title' );
1638 }
1639
1640 if ( strpos( $action, 'bulk_' ) === 0 ) {
1641 FrmAppHelper::remove_get_action();
1642
1643 self::list_form();
1644 return;
1645 }
1646
1647 $message = FrmAppHelper::get_param( 'message' );
1648 if ( 'form_duplicate_error' === $message ) {
1649 self::display_forms_list( array(), '', array( __( 'There was a problem duplicating the form', 'formidable' ) ) );
1650 return;
1651 }
1652
1653 self::display_forms_list();
1654
1655 return;
1656 }
1657 }
1658
1659 public static function json_error( $errors ) {
1660 $errors['json'] = __( 'Abnormal HTML characters prevented your form from saving correctly', 'formidable' );
1661
1662 return $errors;
1663 }
1664
1665 /**
1666 * Education for premium features.
1667 *
1668 * @since 4.05
1669 */
1670 public static function add_form_style_tab_options() {
1671 include( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/add_form_style_options.php' );
1672 }
1673
1674 /**
1675 * Add education about views.
1676 *
1677 * @since 4.07
1678 */
1679 public static function no_views( $values = array() ) {
1680 FrmAppHelper::include_svg();
1681 $id = FrmAppHelper::get_param( 'form', '', 'get', 'absint' );
1682 $form = $id ? FrmForm::getOne( $id ) : false;
1683
1684 include FrmAppHelper::plugin_path() . '/classes/views/shared/views-info.php';
1685 }
1686
1687 /**
1688 * Add education about reports.
1689 *
1690 * @since 4.07
1691 */
1692 public static function no_reports( $values = array() ) {
1693 $id = FrmAppHelper::get_param( 'form', '', 'get', 'absint' );
1694 $form = $id ? FrmForm::getOne( $id ) : false;
1695
1696 include FrmAppHelper::plugin_path() . '/classes/views/shared/reports-info.php';
1697 }
1698
1699 /* FRONT-END FORMS */
1700 public static function admin_bar_css() {
1701 if ( is_admin() || ! current_user_can( 'frm_edit_forms' ) ) {
1702 return;
1703 }
1704
1705 self::move_menu_to_footer();
1706
1707 add_action( 'wp_before_admin_bar_render', 'FrmFormsController::admin_bar_configure' );
1708 FrmAppHelper::load_font_style();
1709 }
1710
1711 /**
1712 * @since 4.05.02
1713 */
1714 private static function move_menu_to_footer() {
1715 $settings = FrmAppHelper::get_settings();
1716 if ( empty( $settings->admin_bar ) ) {
1717 remove_action( 'wp_body_open', 'wp_admin_bar_render', 0 );
1718 }
1719 }
1720
1721 public static function admin_bar_configure() {
1722 global $frm_vars;
1723 if ( empty( $frm_vars['forms_loaded'] ) ) {
1724 return;
1725 }
1726
1727 $actions = array();
1728 foreach ( $frm_vars['forms_loaded'] as $form ) {
1729 if ( is_object( $form ) ) {
1730 $actions[ $form->id ] = $form->name;
1731 }
1732 unset( $form );
1733 }
1734
1735 if ( empty( $actions ) ) {
1736 return;
1737 }
1738
1739 self::add_menu_to_admin_bar();
1740 self::add_forms_to_admin_bar( $actions );
1741 }
1742
1743 /**
1744 * @since 2.05.07
1745 */
1746 public static function add_menu_to_admin_bar() {
1747 global $wp_admin_bar;
1748
1749 $wp_admin_bar->add_node(
1750 array(
1751 'id' => 'frm-forms',
1752 'title' => '<span class="ab-icon"></span><span class="ab-label">' . FrmAppHelper::get_menu_name() . '</span>',
1753 'href' => admin_url( 'admin.php?page=formidable' ),
1754 'meta' => array(
1755 'title' => FrmAppHelper::get_menu_name(),
1756 ),
1757 )
1758 );
1759 }
1760
1761 /**
1762 * @since 2.05.07
1763 */
1764 private static function add_forms_to_admin_bar( $actions ) {
1765 global $wp_admin_bar;
1766
1767 asort( $actions );
1768
1769 foreach ( $actions as $form_id => $name ) {
1770
1771 $wp_admin_bar->add_node(
1772 array(
1773 'parent' => 'frm-forms',
1774 'id' => 'edit_form_' . $form_id,
1775 'title' => empty( $name ) ? __( '(no title)', 'formidable' ) : $name,
1776 'href' => FrmForm::get_edit_link( $form_id ),
1777 )
1778 );
1779 }
1780 }
1781
1782 /**
1783 * The formidable shortcode
1784 *
1785 * @param array $atts The params from the shortcode.
1786 * @return string
1787 */
1788 public static function get_form_shortcode( $atts ) {
1789 global $frm_vars;
1790 if ( isset( $frm_vars['skip_shortcode'] ) && $frm_vars['skip_shortcode'] ) {
1791 $sc = '[formidable';
1792 $sc .= FrmAppHelper::array_to_html_params( $atts );
1793 return $sc . ']';
1794 }
1795
1796 $shortcode_atts = shortcode_atts(
1797 array(
1798 'id' => '',
1799 'key' => '',
1800 'title' => 'auto',
1801 'description' => 'auto',
1802 'readonly' => false,
1803 'entry_id' => false,
1804 'fields' => array(),
1805 'exclude_fields' => array(),
1806 'minimize' => false,
1807 ),
1808 $atts
1809 );
1810 do_action( 'formidable_shortcode_atts', $shortcode_atts, $atts );
1811
1812 return self::show_form( $shortcode_atts['id'], $shortcode_atts['key'], $shortcode_atts['title'], $shortcode_atts['description'], $atts );
1813 }
1814
1815 /**
1816 * @since 5.2.01
1817 *
1818 * @param string|int|false $id
1819 * @param string|false $key
1820 * @return stdClass|false
1821 */
1822 private static function maybe_get_form_by_id_or_key( $id, $key ) {
1823 if ( ! $id ) {
1824 $id = $key;
1825 }
1826 return self::maybe_get_form_to_show( $id );
1827 }
1828
1829 /**
1830 * @param string|int|false $id
1831 * @param string|false $key
1832 * @param string|int|bool $title may be 'auto', true, false, 'true', 'false', 'yes', '1', 1, '0', 0.
1833 * @param string|int|bool $description may be 'auto', true, false, 'true', 'false', 'yes', '1', 1, '0', 0.
1834 * @param array $atts
1835 * @return string
1836 */
1837 public static function show_form( $id = '', $key = '', $title = false, $description = false, $atts = array() ) {
1838 $form = self::maybe_get_form_by_id_or_key( $id, $key );
1839
1840 if ( ! $form ) {
1841 return __( 'Please select a valid form', 'formidable' );
1842 }
1843
1844 if ( 'auto' === $title ) {
1845 $title = ! empty( $form->options['show_title'] );
1846 }
1847
1848 if ( 'auto' === $description ) {
1849 $description = ! empty( $form->options['show_description'] );
1850 }
1851
1852 FrmAppController::maybe_update_styles();
1853
1854 add_action( 'frm_load_form_hooks', 'FrmHooksController::trigger_load_form_hooks' );
1855 FrmAppHelper::trigger_hook_load( 'form', $form );
1856
1857 $form = apply_filters( 'frm_pre_display_form', $form );
1858
1859 $frm_settings = FrmAppHelper::get_settings( array( 'current_form' => $form->id ) );
1860
1861 if ( self::is_viewable_draft_form( $form ) ) {
1862 // don't show a draft form on a page
1863 $form = __( 'Please select a valid form', 'formidable' );
1864 } elseif ( ! FrmForm::is_visible_to_user( $form ) ) {
1865 $form = do_shortcode( $frm_settings->login_msg );
1866 } else {
1867 do_action( 'frm_pre_get_form', $form );
1868 $form = self::get_form( $form, $title, $description, $atts );
1869
1870 /**
1871 * Use this shortcode to check for external shortcodes that may span
1872 * across multiple fields in the customizable HTML
1873 *
1874 * @since 2.0.8
1875 */
1876 $form = apply_filters( 'frm_filter_final_form', $form );
1877 }
1878
1879 return $form;
1880 }
1881
1882 /**
1883 * @param string|int|false $id
1884 * @return stdClass|false
1885 */
1886 private static function maybe_get_form_to_show( $id ) {
1887 $form = false;
1888
1889 if ( ! empty( $id ) ) { // form id or key is set
1890 $form = FrmForm::getOne( $id );
1891 if ( ! $form || $form->parent_form_id || $form->status === 'trash' ) {
1892 $form = false;
1893 }
1894 }
1895
1896 return $form;
1897 }
1898
1899 private static function is_viewable_draft_form( $form ) {
1900 return $form->status === 'draft' && current_user_can( 'frm_edit_forms' ) && ! FrmAppHelper::is_preview_page();
1901 }
1902
1903 public static function get_form( $form, $title, $description, $atts = array() ) {
1904 ob_start();
1905
1906 do_action( 'frm_before_get_form', $atts );
1907
1908 self::get_form_contents( $form, $title, $description, $atts );
1909 self::enqueue_scripts( FrmForm::get_params( $form ) );
1910
1911 $contents = ob_get_contents();
1912 ob_end_clean();
1913
1914 self::maybe_minimize_form( $atts, $contents );
1915
1916 return $contents;
1917 }
1918
1919 public static function enqueue_scripts( $params ) {
1920 do_action( 'frm_enqueue_form_scripts', $params );
1921 }
1922
1923 public static function get_form_contents( $form, $title, $description, $atts ) {
1924 $params = FrmForm::get_params( $form );
1925 $errors = self::get_saved_errors( $form, $params );
1926 $fields = FrmFieldsHelper::get_form_fields( $form->id, $errors );
1927 $reset = false;
1928 $pass_args = compact( 'form', 'fields', 'errors', 'title', 'description', 'reset' );
1929
1930 $handle_process_here = $params['action'] === 'create' && $params['posted_form_id'] == $form->id && $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing
1931
1932 if ( ! $handle_process_here ) {
1933 do_action( 'frm_display_form_action', $params, $fields, $form, $title, $description );
1934 if ( apply_filters( 'frm_continue_to_new', true, $form->id, $params['action'] ) ) {
1935 self::show_form_after_submit( $pass_args );
1936 }
1937 } elseif ( ! empty( $errors ) ) {
1938 self::show_form_after_submit( $pass_args );
1939
1940 } else {
1941
1942 do_action( 'frm_validate_form_creation', $params, $fields, $form, $title, $description );
1943
1944 if ( apply_filters( 'frm_continue_to_create', true, $form->id ) ) {
1945 $entry_id = self::just_created_entry( $form->id );
1946 $pass_args['entry_id'] = $entry_id;
1947 $pass_args['reset'] = true;
1948 $pass_args['conf_method'] = self::get_confirmation_method( compact( 'form', 'entry_id' ) );
1949
1950 self::run_success_action( $pass_args );
1951
1952 do_action(
1953 'frm_after_entry_processed',
1954 array(
1955 'entry_id' => $entry_id,
1956 'form' => $form,
1957 )
1958 );
1959 }
1960 }
1961 }
1962
1963 /**
1964 * If the form was processed earlier (init), get the generated errors
1965 *
1966 * @since 2.05
1967 */
1968 private static function get_saved_errors( $form, $params ) {
1969 global $frm_vars;
1970
1971 if ( $params['posted_form_id'] == $form->id && $_POST && isset( $frm_vars['created_entries'][ $form->id ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1972 $errors = $frm_vars['created_entries'][ $form->id ]['errors'];
1973 } else {
1974 $errors = array();
1975 }
1976
1977 /**
1978 * Allows modifying the generated errors if the form was processed earlier.
1979 *
1980 * @since 5.2.03
1981 *
1982 * @param array $errors Errors data. Is empty array if no errors found.
1983 * @param array $params Form params. See {@see FrmForm::get_params()}.
1984 */
1985 return apply_filters( 'frm_saved_errors', $errors, $params );
1986 }
1987
1988 /**
1989 * @since 2.2.7
1990 */
1991 public static function just_created_entry( $form_id ) {
1992 global $frm_vars;
1993
1994 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;
1995 }
1996
1997 /**
1998 * @since 3.0
1999 */
2000 private static function get_confirmation_method( $atts ) {
2001 $opt = 'success_action';
2002 $method = ( isset( $atts['form']->options[ $opt ] ) && ! empty( $atts['form']->options[ $opt ] ) ) ? $atts['form']->options[ $opt ] : 'message';
2003 $method = apply_filters( 'frm_success_filter', $method, $atts['form'], 'create' );
2004
2005 if ( $method != 'message' && ( ! $atts['entry_id'] || ! is_numeric( $atts['entry_id'] ) ) ) {
2006 $method = 'message';
2007 }
2008
2009 return $method;
2010 }
2011
2012 public static function maybe_trigger_redirect( $form, $params, $args ) {
2013 if ( ! isset( $params['id'] ) ) {
2014 global $frm_vars;
2015 $params['id'] = $frm_vars['created_entries'][ $form->id ]['entry_id'];
2016 }
2017
2018 $conf_method = self::get_confirmation_method(
2019 array(
2020 'form' => $form,
2021 'entry_id' => $params['id'],
2022 )
2023 );
2024
2025 if ( 'redirect' === $conf_method ) {
2026 self::trigger_redirect( $form, $params, $args );
2027 }
2028 }
2029
2030 public static function trigger_redirect( $form, $params, $args ) {
2031 $success_args = array(
2032 'action' => $params['action'],
2033 'conf_method' => 'redirect',
2034 'form' => $form,
2035 'entry_id' => $params['id'],
2036 );
2037
2038 if ( isset( $args['ajax'] ) ) {
2039 $success_args['ajax'] = $args['ajax'];
2040 }
2041
2042 self::run_success_action( $success_args );
2043 }
2044
2045 /**
2046 * Used when the success action is not 'message'
2047 *
2048 * @since 2.05
2049 */
2050 public static function run_success_action( $args ) {
2051 $extra_args = $args;
2052 unset( $extra_args['form'] );
2053
2054 do_action( 'frm_success_action', $args['conf_method'], $args['form'], $args['form']->options, $args['entry_id'], $extra_args );
2055
2056 $opt = ( ! isset( $args['action'] ) || $args['action'] === 'create' ) ? 'success' : 'edit';
2057
2058 $args['success_opt'] = $opt;
2059 if ( $args['conf_method'] === 'page' && is_numeric( $args['form']->options[ $opt . '_page_id' ] ) ) {
2060 self::load_page_after_submit( $args );
2061 } elseif ( $args['conf_method'] === 'redirect' ) {
2062 self::redirect_after_submit( $args );
2063 } else {
2064 self::show_message_after_save( $args );
2065 }
2066 }
2067
2068 /**
2069 * @since 3.0
2070 */
2071 private static function load_page_after_submit( $args ) {
2072 global $post;
2073 $opt = $args['success_opt'];
2074 if ( ! $post || $args['form']->options[ $opt . '_page_id' ] != $post->ID ) {
2075 $page = get_post( $args['form']->options[ $opt . '_page_id' ] );
2076 $old_post = $post;
2077 $post = $page;
2078 $content = apply_filters( 'frm_content', $page->post_content, $args['form'], $args['entry_id'] );
2079 echo apply_filters( 'the_content', $content ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2080 $post = $old_post;
2081 }
2082 }
2083
2084 /**
2085 * @since 3.0
2086 */
2087 private static function redirect_after_submit( $args ) {
2088 global $frm_vars;
2089
2090 add_filter( 'frm_use_wpautop', '__return_false' );
2091
2092 $opt = $args['success_opt'];
2093 $success_url = trim( $args['form']->options[ $opt . '_url' ] );
2094 $success_url = apply_filters( 'frm_content', $success_url, $args['form'], $args['entry_id'] );
2095 $success_url = do_shortcode( $success_url );
2096
2097 $success_msg = isset( $args['form']->options[ $opt . '_msg' ] ) ? $args['form']->options[ $opt . '_msg' ] : __( 'Please wait while you are redirected.', 'formidable' );
2098
2099 $redirect_msg = self::get_redirect_message( $success_url, $success_msg, $args );
2100
2101 $args['id'] = $args['entry_id'];
2102 FrmEntriesController::delete_entry_before_redirect( $success_url, $args['form'], $args );
2103
2104 add_filter( 'frm_redirect_url', 'FrmEntriesController::prepare_redirect_url' );
2105 $success_url = apply_filters( 'frm_redirect_url', $success_url, $args['form'], $args );
2106
2107 $doing_ajax = FrmAppHelper::doing_ajax();
2108
2109 if ( isset( $args['ajax'] ) && $args['ajax'] && $doing_ajax ) {
2110 echo json_encode( array( 'redirect' => $success_url ) );
2111 wp_die();
2112 } elseif ( ! headers_sent() ) {
2113 wp_redirect( esc_url_raw( $success_url ) );
2114 die(); // do not use wp_die or redirect fails
2115 } else {
2116 add_filter( 'frm_use_wpautop', '__return_true' );
2117 echo FrmAppHelper::maybe_kses( $redirect_msg ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2118 echo "<script type='text/javascript'>window.onload = function(){setTimeout(window.location='" . esc_url_raw( $success_url ) . "', 8000);}</script>";
2119 }
2120 }
2121
2122 /**
2123 * @since 3.0
2124 *
2125 * @param string $success_url
2126 * @param string $success_msg
2127 * @param array $args
2128 */
2129 private static function get_redirect_message( $success_url, $success_msg, $args ) {
2130 $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/>' .
2131 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
2132 sprintf( __( '%1$sClick here%2$s if you are not automatically redirected.', 'formidable' ), '<a href="' . esc_url( $success_url ) . '">', '</a>' ) .
2133 '</div></div>';
2134
2135 $redirect_args = array(
2136 'entry_id' => $args['entry_id'],
2137 'form_id' => $args['form']->id,
2138 'form' => $args['form'],
2139 );
2140
2141 return apply_filters( 'frm_redirect_msg', $redirect_msg, $redirect_args );
2142 }
2143
2144 /**
2145 * Prepare to show the success message and empty form after submit
2146 *
2147 * @since 2.05
2148 */
2149 public static function show_message_after_save( $atts ) {
2150 $atts['message'] = self::prepare_submit_message( $atts['form'], $atts['entry_id'] );
2151
2152 if ( ! isset( $atts['form']->options['show_form'] ) || $atts['form']->options['show_form'] ) {
2153 self::show_form_after_submit( $atts );
2154 } else {
2155 self::show_lone_success_messsage( $atts );
2156 }
2157 }
2158
2159 /**
2160 * Show an empty form
2161 *
2162 * @since 2.05
2163 */
2164 private static function show_form_after_submit( $args ) {
2165 self::fill_atts_for_form_display( $args );
2166
2167 $errors = $args['errors'];
2168 $message = $args['message'];
2169 $form = $args['form'];
2170 $title = $args['title'];
2171 $description = $args['description'];
2172
2173 if ( empty( $args['fields'] ) ) {
2174 $values = array(
2175 'custom_style' => FrmAppHelper::custom_style_value( array() ),
2176 );
2177 } else {
2178 $values = FrmEntriesHelper::setup_new_vars( $args['fields'], $form, $args['reset'] );
2179 }
2180 unset( $args );
2181
2182 $include_form_tag = apply_filters( 'frm_include_form_tag', true, $form );
2183
2184 $frm_settings = FrmAppHelper::get_settings();
2185 $submit = isset( $form->options['submit_value'] ) ? $form->options['submit_value'] : $frm_settings->submit_value;
2186
2187 global $frm_vars;
2188 self::maybe_load_css( $form, $values['custom_style'], $frm_vars['load_css'] );
2189
2190 $message_placement = self::message_placement( $form, $message );
2191
2192 include FrmAppHelper::plugin_path() . '/classes/views/frm-entries/new.php';
2193 }
2194
2195 /**
2196 * @return string - 'before', 'after', or 'submit'
2197 *
2198 * @since 4.05.02
2199 */
2200 private static function message_placement( $form, $message ) {
2201 $place = 'before';
2202
2203 if ( $message && isset( $form->options['form_class'] ) ) {
2204 if ( strpos( $form->options['form_class'], 'frm_below_success' ) !== false ) {
2205 $place = 'after';
2206 } elseif ( strpos( $form->options['form_class'], 'frm_inline_success' ) !== false ) {
2207 $place = 'submit';
2208 }
2209 }
2210
2211 /**
2212 * @return string - 'before' or 'after'
2213 *
2214 * @since 4.05.02
2215 */
2216 return apply_filters( 'frm_message_placement', $place, compact( 'form', 'message' ) );
2217 }
2218
2219 /**
2220 * Get all the values needed on the new.php entry page
2221 *
2222 * @since 2.05
2223 */
2224 private static function fill_atts_for_form_display( &$args ) {
2225 $defaults = array(
2226 'errors' => array(),
2227 'message' => '',
2228 'fields' => array(),
2229 'form' => array(),
2230 'title' => true,
2231 'description' => false,
2232 'reset' => false,
2233 );
2234 $args = wp_parse_args( $args, $defaults );
2235 }
2236
2237 /**
2238 * Show the success message without the form
2239 *
2240 * @since 2.05
2241 */
2242 private static function show_lone_success_messsage( $atts ) {
2243 global $frm_vars;
2244 $values = FrmEntriesHelper::setup_new_vars( $atts['fields'], $atts['form'], true );
2245 self::maybe_load_css( $atts['form'], $values['custom_style'], $frm_vars['load_css'] );
2246
2247 $include_extra_container = 'frm_forms' . FrmFormsHelper::get_form_style_class( $values );
2248
2249 $errors = array();
2250 $form = $atts['form'];
2251 $message = $atts['message'];
2252
2253 include( FrmAppHelper::plugin_path() . '/classes/views/frm-entries/errors.php' );
2254 }
2255
2256 /**
2257 * Prepare the success message before it's shown
2258 *
2259 * @since 2.05
2260 */
2261 private static function prepare_submit_message( $form, $entry_id ) {
2262 $frm_settings = FrmAppHelper::get_settings( array( 'current_form' => $form->id ) );
2263
2264 if ( $entry_id && is_numeric( $entry_id ) ) {
2265 $message = isset( $form->options['success_msg'] ) ? $form->options['success_msg'] : $frm_settings->success_msg;
2266 $class = 'frm_message';
2267 } else {
2268 $message = $frm_settings->failed_msg;
2269 $class = FrmFormsHelper::form_error_class();
2270 }
2271
2272 $message = FrmFormsHelper::get_success_message( compact( 'message', 'form', 'entry_id', 'class' ) );
2273
2274 return apply_filters( 'frm_main_feedback', $message, $form, $entry_id );
2275 }
2276
2277 public static function front_head() {
2278 $version = FrmAppHelper::plugin_version();
2279 $suffix = FrmAppHelper::js_suffix();
2280
2281 if ( ! empty( $suffix ) && self::has_combo_js_file() ) {
2282 wp_register_script( 'formidable', FrmAppHelper::plugin_url() . '/js/frm.min.js', array( 'jquery' ), $version, true );
2283 } else {
2284 wp_register_script( 'formidable', FrmAppHelper::plugin_url() . "/js/formidable{$suffix}.js", array( 'jquery' ), $version, true );
2285 }
2286
2287 add_filter( 'script_loader_tag', 'FrmFormsController::defer_script_loading', 10, 2 );
2288
2289 if ( FrmAppHelper::is_admin() ) {
2290 // don't load this in back-end
2291 return;
2292 }
2293
2294 FrmAppHelper::localize_script( 'front' );
2295 FrmStylesController::enqueue_css( 'register' );
2296 }
2297
2298 /**
2299 * @since 3.0
2300 */
2301 public static function has_combo_js_file() {
2302 return is_readable( FrmAppHelper::plugin_path() . '/js/frm.min.js' );
2303 }
2304
2305 public static function maybe_load_css( $form, $this_load, $global_load ) {
2306 $load_css = FrmForm::is_form_loaded( $form, $this_load, $global_load );
2307
2308 if ( ! $load_css ) {
2309 return;
2310 }
2311
2312 global $frm_vars;
2313 self::footer_js( 'header' );
2314 $frm_vars['css_loaded'] = true;
2315
2316 self::load_late_css();
2317 }
2318
2319 /**
2320 * If css is loaded only on applicable pages, include it before the form loads
2321 * to prevent a flash of unstyled form.
2322 *
2323 * @since 4.01
2324 *
2325 * @return void
2326 */
2327 private static function load_late_css() {
2328 $frm_settings = FrmAppHelper::get_settings();
2329 $late_css = $frm_settings->load_style === 'dynamic';
2330
2331 if ( ! $late_css || ! self::should_load_late() ) {
2332 return;
2333 }
2334
2335 global $wp_styles;
2336 if ( is_array( $wp_styles->queue ) && in_array( 'formidable', $wp_styles->queue, true ) ) {
2337 wp_print_styles( 'formidable' );
2338 }
2339 }
2340
2341 /**
2342 * Avoid late load if All in One SEO is active because it prevents CSS from loading entirely.
2343 *
2344 * @since 5.2.03
2345 *
2346 * @return bool
2347 */
2348 private static function should_load_late() {
2349 return ! function_exists( 'aioseo' );
2350 }
2351
2352 public static function defer_script_loading( $tag, $handle ) {
2353 if ( 'recaptcha-api' == $handle && ! strpos( $tag, 'defer' ) ) {
2354 $tag = str_replace( ' src', ' defer="defer" async="async" src', $tag );
2355 }
2356
2357 return $tag;
2358 }
2359
2360 public static function footer_js( $location = 'footer' ) {
2361 global $frm_vars;
2362
2363 FrmStylesController::enqueue_css();
2364
2365 if ( ! FrmAppHelper::is_admin() && $location != 'header' && ! empty( $frm_vars['forms_loaded'] ) ) {
2366 // load formidable js
2367 wp_enqueue_script( 'formidable' );
2368 }
2369 }
2370
2371 /**
2372 * @since 2.0.8
2373 */
2374 private static function maybe_minimize_form( $atts, &$content ) {
2375 // check if minimizing is turned on
2376 if ( self::is_minification_on( $atts ) ) {
2377 $content = str_replace( array( "\r\n", "\r", "\n", "\t", ' ' ), '', $content );
2378 }
2379 }
2380
2381 /**
2382 * @since 2.0.8
2383 * @return boolean
2384 */
2385 private static function is_minification_on( $atts ) {
2386 return isset( $atts['minimize'] ) && ! empty( $atts['minimize'] );
2387 }
2388
2389 /**
2390 * @since 5.0.16
2391 *
2392 * @return void
2393 */
2394 public static function landing_page_preview_option() {
2395 $dir = apply_filters( 'frm_landing_page_preview_option', false );
2396 if ( false === $dir || ! file_exists( $dir . 'landing-page-preview-option.php' ) ) {
2397 $dir = self::get_form_views_path();
2398 }
2399 include $dir . 'landing-page-preview-option.php';
2400 }
2401
2402 /**
2403 * @since 5.0.16
2404 *
2405 * @return string
2406 */
2407 private static function get_form_views_path() {
2408 return FrmAppHelper::plugin_path() . '/classes/views/frm-forms/';
2409 }
2410
2411 /**
2412 * Create a page with an embedded formidable Gutenberg block.
2413 *
2414 * @since 5.2
2415 *
2416 * @return never
2417 */
2418 public static function create_page_with_shortcode() {
2419 if ( ! current_user_can( 'publish_posts' ) ) {
2420 die( 0 );
2421 }
2422
2423 check_ajax_referer( 'frm_ajax', 'nonce' );
2424
2425 $type = FrmAppHelper::get_post_param( 'type', '', 'sanitize_text_field' );
2426 if ( ! $type || ! in_array( $type, array( 'form', 'view' ), true ) ) {
2427 die( 0 );
2428 }
2429
2430 $object_id = FrmAppHelper::get_post_param( 'object_id', '', 'absint' );
2431 if ( ! $object_id ) {
2432 die( 0 );
2433 }
2434
2435 $postarr = array( 'post_type' => 'page' );
2436
2437 if ( 'form' === $type ) {
2438 $postarr['post_content'] = self::get_page_shortcode_content_for_form( $object_id );
2439 } else {
2440 $postarr['post_content'] = apply_filters( 'frm_create_page_with_' . $type . '_shortcode_content', '', $object_id );
2441 }
2442
2443 $name = FrmAppHelper::get_post_param( 'name', '', 'sanitize_text_field' );
2444 if ( $name ) {
2445 $postarr['post_title'] = $name;
2446 }
2447
2448 $success = wp_insert_post( $postarr );
2449 if ( ! is_numeric( $success ) || ! $success ) {
2450 die( 0 );
2451 }
2452
2453 wp_send_json(
2454 array(
2455 'redirect' => get_edit_post_link( $success, 'redirect' ),
2456 )
2457 );
2458 }
2459
2460 /**
2461 * @since 5.3
2462 *
2463 * @param string $content
2464 * @param int $form_id
2465 * @return string
2466 */
2467 private static function get_page_shortcode_content_for_form( $form_id ) {
2468 $shortcode = '[formidable id="' . $form_id . '"]';
2469 $html_comment_start = '<!-- wp:formidable/simple-form {"formId":"' . $form_id . '"} -->';
2470 $html_comment_end = '<!-- /wp:formidable/simple-form -->';
2471 return $html_comment_start . '<div>' . $shortcode . '</div>' . $html_comment_end;
2472 }
2473
2474 /**
2475 * Get page dropdown for AJAX request for embedding form in an existing page.
2476 *
2477 * @return never
2478 */
2479 public static function get_page_dropdown() {
2480 if ( ! current_user_can( 'publish_posts' ) ) {
2481 die( 0 );
2482 }
2483
2484 check_ajax_referer( 'frm_ajax', 'nonce' );
2485
2486 $html = FrmAppHelper::clip(
2487 function() {
2488 FrmAppHelper::maybe_autocomplete_pages_options(
2489 array(
2490 'field_name' => 'frm_page_dropdown',
2491 'page_id' => '',
2492 'placeholder' => __( 'Select a Page', 'formidable' ),
2493 )
2494 );
2495 }
2496 );
2497 $post_type_object = get_post_type_object( 'page' );
2498 wp_send_json(
2499 array(
2500 'html' => $html,
2501 'edit_page_url' => admin_url( sprintf( $post_type_object->_edit_link . '&action=edit', 0 ) ),
2502 )
2503 );
2504 }
2505
2506 /**
2507 * @deprecated 4.0
2508 */
2509 public static function new_form( $values = array() ) {
2510 FrmDeprecated::new_form( $values );
2511 }
2512
2513 /**
2514 * @deprecated 4.0
2515 */
2516 public static function create( $values = array() ) {
2517 _deprecated_function( __METHOD__, '4.0', 'FrmFormsController::update' );
2518 self::update( $values );
2519 }
2520
2521 /**
2522 * @deprecated 1.07.05
2523 * @codeCoverageIgnore
2524 */
2525 public static function add_default_templates( $path, $default = true, $template = true ) {
2526 FrmDeprecated::add_default_templates( $path, $default, $template );
2527 }
2528
2529 /**
2530 * @deprecated 3.0
2531 * @codeCoverageIgnore
2532 */
2533 public static function bulk_create_template( $ids ) {
2534 return FrmDeprecated::bulk_create_template( $ids );
2535 }
2536
2537 /**
2538 * @deprecated 2.03
2539 * @codeCoverageIgnore
2540 */
2541 public static function register_pro_scripts() {
2542 FrmDeprecated::register_pro_scripts();
2543 }
2544
2545 /**
2546 * @deprecated 3.0
2547 * @codeCoverageIgnore
2548 */
2549 public static function edit_key() {
2550 FrmDeprecated::edit_key();
2551 }
2552
2553 /**
2554 * @deprecated 3.0
2555 * @codeCoverageIgnore
2556 */
2557 public static function edit_description() {
2558 FrmDeprecated::edit_description();
2559 }
2560
2561 /**
2562 * @deprecated 4.08
2563 * @since 3.06
2564 */
2565 public static function add_new() {
2566 _deprecated_function( __FUNCTION__, '4.08' );
2567 }
2568 }
2569