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

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

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