PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.7.2
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.7.2
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/controllers/FrmFormsController.php +355 -214 6.36.7.2 View file →
@@ -4,8 +4,18 @@
4 4 }
5 5
6 6 class FrmFormsController {
7 7
8 + /**
9 + * Track the form that opened the redirect URL in a new tab. This is used to check if we should show the default
10 + * message in the currect tab.
11 + *
12 + * @since 6.2
13 + *
14 + * @var array Keys are form IDs and values are 1.
15 + */
16 + private static $redirected_in_new_tab = array();
17 +
8 18 public static function menu() {
9 19 $menu_label = __( 'Forms', 'formidable' );
10 20 if ( ! FrmAppHelper::pro_is_installed() ) {
11 21 $menu_label .= ' (Lite)';
@@ -219,9 +229,9 @@
219 229 wp_die( FrmAppHelper::kses( $message, array( 'a' ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
220 230 }
221 231
222 232 return self::get_edit_vars( $id, array(), $message );
223 - }
233 + }//end if
224 234 }
225 235
226 236 /**
227 237 * Check if the value at the end of the form was included.
@@ -272,9 +282,10 @@
272 282 $url = admin_url( 'admin.php?page=formidable' );
273 283 $message = 'form_duplicate_error';
274 284
275 285 if ( $form ) {
276 - $url = admin_url( 'admin.php?page=formidable&frm_action=edit&id=' . absint( $form ) );
286 + $new_template = FrmAppHelper::simple_get( 'new_template' ) ? '&new_template=true' : '';
287 + $url = admin_url( 'admin.php?page=formidable&frm_action=edit&id=' . absint( $form ) . $new_template );
277 288 $message = 'form_duplicated';
278 289 }
279 290
280 291 $url .= '&message=' . $message;
@@ -299,8 +310,10 @@
299 310 }
300 311
301 312 /**
302 313 * @since 3.0
314 + *
315 + * @return void
303 316 */
304 317 public static function show_page_preview() {
305 318 echo self::page_preview(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
306 319 }
@@ -350,8 +363,13 @@
350 363 return;
351 364 }
352 365
353 366 $random_page = reset( $random_page );
367 + if ( ! is_a( $random_page, 'WP_Post' ) ) {
368 + // The return type can also be int.
369 + return;
370 + }
371 +
354 372 query_posts(
355 373 array(
356 374 'post_type' => 'page',
357 375 'page_id' => $random_page->ID,
@@ -367,9 +385,9 @@
367 385 * Set the WP $post global object. Used for in-theme preview when defining a page.
368 386 *
369 387 * @since 5.5.2
370 388 *
371 - * @param WP_Post $post
389 + * @param WP_Post $page The page object.
372 390 * @return void
373 391 */
374 392 private static function set_post_global( $page ) {
375 393 global $post;
@@ -387,13 +405,29 @@
387 405 add_filter( 'is_active_sidebar', '__return_false' );
388 406 FrmStylesController::enqueue_css( 'enqueue', true );
389 407
390 408 if ( false === get_template_part( 'page' ) ) {
409 + if ( function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) {
410 + add_filter( 'body_class', 'FrmFormsController::preview_block_theme_body_classnames' );
411 + }
391 412 self::fallback_when_page_template_part_is_not_supported_by_theme();
392 413 }
393 414 }
394 415
395 416 /**
417 + * Add padding to the body for block themes.
418 + *
419 + * @since 6.5.2
420 + *
421 + * @param array $classes The body classes list.
422 + * @return array
423 + */
424 + public static function preview_block_theme_body_classnames( $classes ) {
425 + $classes[] = 'has-global-padding';
426 + return $classes;
427 + }
428 +
429 + /**
396 430 * Not every theme supports get_template_part( 'page' ).
397 431 * When this is not supported, false is returned, and we can handle a fallback.
398 432 */
399 433 private static function fallback_when_page_template_part_is_not_supported_by_theme() {
@@ -398,9 +432,10 @@
398 432 */
399 433 private static function fallback_when_page_template_part_is_not_supported_by_theme() {
400 434 if ( have_posts() ) {
401 435 the_post();
402 - get_header( '' );
436 + self::get_template( 'header' );
437 +
403 438 // add some generic class names to the container to add some natural padding to the content.
404 439 // .entry-content catches the WordPress TwentyTwenty theme.
405 440 // .container catches Customizr content.
406 441 echo '<div class="container entry-content">';
@@ -405,13 +440,54 @@
405 440 // .container catches Customizr content.
406 441 echo '<div class="container entry-content">';
407 442 the_content();
408 443 echo '</div>';
409 - get_footer();
444 +
445 + self::get_template( 'footer' );
410 446 }
411 447 }
412 448
413 449 /**
450 + * Calls core function to get a template part if it doesn't cause deprecation warnings. Otherwise skips the deprecation function call
451 + * and renders required html fragements calling required functions.
452 + *
453 + * @since 6.7.1
454 + * @param string $template
455 + * @return void
456 + */
457 + private static function get_template( $template ) {
458 + if ( self::should_try_getting_template( $template ) ) {
459 + call_user_func( 'get_' . $template );
460 + return;
461 + }
462 +
463 + if ( 'header' === $template ) {
464 + include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/preview/header.php';
465 + return;
466 + }
467 +
468 + if ( 'footer' === $template ) {
469 + include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/preview/footer.php';
470 + }
471 + }
472 +
473 + /**
474 + * Returns true if calling a template function doesn't trigger deprecation warnings.
475 + *
476 + * @since 6.7.1
477 + * @param string $template
478 + * @return bool
479 + */
480 + private static function should_try_getting_template( $template ) {
481 + $stylesheet_path = get_stylesheet_directory();
482 + $template_path = get_template_directory();
483 + $is_child_theme = $stylesheet_path !== $template_path;
484 + $template_name = $template . '.php';
485 +
486 + return file_exists( $stylesheet_path . '/' . $template_name ) || $is_child_theme && file_exists( $template_path . '/' . $template_name );
487 + }
488 +
489 + /**
414 490 * Set the page title for the theme preview page
415 491 *
416 492 * @since 3.0
417 493 */
@@ -432,15 +508,20 @@
432 508 return __( 'Form Preview', 'formidable' );
433 509 }
434 510
435 511 /**
436 - * Set the page content for the theme preview page
512 + * Set the page content for the theme preview page.
437 513 *
438 514 * @since 3.0
515 + *
516 + * @param string $content
517 + * @return string
439 518 */
440 519 public static function preview_content( $content ) {
441 520 if ( in_the_loop() ) {
442 - $content = self::show_page_preview();
521 + self::show_page_preview();
522 + // Clear the content for the page we're using.
523 + $content = '';
443 524 }
444 525
445 526 return $content;
446 527 }
@@ -527,9 +608,9 @@
527 608 FrmAppHelper::permission_check( $available_status[ $status ]['permission'] );
528 609
529 610 $params = FrmForm::list_page_params();
530 611
531 - //check nonce url
612 + // Check nonce url.
532 613 check_admin_referer( $status . '_form_' . $params['id'] );
533 614
534 615 $count = 0;
535 616 if ( FrmForm::set_status( $params['id'], $available_status[ $status ]['new_status'] ) ) {
@@ -610,15 +691,20 @@
610 691 $count ++;
611 692 }
612 693 }
613 694
614 - /* translators: %1$s: Number of forms */
615 - $message = sprintf( _n( '%1$s form permanently deleted.', '%1$s forms permanently deleted.', $count, 'formidable' ), $count );
695 + if ( $count ) {
696 + /* translators: %1$s: Number of forms */
697 + return sprintf( _n( '%1$s form permanently deleted.', '%1$s forms permanently deleted.', $count, 'formidable' ), $count );
698 + }
616 699
617 - return $message;
700 + return '';
618 701 }
619 702
620 - private static function delete_all() {
703 + /**
704 + * @since 6.7.1 Function went from private to public.
705 + */
706 + public static function delete_all() {
621 707 // Check nonce url.
622 708 $permission_error = FrmAppHelper::permission_nonce_error( 'frm_delete_forms', '_wpnonce', 'bulk-toplevel_page_formidable' );
623 709 if ( $permission_error !== false ) {
624 710 self::display_forms_list( array(), '', array( $permission_error ) );
@@ -625,14 +711,15 @@
625 711
626 712 return;
627 713 }
628 714
629 - $count = FrmForm::scheduled_delete( time() );
715 + $count = FrmForm::scheduled_delete( time() );
716 + $url = remove_query_arg( array( 'delete_all' ) );
630 717
631 - /* translators: %1$s: Number of forms */
632 - $message = sprintf( _n( '%1$s form permanently deleted.', '%1$s forms permanently deleted.', $count, 'formidable' ), $count );
718 + $url .= '&message=forms_permanently_deleted&forms_deleted=' . $count;
633 719
634 - self::display_forms_list( array(), $message );
720 + wp_safe_redirect( $url );
721 + die();
635 722 }
636 723
637 724 /**
638 725 * Create a new form from the modal.
@@ -670,9 +757,9 @@
670 757 self::create_default_on_submit_action( $form_id );
671 758 self::create_default_email_action( $form_id );
672 759
673 760 $response = array(
674 - 'redirect' => FrmForm::get_edit_link( $form_id ),
761 + 'redirect' => FrmForm::get_edit_link( $form_id ) . '&new_template=true',
675 762 );
676 763
677 764 echo wp_json_encode( $response );
678 765 wp_die();
@@ -678,46 +765,13 @@
678 765 wp_die();
679 766 }
680 767
681 768 /**
682 - * Create a custom template from a form
683 - *
684 - * @since 3.06
685 - */
686 - public static function build_template() {
687 - global $wpdb;
688 -
689 - FrmAppHelper::permission_check( 'frm_edit_forms' );
690 - check_ajax_referer( 'frm_ajax', 'nonce' );
691 -
692 - $form_id = FrmAppHelper::get_param( 'xml', '', 'post', 'absint' );
693 - $new_form_id = FrmForm::duplicate( $form_id, 1, true );
694 - if ( ! $new_form_id ) {
695 - $response = array(
696 - 'message' => __( 'There was an error creating a template.', 'formidable' ),
697 - );
698 - } else {
699 - $new_values = self::get_modal_values();
700 - $query_results = $wpdb->update( $wpdb->prefix . 'frm_forms', $new_values, array( 'id' => $new_form_id ) );
701 - if ( $query_results ) {
702 - FrmForm::clear_form_cache();
703 - }
704 -
705 - $response = array(
706 - 'redirect' => admin_url( 'admin.php?page=formidable&frm_action=duplicate&id=' . $new_form_id ) . '&_wpnonce=' . wp_create_nonce(),
707 - );
708 - }
709 -
710 - echo wp_json_encode( $response );
711 - wp_die();
712 - }
713 -
714 - /**
715 769 * Before creating a new form, get the name and description from the modal.
716 770 *
717 771 * @since 4.0
718 772 */
719 - private static function get_modal_values() {
773 + public static function get_modal_values() {
720 774 $name = FrmAppHelper::get_param( 'name', '', 'post', 'sanitize_text_field' );
721 775 $desc = FrmAppHelper::get_param( 'desc', '', 'post', 'sanitize_textarea_field' );
722 776
723 777 return array(
@@ -879,14 +933,14 @@
879 933 * @return array<string,string>
880 934 */
881 935 public static function get_columns( $columns ) {
882 936 $columns['cb'] = '<input type="checkbox" />';
883 - $columns['name'] = __( 'Form Title', 'formidable' );
884 - $columns['entries'] = __( 'Entries', 'formidable' );
937 + $columns['name'] = esc_html__( 'Form Title', 'formidable' );
938 + $columns['entries'] = esc_html__( 'Entries', 'formidable' );
885 939 $columns['id'] = 'ID';
886 - $columns['form_key'] = __( 'Key', 'formidable' );
887 - $columns['shortcode'] = __( 'Actions', 'formidable' );
888 - $columns['created_at'] = __( 'Date', 'formidable' );
940 + $columns['form_key'] = esc_html__( 'Key', 'formidable' );
941 + $columns['shortcode'] = esc_html__( 'Actions', 'formidable' );
942 + $columns['created_at'] = esc_html__( 'Date', 'formidable' );
889 943
890 944 add_screen_option(
891 945 'per_page',
892 946 array(
@@ -940,147 +994,43 @@
940 994
941 995 return $save;
942 996 }
943 997
944 - /**
945 - * @return bool
946 - */
947 - public static function expired() {
948 - global $frm_expired;
949 - return $frm_expired;
950 - }
998 + private static function get_edit_vars( $id, $errors = array(), $message = '', $create_link = false ) {
999 + global $frm_vars;
951 1000
952 - /**
953 - * Get data from api before rendering it so that we can flag the modal as expired
954 - *
955 - * @return void
956 - */
957 - public static function before_list_templates() {
958 - global $frm_templates;
959 - global $frm_expired;
960 - global $frm_license_type;
961 -
962 - $api = new FrmFormTemplateApi();
963 - $frm_templates = $api->get_api_info();
964 - $expired = false;
965 - $license_type = '';
966 - if ( isset( $frm_templates['error'] ) ) {
967 - $error = $frm_templates['error']['message'];
968 - $error = str_replace( 'utm_medium=addons', 'utm_medium=form-templates', $error );
969 - $expired = 'expired' === $frm_templates['error']['code'];
970 - $license_type = isset( $frm_templates['error']['type'] ) ? $frm_templates['error']['type'] : '';
971 - unset( $frm_templates['error'] );
972 - }
973 -
974 - $frm_expired = $expired;
975 - $frm_license_type = $license_type;
976 - }
977 -
978 - /**
979 - * @return void
980 - */
981 - public static function list_templates() {
982 - global $frm_templates;
983 - global $frm_license_type;
984 -
985 - $templates = $frm_templates;
986 - $custom_templates = array();
987 - $templates_by_category = array();
988 -
989 - self::add_user_templates( $custom_templates );
990 -
991 - foreach ( $templates as $template ) {
992 - if ( ! isset( $template['categories'] ) ) {
993 - continue;
994 - }
995 -
996 - foreach ( $template['categories'] as $category ) {
997 - if ( ! isset( $templates_by_category[ $category ] ) ) {
998 - $templates_by_category[ $category ] = array();
999 - }
1000 -
1001 - $templates_by_category[ $category ][] = $template;
1002 - }
1003 - }
1004 - unset( $template );
1005 -
1006 - // Subcategories that are included elsewhere.
1007 - $redundant_cats = array( 'PayPal', 'Stripe', 'Twilio' );
1008 -
1009 - $categories = array_keys( $templates_by_category );
1010 - $categories = array_diff( $categories, FrmFormsHelper::ignore_template_categories() );
1011 - $categories = array_diff( $categories, $redundant_cats );
1012 - sort( $categories );
1013 -
1014 - array_walk(
1015 - $custom_templates,
1016 - function( &$template ) {
1017 - $template['custom'] = true;
1018 - }
1001 + $form = FrmForm::getOne( $id );
1002 + $error_args = array(
1003 + 'title' => __( 'You can\'t edit the form', 'formidable' ),
1004 + 'body' => __( 'You are trying to edit a form that does not exist', 'formidable' ),
1005 + 'cancel_url' => admin_url( 'admin.php?page=formidable' ),
1006 + 'continue_url' => add_query_arg(
1007 + array(
1008 + 'page' => 'formidable',
1009 + )
1010 + ),
1019 1011 );
1020 -
1021 - $my_templates_translation = __( 'My Templates', 'formidable' );
1022 - $categories = array_merge( array( $my_templates_translation ), $categories );
1023 - $pricing = FrmAppHelper::admin_upgrade_link( 'form-templates' );
1024 - $license_type = $frm_license_type;
1025 - $args = compact( 'pricing', 'license_type' );
1026 - $where = apply_filters( 'frm_forms_dropdown', array(), '' );
1027 - $forms = FrmForm::get_published_forms( $where );
1028 - $view_path = FrmAppHelper::plugin_path() . '/classes/views/frm-forms/';
1029 -
1030 - $templates_by_category[ $my_templates_translation ] = $custom_templates;
1031 -
1032 - unset( $pricing, $license_type, $where );
1033 - wp_enqueue_script( 'accordion' ); // register accordion for template groups
1034 - require $view_path . 'list-templates.php';
1035 - }
1036 -
1037 - /**
1038 - * @since 4.03.01
1039 - */
1040 - private static function get_template_categories( $templates ) {
1041 - $categories = array();
1042 - foreach ( $templates as $template ) {
1043 - if ( isset( $template['categories'] ) ) {
1044 - $categories = array_merge( $categories, $template['categories'] );
1045 - }
1012 + if ( ! $form ) {
1013 + FrmAppController::show_error_modal( $error_args );
1014 + return;
1046 1015 }
1047 - $exclude_cats = FrmFormsHelper::ignore_template_categories();
1048 - $categories = array_unique( $categories );
1049 - $categories = array_diff( $categories, $exclude_cats );
1050 - sort( $categories );
1051 - return $categories;
1052 - }
1053 1016
1054 - private static function add_user_templates( &$templates ) {
1055 - $user_templates = array(
1056 - 'is_template' => 1,
1057 - 'default_template' => 0,
1058 - );
1059 - $user_templates = FrmForm::getAll( $user_templates, 'name' );
1060 - foreach ( $user_templates as $template ) {
1061 - $template = array(
1062 - 'id' => $template->id,
1063 - 'name' => $template->name,
1064 - 'key' => $template->form_key,
1065 - 'description' => $template->description,
1066 - 'url' => wp_nonce_url( admin_url( 'admin.php?page=formidable&frm_action=duplicate&id=' . absint( $template->id ) ) ),
1067 - 'released' => $template->created_at,
1068 - 'installed' => 1,
1017 + if ( 'trash' === $form->status ) {
1018 + $error_args['body'] = __( 'The form you\'re trying to edit is in trash. You must restore it first before you can make changes', 'formidable' );
1019 + $error_args['continue_url'] = add_query_arg(
1020 + array(
1021 + 'page' => 'formidable',
1022 + '_wpnonce' => wp_create_nonce( 'untrash_form_' . $id ),
1023 + 'form_type' => 'trash',
1024 + 'frm_action' => 'untrash',
1025 + 'id' => $id,
1026 + )
1069 1027 );
1070 - array_unshift( $templates, $template );
1071 - unset( $template );
1028 + $error_args['continue_text'] = __( 'Restore form', 'formidable' );
1029 + FrmAppController::show_error_modal( $error_args );
1030 + return;
1072 1031 }
1073 - }
1074 1032
1075 - private static function get_edit_vars( $id, $errors = array(), $message = '', $create_link = false ) {
1076 - global $frm_vars;
1077 -
1078 - $form = FrmForm::getOne( $id );
1079 - if ( ! $form ) {
1080 - wp_die( esc_html__( 'You are trying to edit a form that does not exist.', 'formidable' ) );
1081 - }
1082 -
1083 1033 if ( $form->parent_form_id ) {
1084 1034 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
1085 1035 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>' ) );
1086 1036 }
@@ -1259,8 +1209,21 @@
1259 1209 'screenshot' => 'chat.png',
1260 1210 )
1261 1211 ),
1262 1212 ),
1213 + 'abandonment' => array(
1214 + 'name' => __( 'Form Abandonment', 'formidable' ),
1215 + 'icon' => 'frm_icon_font frm_abandoned_icon',
1216 + 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1217 + 'data' => FrmAppHelper::get_upgrade_data_params(
1218 + 'abandonment',
1219 + array(
1220 + 'upgrade' => __( 'Form abandonment settings', 'formidable' ),
1221 + 'message' => __( 'Unlock the power of data capture to boost lead generation and master the art of form optimization.', 'formidable' ),
1222 + 'screenshot' => 'abandonment.png',
1223 + )
1224 + ),
1225 + ),
1263 1226 'html' => array(
1264 1227 'name' => __( 'Customize HTML', 'formidable' ),
1265 1228 'class' => __CLASS__,
1266 1229 'function' => 'html_settings',
@@ -1267,9 +1230,9 @@
1267 1230 'icon' => 'frm_icon_font frm_code_icon',
1268 1231 ),
1269 1232 );
1270 1233
1271 - foreach ( array( 'landing', 'chat' ) as $feature ) {
1234 + foreach ( array( 'landing', 'chat', 'abandonment' ) as $feature ) {
1272 1235 if ( ! FrmAppHelper::show_new_feature( $feature ) ) {
1273 1236 unset( $sections[ $feature ] );
1274 1237 }
1275 1238 }
@@ -1303,9 +1266,9 @@
1303 1266 $section['id'] = $section['anchor'];
1304 1267 }
1305 1268
1306 1269 $sections[ $key ] = $section;
1307 - }
1270 + }//end foreach
1308 1271
1309 1272 return $sections;
1310 1273 }
1311 1274
@@ -1605,13 +1568,17 @@
1605 1568 * Replace any [form_name] shortcodes in a string.
1606 1569 *
1607 1570 * @since 5.5
1608 1571 *
1609 - * @param string $string
1572 + * @param string|array $string
1610 1573 * @param stdClass|string|int $form
1611 - * @return string
1574 + * @return string|array
1612 1575 */
1613 1576 public static function replace_form_name_shortcodes( $string, $form ) {
1577 + if ( ! is_string( $string ) ) {
1578 + return $string;
1579 + }
1580 +
1614 1581 if ( false === strpos( $string, '[form_name]' ) ) {
1615 1582 return $string;
1616 1583 }
1617 1584
@@ -1725,9 +1692,9 @@
1725 1692 if ( isset( $_REQUEST['delete_all'] ) ) {
1726 1693 // Override the action for this page.
1727 1694 $action = 'delete_all';
1728 1695 }
1729 - }
1696 + }//end if
1730 1697
1731 1698 add_action( 'frm_load_form_hooks', 'FrmHooksController::trigger_load_form_hooks' );
1732 1699 FrmAppHelper::trigger_hook_load( 'form' );
1733 1700
@@ -1739,9 +1706,8 @@
1739 1706 case 'update':
1740 1707 case 'trash':
1741 1708 case 'untrash':
1742 1709 case 'destroy':
1743 - case 'delete_all':
1744 1710 case 'settings':
1745 1711 case 'update_settings':
1746 1712 return self::$action( $vars );
1747 1713 case 'lite-reports':
@@ -1771,14 +1737,47 @@
1771 1737 self::display_forms_list( array(), '', array( __( 'There was a problem duplicating the form', 'formidable' ) ) );
1772 1738 return;
1773 1739 }
1774 1740
1741 + if ( 'forms_permanently_deleted' === $message ) {
1742 + $count = FrmAppHelper::get_param( 'forms_deleted', 0, 'get', 'absint' );
1743 + /* translators: %1$s: Number of forms */
1744 + $message = sprintf( _n( '%1$s form permanently deleted.', '%1$s forms permanently deleted.', $count, 'formidable' ), $count );
1745 + self::display_forms_list( array(), $message, '' );
1746 + return;
1747 + }
1748 +
1775 1749 self::display_forms_list();
1776 1750
1777 1751 return;
1778 - }
1752 + }//end switch
1779 1753 }
1780 1754
1755 + /**
1756 + * Rename a form.
1757 + *
1758 + * Handles the AJAX request for renaming a form.
1759 + *
1760 + * @since 6.7
1761 + *
1762 + * @return void
1763 + */
1764 + public static function rename_form() {
1765 + // Check permission and nonce
1766 + FrmAppHelper::permission_check( 'frm_edit_forms' );
1767 + check_ajax_referer( 'frm_ajax', 'nonce' );
1768 +
1769 + // Get posted data
1770 + $form_id = FrmAppHelper::get_post_param( 'form_id', '', 'absint' );
1771 + $name = FrmAppHelper::get_post_param( 'form_name', '', 'sanitize_text_field' );
1772 +
1773 + // Update the form name and form key.
1774 + $form_key = FrmAppHelper::get_unique_key( sanitize_title( $name ), 'frm_forms', 'form_key' );
1775 + FrmForm::update( $form_id, compact( 'name', 'form_key' ) );
1776 +
1777 + wp_send_json_success( compact( 'form_key' ) );
1778 + }
1779 +
1781 1780 public static function json_error( $errors ) {
1782 1781 $errors['json'] = __( 'Abnormal HTML characters prevented your form from saving correctly', 'formidable' );
1783 1782
1784 1783 return $errors;
@@ -1817,9 +1816,11 @@
1817 1816
1818 1817 include FrmAppHelper::plugin_path() . '/classes/views/shared/reports-info.php';
1819 1818 }
1820 1819
1821 - /* FRONT-END FORMS */
1820 + /**
1821 + * FRONT-END FORMS.
1822 + */
1822 1823 public static function admin_bar_css() {
1823 1824 if ( is_admin() || ! current_user_can( 'frm_edit_forms' ) ) {
1824 1825 return;
1825 1826 }
@@ -2007,9 +2008,10 @@
2007 2008 */
2008 2009 private static function maybe_get_form_to_show( $id ) {
2009 2010 $form = false;
2010 2011
2011 - if ( ! empty( $id ) ) { // form id or key is set
2012 + if ( ! empty( $id ) ) {
2013 + // Form id or key is set.
2012 2014 $form = FrmForm::getOne( $id );
2013 2015 if ( ! $form || $form->parent_form_id || $form->status === 'trash' ) {
2014 2016 $form = false;
2015 2017 }
@@ -2081,9 +2083,9 @@
2081 2083 'form' => $form,
2082 2084 )
2083 2085 );
2084 2086 }
2085 - }
2087 + }//end if
2086 2088 }
2087 2089
2088 2090 /**
2089 2091 * If the form was processed earlier (init), get the generated errors
@@ -2261,8 +2263,13 @@
2261 2263 if ( ! FrmOnSubmitHelper::form_has_migrated( $args['form'] ) ) {
2262 2264 return array();
2263 2265 }
2264 2266
2267 + // If a redirect action has already opened the URL in a new tab, we show the default message in the currect tab.
2268 + if ( ! empty( self::$redirected_in_new_tab[ $args['form']->id ] ) ) {
2269 + return array( FrmOnSubmitHelper::get_fallback_action_after_open_in_new_tab( $event ) );
2270 + }
2271 +
2265 2272 $entry = FrmEntry::getOne( $args['entry_id'], true );
2266 2273 $actions = FrmOnSubmitHelper::get_actions( $args['form']->id );
2267 2274 $met_actions = array();
2268 2275 $has_redirect = false;
@@ -2278,9 +2285,10 @@
2278 2285
2279 2286 $action_type = FrmOnSubmitHelper::get_action_type( $action );
2280 2287
2281 2288 if ( 'redirect' === $action_type ) {
2282 - if ( $has_redirect ) { // Do not process because we run the first redirect action only.
2289 + if ( $has_redirect ) {
2290 + // Do not process because we run the first redirect action only.
2283 2291 continue;
2284 2292 }
2285 2293 }
2286 2294
@@ -2293,9 +2301,9 @@
2293 2301 }
2294 2302
2295 2303 $met_actions[] = $action;
2296 2304 unset( $action );
2297 - }
2305 + }//end foreach
2298 2306
2299 2307 $args['event'] = $event;
2300 2308
2301 2309 /**
@@ -2484,9 +2492,9 @@
2484 2492 add_filter( 'the_content', 'FrmFormsController::preview_content', 9999 );
2485 2493 }
2486 2494
2487 2495 $post = $old_post;
2488 - }
2496 + }//end if
2489 2497 }
2490 2498
2491 2499 /**
2492 2500 * @since 3.0
@@ -2507,16 +2515,25 @@
2507 2515 $success_url = apply_filters( 'frm_redirect_url', $success_url, $args['form'], $args );
2508 2516
2509 2517 $doing_ajax = FrmAppHelper::doing_ajax();
2510 2518
2511 - if ( ! empty( $args['ajax'] ) && $doing_ajax && empty( $args['force_delay_redirect'] ) ) { // Is AJAX submit and there is just one Redirect action runs.
2512 - echo json_encode( array( 'redirect' => $success_url ) );
2519 + if ( ! empty( $args['ajax'] ) && $doing_ajax && empty( $args['force_delay_redirect'] ) ) {
2520 + // Is AJAX submit and there is just one Redirect action runs.
2521 + echo json_encode( self::get_ajax_redirect_response_data( $args + compact( 'success_url' ) ) );
2513 2522 wp_die();
2514 2523 }
2515 2524
2516 - if ( ! headers_sent() && empty( $args['force_delay_redirect'] ) ) { // Not AJAX submit, no headers sent, and there is just one Redirect action runs.
2525 + if ( ! headers_sent() && empty( $args['force_delay_redirect'] ) ) {
2526 + // Not AJAX submit, no headers sent, and there is just one Redirect action runs.
2527 + if ( ! empty( $args['form']->options['open_in_new_tab'] ) ) {
2528 + self::print_open_in_new_tab_js_with_fallback_handler( $success_url, $args );
2529 + self::$redirected_in_new_tab[ $args['form']->id ] = 1;
2530 + return;
2531 + }
2532 +
2517 2533 wp_redirect( esc_url_raw( $success_url ) );
2518 - die(); // do not use wp_die or redirect fails
2534 + // Do not use wp_die or redirect fails.
2535 + die();
2519 2536 }
2520 2537
2521 2538 // Redirect with a delay.
2522 2539 self::redirect_after_submit_using_js( $args + compact( 'success_url', 'doing_ajax' ) );
@@ -2522,8 +2539,63 @@
2522 2539 self::redirect_after_submit_using_js( $args + compact( 'success_url', 'doing_ajax' ) );
2523 2540 }
2524 2541
2525 2542 /**
2543 + * Prints open in new tab js with fallback handler.
2544 + *
2545 + * @since 6.3.1
2546 + *
2547 + * @param string $success_url Success URL.
2548 + * @param array $args See {@see FrmFormsController::redirect_after_submit()}.
2549 + */
2550 + private static function print_open_in_new_tab_js_with_fallback_handler( $success_url, $args ) {
2551 + echo '<script>var newTab = window.open("' . esc_url_raw( $success_url ) . '", "_blank");';
2552 + echo 'if ( ! newTab ) {';
2553 +
2554 + $data = array(
2555 + 'formId' => intval( $args['form']->id ),
2556 + 'message' => self::get_redirect_fallback_message( $success_url, $args ),
2557 + );
2558 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2559 + echo 'frmShowNewTabFallback = ' . FrmAppHelper::maybe_json_encode( $data ) . ';';
2560 + echo '}</script>';
2561 + }
2562 +
2563 + /**
2564 + * Gets response data for redirect action when AJAX submitting.
2565 + *
2566 + * @since 6.3.1
2567 + *
2568 + * @param array $args See {@see FrmFormsController::run_success_action()}.
2569 + * @return array
2570 + */
2571 + private static function get_ajax_redirect_response_data( $args ) {
2572 + $response_data = array( 'redirect' => $args['success_url'] );
2573 +
2574 + if ( ! empty( $args['form']->options['open_in_new_tab'] ) ) {
2575 + $response_data['openInNewTab'] = 1;
2576 +
2577 + $args['message'] = FrmOnSubmitHelper::get_default_new_tab_msg();
2578 +
2579 + $args['form']->options['success_msg'] = $args['message'];
2580 + $args['form']->options['edit_msg'] = $args['message'];
2581 + if ( ! isset( $args['fields'] ) ) {
2582 + $args['fields'] = FrmField::get_all_for_form( $args['form']->id );
2583 + }
2584 +
2585 + $args['message'] = self::prepare_submit_message( $args['form'], $args['entry_id'], $args );
2586 +
2587 + ob_start();
2588 + self::show_lone_success_messsage( $args );
2589 + $response_data['content'] = ob_get_clean();
2590 +
2591 + $response_data['fallbackMsg'] = self::get_redirect_fallback_message( $args['success_url'], $args );
2592 + }
2593 +
2594 + return $response_data;
2595 + }
2596 +
2597 + /**
2526 2598 * Redirects after submitting using JS. This is used when showing message before redirecting.
2527 2599 *
2528 2600 * @since 6.0
2529 2601 *
@@ -2531,8 +2603,9 @@
2531 2603 */
2532 2604 private static function redirect_after_submit_using_js( $args ) {
2533 2605 $success_msg = FrmOnSubmitHelper::get_default_redirect_msg();
2534 2606 $redirect_msg = self::get_redirect_message( $args['success_url'], $success_msg, $args );
2607 + $success_url = esc_url_raw( $args['success_url'] );
2535 2608
2536 2609 /**
2537 2610 * Filters the delay time before redirecting when On Submit Redirect action is delayed.
2538 2611 *
@@ -2541,16 +2614,23 @@
2541 2614 * @param int $delay_time Delay time in miliseconds.
2542 2615 */
2543 2616 $delay_time = apply_filters( 'frm_redirect_delay_time', 8000 );
2544 2617
2618 + if ( ! empty( $args['form']->options['open_in_new_tab'] ) ) {
2619 + $redirect_js = 'window.open("' . $success_url . '", "_blank")';
2620 + } else {
2621 + $redirect_js = 'window.location="' . $success_url . '";';
2622 + }
2623 +
2545 2624 add_filter( 'frm_use_wpautop', '__return_true' );
2546 2625
2547 2626 echo FrmAppHelper::maybe_kses( $redirect_msg ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2548 2627 echo '<script>';
2549 - if ( empty( $args['doing_ajax'] ) ) { // Not AJAX submit, delay JS until window.load.
2628 + if ( empty( $args['doing_ajax'] ) ) {
2629 + // Not AJAX submit, delay JS until window.load.
2550 2630 echo 'window.onload=function(){';
2551 2631 }
2552 - echo 'setTimeout(function(){window.location="' . esc_url_raw( $args['success_url'] ) . '";}, ' . intval( $delay_time ) . ');';
2632 + echo 'setTimeout(function(){' . $redirect_js . '}, ' . intval( $delay_time ) . ');'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2553 2633 if ( empty( $args['doing_ajax'] ) ) {
2554 2634 echo '};';
2555 2635 }
2556 2636 echo '</script>';
@@ -2560,14 +2640,13 @@
2560 2640 * @since 3.0
2561 2641 *
2562 2642 * @param string $success_url
2563 2643 * @param string $success_msg
2564 - * @param array $args
2644 + * @param array $args
2565 2645 */
2566 2646 private static function get_redirect_message( $success_url, $success_msg, $args ) {
2567 2647 $redirect_msg = '<div class="' . esc_attr( FrmFormsHelper::get_form_style_class( $args['form'] ) ) . '"><div class="frm-redirect-msg" role="status">' . $success_msg . '<br/>' .
2568 - /* translators: %1$s: Start link HTML, %2$s: End link HTML */
2569 - sprintf( __( '%1$sClick here%2$s if you are not automatically redirected.', 'formidable' ), '<a href="' . esc_url( $success_url ) . '">', '</a>' ) .
2648 + self::get_redirect_fallback_message( $success_url, $args ) .
2570 2649 '</div></div>';
2571 2650
2572 2651 $redirect_args = array(
2573 2652 'entry_id' => $args['entry_id'],
@@ -2578,8 +2657,31 @@
2578 2657 return apply_filters( 'frm_redirect_msg', $redirect_msg, $redirect_args );
2579 2658 }
2580 2659
2581 2660 /**
2661 + * Gets fallback message when redirecting failed.
2662 + *
2663 + * @since 6.3.1
2664 + *
2665 + * @param string $success_url Redirect URL.
2666 + * @param array $args Contains `form` object.
2667 + * @return string
2668 + */
2669 + private static function get_redirect_fallback_message( $success_url, $args ) {
2670 + $target = '';
2671 + if ( ! empty( $args['form']->options['open_in_new_tab'] ) ) {
2672 + $target = ' target="_blank"';
2673 + }
2674 +
2675 + return sprintf(
2676 + /* translators: %1$s: Start link HTML, %2$s: End link HTML */
2677 + __( '%1$sClick here%2$s if you are not automatically redirected.', 'formidable' ),
2678 + '<a href="' . esc_url( $success_url ) . '"' . $target . '>',
2679 + '</a>'
2680 + );
2681 + }
2682 +
2683 + /**
2582 2684 * Prepare to show the success message and empty form after submit
2583 2685 *
2584 2686 * @since 2.05
2585 2687 */
@@ -2877,9 +2979,9 @@
2877 2979 * Create a page with an embedded formidable Gutenberg block.
2878 2980 *
2879 2981 * @since 5.2
2880 2982 *
2881 - * @return never
2983 + * @return void
2882 2984 */
2883 2985 public static function create_page_with_shortcode() {
2884 2986 if ( ! current_user_can( 'publish_posts' ) ) {
2885 2987 die( 0 );
@@ -2924,10 +3026,9 @@
2924 3026
2925 3027 /**
2926 3028 * @since 5.3
2927 3029 *
2928 - * @param string $content
2929 - * @param int $form_id
3030 + * @param int $form_id
2930 3031 * @return string
2931 3032 */
2932 3033 private static function get_page_shortcode_content_for_form( $form_id ) {
2933 3034 $shortcode = '[formidable id="' . $form_id . '"]';
@@ -2938,9 +3039,9 @@
2938 3039
2939 3040 /**
2940 3041 * Get page dropdown for AJAX request for embedding form in an existing page.
2941 3042 *
2942 - * @return never
3043 + * @return void
2943 3044 */
2944 3045 public static function get_page_dropdown() {
2945 3046 if ( ! current_user_can( 'publish_posts' ) ) {
2946 3047 die( 0 );
@@ -3012,6 +3113,46 @@
3012 3113 * @since 3.06
3013 3114 */
3014 3115 public static function add_new() {
3015 3116 _deprecated_function( __FUNCTION__, '4.08' );
3117 + }
3118 +
3119 + /**
3120 + * Create a custom template from a form
3121 + *
3122 + * @since 3.06
3123 + * @deprecated 6.7
3124 + */
3125 + public static function build_template() {
3126 + _deprecated_function( __METHOD__, '6.7' );
3127 + }
3128 +
3129 + /**
3130 + * @deprecated 6.7
3131 + *
3132 + * @return bool
3133 + */
3134 + public static function expired() {
3135 + _deprecated_function( __METHOD__, '6.7' );
3136 + return FrmAddonsController::is_license_expired();
3137 + }
3138 +
3139 + /**
3140 + * Get data from api before rendering it so that we can flag the modal as expired
3141 + *
3142 + * @deprecated 6.7
3143 + *
3144 + * @return void
3145 + */
3146 + public static function before_list_templates() {
3147 + _deprecated_function( __METHOD__, '6.7' );
3148 + }
3149 +
3150 + /**
3151 + * @deprecated 6.7
3152 + *
3153 + * @return void
3154 + */
3155 + public static function list_templates() {
3156 + _deprecated_function( __METHOD__, '6.7' );
3016 3157 }
3017 3158 }