PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.3
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.3
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / controllers / FrmFormsController.php

FrmFormsController.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 5.3, at classes/controllers/FrmFormsController.php

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