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

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