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

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