PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
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 +383 -144 6.27 → trunk View file →
@@ -47,8 +47,15 @@
47 47 add_filter( 'manage_toplevel_page_formidable_columns', 'FrmFormsController::get_columns', 0 );
48 48 add_filter( 'manage_toplevel_page_formidable_sortable_columns', 'FrmFormsController::get_sortable_columns' );
49 49 }
50 50
51 + /**
52 + * Runs on admin head of the formidable forms page.
53 + *
54 + * @since 6.32 This adds screen options.
55 + *
56 + * @return void
57 + */
51 58 public static function head() {
52 59 if ( wp_is_mobile() ) {
53 60 wp_enqueue_script( 'jquery-touch-punch' );
54 61 }
@@ -126,15 +133,17 @@
126 133 }
127 134
128 135 $create_email = apply_filters( 'frm_create_default_email_action', true, $form );
129 136
130 - if ( $create_email ) {
131 - /**
132 - * @var FrmFormAction
133 - */
134 - $action_control = FrmFormActionsController::get_form_actions( 'email' );
135 - $action_control->create( $form->id );
137 + if ( ! $create_email ) {
138 + return;
136 139 }
140 +
141 + /**
142 + * @var FrmFormAction
143 + */
144 + $action_control = FrmFormActionsController::get_form_actions( 'email' );
145 + $action_control->create( $form->id );
137 146 }
138 147
139 148 /**
140 149 * Create the default On submit action
@@ -161,15 +170,17 @@
161 170 * @param object $form Form object.
162 171 */
163 172 $create = apply_filters( 'frm_create_default_on_submit_action', true, $form );
164 173
165 - if ( $create ) {
166 - /**
167 - * @var FrmFormAction
168 - */
169 - $action_control = FrmFormActionsController::get_form_actions( FrmOnSubmitAction::$slug );
170 - $action_control->create( $form->id );
174 + if ( ! $create ) {
175 + return;
171 176 }
177 +
178 + /**
179 + * @var FrmFormAction
180 + */
181 + $action_control = FrmFormActionsController::get_form_actions( FrmOnSubmitAction::$slug );
182 + $action_control->create( $form->id );
172 183 }
173 184
174 185 /**
175 186 * Creates submit button field.
@@ -262,9 +273,9 @@
262 273 }
263 274
264 275 do_action( 'frm_before_update_form_settings', $id );
265 276
266 - $antispam_was_on = self::antispam_was_on( $id );
277 + $antispam_was_on = self::antispam_was_on( $id ); // phpcs:ignore Formidable.CodeAnalysis.InlineSingleUseVariable
267 278
268 279 FrmForm::update( $id, $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
269 280
270 281 $antispam_is_on = ! empty( $_POST['options']['antispam'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
@@ -272,8 +283,12 @@
272 283 if ( $antispam_is_on !== $antispam_was_on ) {
273 284 FrmAntiSpam::clear_caches();
274 285 }
275 286
287 + // Handle captcha field inclusion
288 + $include_captcha = isset( $_POST['frm_include_captcha'] ) && '1' === $_POST['frm_include_captcha']; // phpcs:ignore WordPress.Security.NonceVerification.Missing
289 + self::handle_captcha_field( $id, $include_captcha );
290 +
276 291 $message = __( 'Settings Successfully Updated', 'formidable' );
277 292
278 293 self::get_settings_vars( $id, array(), compact( 'message', 'warnings' ) );
279 294 }
@@ -288,8 +303,46 @@
288 303 return ! empty( $form->options['antispam'] );
289 304 }
290 305
291 306 /**
307 + * Handle captcha field inclusion in form
308 + *
309 + * @since 6.33
310 + *
311 + * @param int $form_id Form ID.
312 + * @param bool $include_captcha Whether to include captcha field.
313 + *
314 + * @return void
315 + */
316 + private static function handle_captcha_field( $form_id, $include_captcha ) {
317 + $form_fields = FrmField::get_all_for_form( $form_id, '', 'exclude' );
318 + $captcha_field_id = 0;
319 + $submit_field_order = 0;
320 +
321 + foreach ( $form_fields as $field ) {
322 + if ( 'captcha' === $field->type ) {
323 + $captcha_field_id = $field->id;
324 + break;
325 + }
326 +
327 + if ( 'submit' === $field->type ) {
328 + $submit_field_order = $field->field_order;
329 + }
330 + }
331 +
332 + if ( $include_captcha && ! $captcha_field_id ) {
333 + // Create captcha field just before submit button
334 + $field_values = FrmFieldsHelper::setup_new_vars( 'captcha', $form_id );
335 + $field_values['name'] = __( 'Captcha', 'formidable' );
336 + $field_values['field_order'] = $submit_field_order > 0 ? $submit_field_order - 1 : 0;
337 + FrmField::create( $field_values );
338 + } elseif ( ! $include_captcha && $captcha_field_id ) {
339 + // Delete captcha field
340 + FrmField::destroy( $captcha_field_id );
341 + }
342 + }
343 +
344 + /**
292 345 * @param array $values
293 346 *
294 347 * @return void
295 348 */
@@ -566,14 +619,16 @@
566 619 add_action( 'loop_no_results', 'FrmFormsController::show_page_preview' );
567 620 add_filter( 'is_active_sidebar', '__return_false' );
568 621 FrmStylesController::enqueue_css( 'enqueue', true );
569 622
570 - if ( false === get_template_part( 'page' ) ) {
571 - if ( function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) {
572 - add_filter( 'body_class', 'FrmFormsController::preview_block_theme_body_classnames' );
573 - }
574 - self::fallback_when_page_template_part_is_not_supported_by_theme();
623 + if ( false !== get_template_part( 'page' ) ) {
624 + return;
575 625 }
626 +
627 + if ( function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) {
628 + add_filter( 'body_class', 'FrmFormsController::preview_block_theme_body_classnames' );
629 + }
630 + self::fallback_when_page_template_part_is_not_supported_by_theme();
576 631 }
577 632
578 633 /**
579 634 * Add padding to the body for block themes.
@@ -595,25 +650,27 @@
595 650 *
596 651 * @return void
597 652 */
598 653 private static function fallback_when_page_template_part_is_not_supported_by_theme() {
599 - if ( have_posts() ) {
600 - the_post();
601 - self::get_template( 'header' );
654 + if ( ! have_posts() ) {
655 + return;
656 + }
602 657
603 - // add some generic class names to the container to add some natural padding to the content.
604 - // .entry-content catches the WordPress TwentyTwenty theme.
605 - // .container catches Customizr content.
606 - echo '<div class="container entry-content">';
607 - the_content();
608 - echo '</div>';
658 + the_post();
659 + self::get_template( 'header' );
609 660
610 - // Prevent extra unexpected forms in the footer.
611 - // For some reason this happens in the Twenty Twenty Five theme.
612 - add_filter( 'frm_filter_final_form', '__return_empty_string' );
661 + // Add some generic class names to the container to add some natural padding to the content.
662 + // .entry-content catches the WordPress TwentyTwenty theme.
663 + // .container catches Customizr content.
664 + echo '<div class="container entry-content">';
665 + the_content();
666 + echo '</div>';
613 667
614 - self::get_template( 'footer' );
615 - }
668 + // Prevent extra unexpected forms in the footer.
669 + // For some reason this happens in the Twenty Twenty Five theme.
670 + add_filter( 'frm_filter_final_form', '__return_empty_string' );
671 +
672 + self::get_template( 'footer' );
616 673 }
617 674
618 675 /**
619 676 * Calls core function to get a template part if it doesn't cause deprecation warnings. Otherwise skips the deprecation function call
@@ -668,13 +725,9 @@
668 725 *
669 726 * @return string
670 727 */
671 728 public static function preview_page_title( $title ) {
672 - if ( in_the_loop() ) {
673 - $title = self::preview_title( $title );
674 - }
675 -
676 - return $title;
729 + return in_the_loop() ? self::preview_title( $title ) : $title;
677 730 }
678 731
679 732 /**
680 733 * Set the page title for the theme preview page.
@@ -760,16 +813,18 @@
760 813 *
761 814 * @return void
762 815 */
763 816 public static function maybe_block_preview( $form_key ) {
764 - if ( FrmFormsHelper::should_block_preview( $form_key ) ) {
765 - $error = __( 'You do not have permission to view this form', 'formidable' );
766 - wp_die(
767 - '<h1>' . esc_html( $error ) . '</h1>',
768 - '<p>' . esc_html( $error ) . '</p>',
769 - 403
770 - );
817 + if ( ! FrmFormsHelper::should_block_preview( $form_key ) ) {
818 + return;
771 819 }
820 +
821 + $error = __( 'You do not have permission to view this form', 'formidable' );
822 + wp_die(
823 + '<h1>' . esc_html( $error ) . '</h1>',
824 + '<p>' . esc_html( $error ) . '</p>',
825 + 403
826 + );
772 827 }
773 828
774 829 /**
775 830 * Some themes have a null $src value.
@@ -788,12 +843,9 @@
788 843 *
789 844 * @return string
790 845 */
791 846 function ( $src ) {
792 - if ( is_null( $src ) ) {
793 - $src = '';
794 - }
795 - return $src;
847 + return is_null( $src ) ? '' : $src;
796 848 }
797 849 );
798 850 }
799 851
@@ -1059,21 +1111,22 @@
1059 1111 *
1060 1112 * @return void
1061 1113 */
1062 1114 public static function insert_form_button() {
1063 - if ( current_user_can( 'frm_view_forms' ) ) {
1064 - // Store the result in memory and re-use it when this function is called multiple times.
1065 - // This helps speed up the form builder when there are a lot of HTML fields, where this
1066 - // button is inserted once per HTML field.
1067 - // In a form with 66 HTML fields, this saves 0.5 seconds on page load time, tested locally.
1068 - if ( ! isset( self::$formidable_tinymce_button ) ) {
1069 - FrmAppHelper::load_admin_wide_js();
1070 - $menu_name = FrmAppHelper::get_menu_name();
1071 - $icon = apply_filters( 'frm_media_icon', FrmAppHelper::svg_logo() );
1072 - self::$formidable_tinymce_button = '<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' ) . '">' . FrmAppHelper::kses( $icon, 'all' ) . ' ' . esc_html( $menu_name ) . '</a>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
1073 - }
1074 - echo self::$formidable_tinymce_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1115 + if ( ! current_user_can( 'frm_view_forms' ) ) {
1116 + return;
1075 1117 }
1118 +
1119 + // Store the result in memory and re-use it when this function is called multiple times.
1120 + // This helps speed up the form builder when there are a lot of HTML fields, where this
1121 + // Button is inserted once per HTML field.
1122 + // In a form with 66 HTML fields, this saves 0.5 seconds on page load time, tested locally.
1123 + if ( ! isset( self::$formidable_tinymce_button ) ) {
1124 + FrmAppHelper::load_admin_wide_js();
1125 + $icon = apply_filters( 'frm_media_icon', FrmAppHelper::svg_logo() );
1126 + self::$formidable_tinymce_button = '<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' ) . '">' . FrmAppHelper::kses( $icon, 'all' ) . ' ' . esc_html( FrmAppHelper::get_menu_name() ) . '</a>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
1127 + }
1128 + echo self::$formidable_tinymce_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1076 1129 }
1077 1130
1078 1131 /**
1079 1132 * @return void
@@ -1094,17 +1147,21 @@
1094 1147 $shortcodes = apply_filters( 'frm_popup_shortcodes', $shortcodes );
1095 1148
1096 1149 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/insert_form_popup.php';
1097 1150
1098 - if ( FrmAppHelper::is_form_builder_page() && ! class_exists( '_WP_Editors', false ) ) {
1099 - // initialize a wysiwyg so we have usable settings defined in tinyMCEPreInit.mceInit
1100 - require ABSPATH . WPINC . '/class-wp-editor.php';
1101 - ?>
1102 - <div class="frm_hidden">
1103 - <?php wp_editor( '', 'frm_description_placeholder', array() ); ?>
1104 - </div>
1105 - <?php
1151 + if ( ! FrmAppHelper::is_form_builder_page() || class_exists( '_WP_Editors', false ) ) {
1152 + return;
1106 1153 }
1154 +
1155 + // Initialize a wysiwyg so we have usable settings defined in tinyMCEPreInit.mceInit
1156 + require ABSPATH . WPINC . '/class-wp-editor.php';
1157 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
1158 + ?>
1159 + <div class="frm_hidden">
1160 + <?php wp_editor( '', 'frm_description_placeholder', array() ); ?>
1161 + </div>
1162 + <?php
1163 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
1107 1164 }
1108 1165
1109 1166 /**
1110 1167 * Check the page being loaded, determine if this is a page that should include the form popup.
@@ -1158,9 +1215,9 @@
1158 1215
1159 1216 $opts = apply_filters( 'frm_sc_popup_opts', $opts, $shortcode );
1160 1217
1161 1218 if ( isset( $opts['form_id'] ) && is_string( $opts['form_id'] ) ) {
1162 - // allow other shortcodes to use the required form id option
1219 + // Allow other shortcodes to use the required form id option
1163 1220 $form_id = $opts['form_id'];
1164 1221 unset( $opts['form_id'] );
1165 1222 }
1166 1223
@@ -1202,9 +1259,9 @@
1202 1259
1203 1260 $total_pages = $wp_list_table->get_pagination_arg( 'total_pages' );
1204 1261
1205 1262 if ( $pagenum > $total_pages && $total_pages > 0 ) {
1206 - wp_redirect( esc_url_raw( add_query_arg( 'paged', $total_pages ) ) );
1263 + wp_safe_redirect( esc_url_raw( add_query_arg( 'paged', $total_pages ) ) );
1207 1264 die();
1208 1265 }
1209 1266
1210 1267 $error = FrmInbox::check_for_error();
@@ -1224,17 +1281,27 @@
1224 1281 public static function get_columns( $columns ) {
1225 1282 $columns['cb'] = '<input type="checkbox" />';
1226 1283 $columns['name'] = esc_html__( 'Form Title', 'formidable' );
1227 1284 $columns['entries'] = esc_html__( 'Entries', 'formidable' );
1285 + $columns['views'] = esc_html__( 'Views', 'formidable' );
1228 1286 $columns['id'] = 'ID';
1229 1287 $columns['form_key'] = esc_html__( 'Key', 'formidable' );
1230 1288
1231 - if ( 'trash' !== FrmAppHelper::simple_get( 'form_type' ) ) {
1289 + if ( 'trash' !== FrmAppHelper::simple_get( 'form_type' ) && has_filter( 'frm_form_list_actions' ) ) {
1290 + // If there is any filters added, keep this column.
1232 1291 $columns['shortcode'] = esc_html__( 'Actions', 'formidable' );
1233 1292 }
1234 1293
1235 1294 $columns['created_at'] = esc_html__( 'Date', 'formidable' );
1236 1295
1296 + if ( 'trash' !== FrmAppHelper::simple_get( 'form_type' ) ) {
1297 + $columns['embeds'] = esc_html__( 'Embeds', 'formidable' );
1298 + $columns['settings'] = '<div class="frm-forms-list-settings-btn-wrapper"><a href="#" class="frm-forms-list-settings-btn">';
1299 + $columns['settings'] .= FrmAppHelper::icon_by_class( 'frmfont frm_settings_icon', array( 'echo' => false ) );
1300 + $columns['settings'] .= '<span class="screen-reader-text">' . esc_html__( 'List settings', 'formidable' ) . '</span>';
1301 + $columns['settings'] .= '</a></div>';
1302 + }
1303 +
1237 1304 add_screen_option(
1238 1305 'per_page',
1239 1306 array(
1240 1307 'label' => __( 'Forms', 'formidable' ),
@@ -1292,9 +1359,9 @@
1292 1359 * @return mixed
1293 1360 */
1294 1361 public static function save_per_page( $save, $option, $value ) {
1295 1362 if ( $option === 'formidable_page_formidable_per_page' ) {
1296 - $save = (int) $value;
1363 + return (int) $value;
1297 1364 }
1298 1365
1299 1366 return $save;
1300 1367 }
@@ -1512,19 +1579,24 @@
1512 1579 'advanced' => array(
1513 1580 'name' => __( 'General', 'formidable' ),
1514 1581 'title' => __( 'General Form Settings', 'formidable' ),
1515 1582 'function' => array( self::class, 'advanced_settings' ),
1516 - 'icon' => 'frmfont frm_settings_icon',
1583 + 'icon' => 'frmfont frm_small_settings_icon',
1517 1584 ),
1518 1585 'email' => array(
1519 1586 'name' => __( 'Actions & Notifications', 'formidable' ),
1520 1587 'function' => array( 'FrmFormActionsController', 'email_settings' ),
1521 1588 'id' => 'frm_notification_settings',
1522 - 'icon' => 'frmfont frm_mail_bulk_icon',
1589 + 'icon' => 'frmfont frm_notification_check_icon',
1523 1590 ),
1591 + 'spam' => array(
1592 + 'name' => __( 'Spam', 'formidable' ),
1593 + 'function' => array( self::class, 'spam_settings' ),
1594 + 'icon' => 'frmfont frm_shield_check2_icon',
1595 + ),
1524 1596 'permissions' => array(
1525 1597 'name' => __( 'Form Permissions', 'formidable' ),
1526 - 'icon' => 'frmfont frm_lock_closed_icon',
1598 + 'icon' => 'frmfont frm_lock_closed2_icon',
1527 1599 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1528 1600 'data' => array(
1529 1601 'medium' => 'permissions',
1530 1602 'upgrade' => __( 'Form Permissions', 'formidable' ),
@@ -1534,9 +1606,9 @@
1534 1606 ),
1535 1607 ),
1536 1608 'scheduling' => array(
1537 1609 'name' => __( 'Form Scheduling', 'formidable' ),
1538 - 'icon' => 'frmfont frm_calendar_icon',
1610 + 'icon' => 'frmfont frm_schedule_icon',
1539 1611 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1540 1612 'data' => array(
1541 1613 'medium' => 'scheduling',
1542 1614 'upgrade' => __( 'Form scheduling settings', 'formidable' ),
@@ -1547,19 +1619,19 @@
1547 1619 'buttons' => array(
1548 1620 'name' => __( 'Buttons', 'formidable' ),
1549 1621 'class' => self::class,
1550 1622 'function' => 'buttons_settings',
1551 - 'icon' => 'frmfont frm_button_icon',
1623 + 'icon' => 'frmfont frm-buttons-style',
1552 1624 ),
1553 1625 'landing' => array(
1554 1626 'name' => __( 'Form Landing Page', 'formidable' ),
1555 - 'icon' => 'frmfont frm_file_text_icon',
1627 + 'icon' => 'frmfont frm_cross_device_icon',
1556 1628 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1557 1629 'data' => FrmAppHelper::get_landing_page_upgrade_data_params(),
1558 1630 ),
1559 1631 'chat' => array(
1560 1632 'name' => __( 'Conversational Forms', 'formidable' ),
1561 - 'icon' => 'frmfont frm_chat_forms_icon',
1633 + 'icon' => 'frmfont frm_chat_bubbles_icon',
1562 1634 'html_class' => 'frm_show_upgrade_tab frm_noallow',
1563 1635 'data' => FrmAppHelper::get_upgrade_data_params(
1564 1636 'chat',
1565 1637 array(
@@ -1587,9 +1659,9 @@
1587 1659 'html' => array(
1588 1660 'name' => __( 'Customize HTML', 'formidable' ),
1589 1661 'class' => self::class,
1590 1662 'function' => 'html_settings',
1591 - 'icon' => 'frmfont frm_code_icon',
1663 + 'icon' => 'frmfont frm_code2_icon',
1592 1664 ),
1593 1665 );
1594 1666
1595 1667 if ( ! has_action( 'frm_add_form_style_tab_options' ) && ! has_action( 'frm_add_form_button_options' ) ) {
@@ -1639,18 +1711,16 @@
1639 1711 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/settings-advanced.php';
1640 1712 }
1641 1713
1642 1714 /**
1715 + * @since 6.33
1716 + *
1643 1717 * @param array $values
1644 1718 *
1645 1719 * @return void
1646 1720 */
1647 - public static function render_spam_settings( $values ) {
1648 - if ( function_exists( 'akismet_http_post' ) ) {
1649 - include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/spam-settings/akismet.php';
1650 - }
1651 - include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/spam-settings/stopforumspam.php';
1652 - include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/spam-settings/antispam.php';
1721 + public static function spam_settings( $values ) {
1722 + include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/spam-settings.php';
1653 1723 }
1654 1724
1655 1725 /**
1656 1726 * @since 4.0
@@ -1728,9 +1798,9 @@
1728 1798 $linked_forms = array();
1729 1799 $col = 'one';
1730 1800 $settings_tab = FrmAppHelper::is_admin_page( 'formidable' );
1731 1801 $cond_shortcodes = apply_filters( 'frm_conditional_shortcodes', array() );
1732 - $entry_shortcodes = self::get_shortcode_helpers( $settings_tab );
1802 + $entry_shortcodes = self::get_shortcode_helpers( $settings_tab, $form_id );
1733 1803 $advanced_helpers = self::advanced_helpers( compact( 'fields', 'form_id' ) );
1734 1804
1735 1805 if ( 'default' === $template_path || ! file_exists( $template_path ) ) {
1736 1806 include FrmAppHelper::plugin_path() . '/classes/views/shared/mb_adv_info.php';
@@ -1781,8 +1851,126 @@
1781 1851 return apply_filters( 'frm_advanced_helpers', $advanced_helpers, $atts );
1782 1852 }
1783 1853
1784 1854 /**
1855 + * Adds a shortcode for each part of a multi-part field to the field shortcode list,
1856 + * so a single part can be used on its own, like [25 show=first] for a Name field.
1857 + *
1858 + * @since 6.35
1859 + *
1860 + * @param array $atts Includes 'field'.
1861 + *
1862 + * @return void
1863 + */
1864 + public static function field_part_shortcodes( $atts ) {
1865 + $field = $atts['field'];
1866 +
1867 + foreach ( self::get_field_parts( $field ) as $part => $label ) {
1868 + FrmFormsHelper::insert_opt_html(
1869 + array(
1870 + 'id' => $field->id . ' show=' . $part,
1871 + 'key' => $field->field_key . ' show=' . $part,
1872 + // Keep the part label and the option out of the truncated text so they stay readable.
1873 + 'key_label' => $field->field_key,
1874 + 'key_suffix' => ' show=' . $part,
1875 + 'name' => $field->name,
1876 + 'name_suffix' => ' (' . $label . ')',
1877 + 'type' => $field->type,
1878 + 'class' => 'frm-customize-list dropdown-item',
1879 + )
1880 + );
1881 + unset( $part, $label );
1882 + }
1883 + }
1884 +
1885 + /**
1886 + * Gets the parts of a multi-part field that can be shown on their own with a show= shortcode option.
1887 + *
1888 + * @since 6.35
1889 + *
1890 + * @param stdClass $field
1891 + *
1892 + * @return array Part labels keyed by the show= option value.
1893 + */
1894 + private static function get_field_parts( $field ) {
1895 + $parts = array();
1896 +
1897 + if ( 'name' === $field->type ) {
1898 + $parts = self::get_name_field_parts( $field );
1899 + } elseif ( 'address' === $field->type ) {
1900 + $parts = self::get_address_field_parts( $field );
1901 + }
1902 +
1903 + /**
1904 + * Allows add-ons to add the parts of their own multi-part fields.
1905 + *
1906 + * @since 6.35
1907 + *
1908 + * @param array $parts Part labels keyed by the show= option value.
1909 + * @param stdClass $field The field the parts belong to.
1910 + */
1911 + return apply_filters( 'frm_field_parts_for_shortcodes', $parts, $field );
1912 + }
1913 +
1914 + /**
1915 + * Gets the parts of a Name field that are in use. Only the parts included in the
1916 + * selected name layout hold a value, so the rest would always show as blank.
1917 + *
1918 + * @since 6.35
1919 + *
1920 + * @param stdClass $field
1921 + *
1922 + * @return array Part labels keyed by the show= option value, in layout order.
1923 + */
1924 + private static function get_name_field_parts( $field ) {
1925 + $labels = array(
1926 + 'first' => __( 'First', 'formidable' ),
1927 + 'middle' => __( 'Middle', 'formidable' ),
1928 + 'last' => __( 'Last', 'formidable' ),
1929 + );
1930 + $layout = FrmField::get_option( $field, 'name_layout' );
1931 +
1932 + if ( ! $layout ) {
1933 + $layout = 'first_last';
1934 + }
1935 +
1936 + // The layout option names the parts in use, in display order, like first_middle_last.
1937 + $parts = array();
1938 +
1939 + foreach ( explode( '_', $layout ) as $part ) {
1940 + if ( isset( $labels[ $part ] ) ) {
1941 + $parts[ $part ] = $labels[ $part ];
1942 + }
1943 + unset( $part );
1944 + }
1945 +
1946 + return $parts;
1947 + }
1948 +
1949 + /**
1950 + * Gets the parts of an Address field that are in use. The address type decides which
1951 + * parts are on the form, so the rest would always show as blank.
1952 + *
1953 + * @since 6.35
1954 + *
1955 + * @param stdClass $field
1956 + *
1957 + * @return array Part labels keyed by the show= option value.
1958 + */
1959 + private static function get_address_field_parts( $field ) {
1960 + $parts = FrmFieldAddress::get_part_labels();
1961 + $address_type = FrmField::get_option( $field, 'address_type' );
1962 +
1963 + if ( in_array( $address_type, array( 'us', 'generic' ), true ) ) {
1964 + unset( $parts['country'] );
1965 + } elseif ( 'europe' === $address_type ) {
1966 + unset( $parts['state'] );
1967 + }
1968 +
1969 + return $parts;
1970 + }
1971 +
1972 + /**
1785 1973 * Get an array of the options to display in the advanced tab
1786 1974 * of the customization panel
1787 1975 *
1788 1976 * @since 2.0.6
@@ -1837,12 +2025,13 @@
1837 2025 *
1838 2026 * @since 2.0.6
1839 2027 *
1840 2028 * @param bool $settings_tab
2029 + * @param int $form_id
1841 2030 *
1842 2031 * @return array
1843 2032 */
1844 - private static function get_shortcode_helpers( $settings_tab ) {
2033 + private static function get_shortcode_helpers( $settings_tab, $form_id = 0 ) {
1845 2034 $entry_shortcodes = array(
1846 2035 'id' => __( 'Entry ID', 'formidable' ),
1847 2036 'key' => __( 'Entry Key', 'formidable' ),
1848 2037 'post_id' => __( 'Post ID', 'formidable' ),
@@ -1868,10 +2057,11 @@
1868 2057 * @since 2.0.6
1869 2058 *
1870 2059 * @param array $entry_shortcodes
1871 2060 * @param bool $settings_tab
2061 + * @param int $form_id
1872 2062 */
1873 - return apply_filters( 'frm_helper_shortcodes', $entry_shortcodes, $settings_tab );
2063 + return apply_filters( 'frm_helper_shortcodes', $entry_shortcodes, $settings_tab, $form_id );
1874 2064 }
1875 2065
1876 2066 /**
1877 2067 * Insert the form class setting into the form.
@@ -1988,15 +2178,17 @@
1988 2178 *
1989 2179 * @return void
1990 2180 */
1991 2181 private static function get_entry_by_param( &$entry ) {
1992 - if ( ! $entry || ! is_object( $entry ) ) {
1993 - if ( ! $entry || ! is_numeric( $entry ) ) {
1994 - $entry = FrmAppHelper::get_post_param( 'id', false, 'sanitize_title' );
1995 - }
2182 + if ( $entry && is_object( $entry ) ) {
2183 + return;
2184 + }
1996 2185
1997 - FrmEntry::maybe_get_entry( $entry );
2186 + if ( ! $entry || ! is_numeric( $entry ) ) {
2187 + $entry = FrmAppHelper::get_post_param( 'id', false, 'sanitize_title' );
1998 2188 }
2189 +
2190 + FrmEntry::maybe_get_entry( $entry );
1999 2191 }
2000 2192
2001 2193 /**
2002 2194 * @param string $content
@@ -2094,10 +2286,16 @@
2094 2286 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
2095 2287 $json_vars = htmlspecialchars_decode( nl2br( str_replace( '&quot;', '"', wp_unslash( $_POST['frm_compact_fields'] ) ) ) );
2096 2288 $json_vars = json_decode( $json_vars, true );
2097 2289
2098 - if ( ! $json_vars ) {
2099 - // json decoding failed so we should return an error message.
2290 + if ( $json_vars ) {
2291 + $vars = FrmAppHelper::json_to_array( $json_vars );
2292 + $action = $vars[ $action ];
2293 + unset( $_REQUEST['frm_compact_fields'], $_POST['frm_compact_fields'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
2294 + $_REQUEST = array_merge( $_REQUEST, $vars ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
2295 + $_POST = array_merge( $_POST, $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
2296 + } else {
2297 + // Json decoding failed so we should return an error message.
2100 2298 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
2101 2299
2102 2300 if ( 'edit' === $action ) {
2103 2301 $action = 'update';
@@ -2103,14 +2301,8 @@
2103 2301 $action = 'update';
2104 2302 }
2105 2303
2106 2304 add_filter( 'frm_validate_form', 'FrmFormsController::json_error' );
2107 - } else {
2108 - $vars = FrmAppHelper::json_to_array( $json_vars );
2109 - $action = $vars[ $action ];
2110 - unset( $_REQUEST['frm_compact_fields'], $_POST['frm_compact_fields'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
2111 - $_REQUEST = array_merge( $_REQUEST, $vars ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
2112 - $_POST = array_merge( $_POST, $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
2113 2305 }
2114 2306 } else {
2115 2307 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
2116 2308
@@ -2205,9 +2397,10 @@
2205 2397 }
2206 2398
2207 2399 if ( $name === $form->name ) {
2208 2400 // Nothing to change so exit early.
2209 - wp_send_json_success();
2401 + $form_key = $form->form_key;
2402 + wp_send_json_success( compact( 'form_key' ) );
2210 2403 }
2211 2404
2212 2405 $to_update = array(
2213 2406 'name' => $name,
@@ -2212,14 +2405,14 @@
2212 2405 $to_update = array(
2213 2406 'name' => $name,
2214 2407 );
2215 2408
2216 - if ( '' !== $name ) {
2409 + if ( '' === $name ) {
2410 + $form_key = $form->form_key;
2411 + } else {
2217 2412 // Only update form_key if name is not empty.
2218 2413 $form_key = FrmAppHelper::get_unique_key( sanitize_title( $name ), 'frm_forms', 'form_key' );
2219 2414 $to_update['form_key'] = $form_key;
2220 - } else {
2221 - $form_key = $form->form_key;
2222 2415 }
2223 2416
2224 2417 FrmForm::update( $form_id, $to_update );
2225 2418
@@ -2286,11 +2479,9 @@
2286 2479 /**
2287 2480 * @since 4.05.02
2288 2481 */
2289 2482 private static function move_menu_to_footer() {
2290 - $settings = FrmAppHelper::get_settings();
2291 -
2292 - if ( empty( $settings->admin_bar ) ) {
2483 + if ( empty( FrmAppHelper::get_settings()->admin_bar ) ) {
2293 2484 remove_action( 'wp_body_open', 'wp_admin_bar_render', 0 );
2294 2485 }
2295 2486 }
2296 2487
@@ -2352,9 +2543,9 @@
2352 2543 $wp_admin_bar->add_node(
2353 2544 array(
2354 2545 'parent' => 'frm-forms',
2355 2546 'id' => 'edit_form_' . $form_id,
2356 - 'title' => empty( $name ) ? FrmFormsHelper::get_no_title_text() : $name,
2547 + 'title' => $name ? $name : FrmFormsHelper::get_no_title_text(),
2357 2548 'href' => FrmForm::get_edit_link( $form_id ),
2358 2549 )
2359 2550 );
2360 2551 }
@@ -2442,9 +2633,9 @@
2442 2633 $form = apply_filters( 'frm_pre_display_form', $form );
2443 2634 $frm_settings = FrmAppHelper::get_settings( array( 'current_form' => $form->id ) );
2444 2635
2445 2636 if ( self::is_viewable_draft_form( $form ) ) {
2446 - // don't show a draft form on a page
2637 + // Don't show a draft form on a page
2447 2638 $form = __( 'Please select a valid form', 'formidable' );
2448 2639 } elseif ( ! FrmForm::is_visible_to_user( $form ) ) {
2449 2640 $form = do_shortcode( $frm_settings->login_msg );
2450 2641 } else {
@@ -2553,9 +2744,8 @@
2553 2744 self::show_form_after_submit( $pass_args );
2554 2745 }
2555 2746 } elseif ( $errors ) {
2556 2747 self::show_form_after_submit( $pass_args );
2557 -
2558 2748 } else {
2559 2749 do_action( 'frm_validate_form_creation', $params, $fields, $form, $title, $description );
2560 2750
2561 2751 if ( apply_filters( 'frm_continue_to_create', true, $form->id ) ) {
@@ -2649,9 +2839,9 @@
2649 2839
2650 2840 $method = apply_filters( 'frm_success_filter', $method, $atts['form'], $action );
2651 2841
2652 2842 if ( $method !== 'message' && ( ! $atts['entry_id'] || ! is_numeric( $atts['entry_id'] ) ) ) {
2653 - $method = 'message';
2843 + return 'message';
2654 2844 }
2655 2845
2656 2846 return $method;
2657 2847 }
@@ -2690,14 +2880,12 @@
2690 2880 * @param array $params See {@see FrmFormsController::maybe_trigger_redirect()}.
2691 2881 * @param array $args See {@see FrmFormsController::maybe_trigger_redirect()}.
2692 2882 */
2693 2883 public static function maybe_trigger_redirect_with_action( $conf_method, $form, $params, $args ) {
2694 - if ( is_array( $conf_method ) && 1 === count( $conf_method ) ) {
2695 - if ( 'redirect' === FrmOnSubmitHelper::get_action_type( $conf_method[0] ) && empty( $conf_method[0]->post_content['redirect_delay'] ) ) {
2696 - $event = FrmOnSubmitHelper::current_event( $params );
2697 - FrmOnSubmitHelper::populate_on_submit_data( $form->options, $conf_method[0], $event );
2698 - $conf_method = 'redirect';
2699 - }
2884 + if ( is_array( $conf_method ) && 1 === count( $conf_method ) && 'redirect' === FrmOnSubmitHelper::get_action_type( $conf_method[0] ) && empty( $conf_method[0]->post_content['redirect_delay'] ) ) { // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
2885 + $event = FrmOnSubmitHelper::current_event( $params );
2886 + FrmOnSubmitHelper::populate_on_submit_data( $form->options, $conf_method[0], $event );
2887 + $conf_method = 'redirect';
2700 2888 }
2701 2889
2702 2890 if ( 'redirect' === $conf_method ) {
2703 2891 self::trigger_redirect( $form, $params, $args );
@@ -2799,13 +2987,11 @@
2799 2987 }
2800 2988
2801 2989 $action_type = FrmOnSubmitHelper::get_action_type( $action );
2802 2990
2803 - if ( 'redirect' === $action_type ) {
2804 - if ( $has_redirect ) {
2805 - // Do not process because we run the first redirect action only.
2806 - continue;
2807 - }
2991 + if ( 'redirect' === $action_type && $has_redirect ) {
2992 + // Do not process because we run the first redirect action only.
2993 + continue;
2808 2994 }
2809 2995
2810 2996 if ( ! self::is_valid_on_submit_action( $action, $args, $event ) ) {
2811 2997 continue;
@@ -2831,9 +3017,9 @@
2831 3017 */
2832 3018 $met_actions = apply_filters( 'frm_get_met_on_submit_actions', $met_actions, $args );
2833 3019
2834 3020 if ( ! $met_actions ) {
2835 - $met_actions = array( FrmOnSubmitHelper::get_fallback_action( $event ) );
3021 + return array( FrmOnSubmitHelper::get_fallback_action( $event ) );
2836 3022 }
2837 3023
2838 3024 return $met_actions;
2839 3025 }
@@ -2935,13 +3121,15 @@
2935 3121
2936 3122 unset( $action );
2937 3123 }
2938 3124
2939 - if ( $redirect_action ) {
2940 - // Show script to delay the redirection.
2941 - $args['force_delay_redirect'] = true;
2942 - self::run_single_on_submit_action( $args, $redirect_action );
3125 + if ( ! $redirect_action ) {
3126 + return;
2943 3127 }
3128 +
3129 + // Show script to delay the redirection.
3130 + $args['force_delay_redirect'] = true;
3131 + self::run_single_on_submit_action( $args, $redirect_action );
2944 3132 }
2945 3133
2946 3134 /**
2947 3135 * Runs single On Submit action.
@@ -3190,13 +3378,16 @@
3190 3378 * @param string $success_msg
3191 3379 * @param array $args
3192 3380 */
3193 3381 private static function get_redirect_message( $success_url, $success_msg, $args ) {
3194 - $success_msg = apply_filters( 'frm_content', $success_msg, $args['form'], $args['entry_id'] );
3195 - $success_msg = do_shortcode( FrmAppHelper::use_wpautop( $success_msg ) );
3382 + $success_msg = apply_filters( 'frm_content', $success_msg, $args['form'], $args['entry_id'] );
3383 + $success_msg = do_shortcode( FrmAppHelper::use_wpautop( $success_msg ) );
3384 +
3385 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
3196 3386 $redirect_msg = '<div class="' . esc_attr( FrmFormsHelper::get_form_style_class( $args['form'] ) ) . '"><div class="frm-redirect-msg" role="status">' . $success_msg . '<br/>' . // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3197 3387 self::get_redirect_fallback_message( $success_url, $args ) .
3198 3388 '</div></div>';
3389 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
3199 3390
3200 3391 $redirect_args = array(
3201 3392 'entry_id' => $args['entry_id'],
3202 3393 'form_id' => $args['form']->id,
@@ -3390,11 +3581,11 @@
3390 3581 *
3391 3582 * @since 2.05
3392 3583 * @since 6.0.x Added the third parameter.
3393 3584 *
3394 - * @param object $form Form object.
3395 - * @param int $entry_id Entry ID.
3396 - * @param array $args See {@see FrmFormsController::run_success_action()}.
3585 + * @param object $form Form object.
3586 + * @param int|string $entry_id Entry ID.
3587 + * @param array $args See {@see FrmFormsController::run_success_action()}.
3397 3588 *
3398 3589 * @return string
3399 3590 */
3400 3591 private static function prepare_submit_message( $form, $entry_id, $args = array() ) {
@@ -3429,9 +3620,9 @@
3429 3620
3430 3621 add_filter( 'script_loader_tag', 'FrmFormsController::defer_script_loading', 10, 2 );
3431 3622
3432 3623 if ( FrmAppHelper::is_admin() ) {
3433 - // don't load this in back-end
3624 + // Don't load this in back-end
3434 3625 return;
3435 3626 }
3436 3627
3437 3628 FrmAppHelper::localize_script( 'front' );
@@ -3507,9 +3698,9 @@
3507 3698 * @return string
3508 3699 */
3509 3700 public static function defer_script_loading( $tag, $handle ) {
3510 3701 if ( 'captcha-api' === $handle && ! str_contains( $tag, 'defer' ) ) {
3511 - $tag = str_replace( ' src', ' defer="defer" async="async" src', $tag );
3702 + return str_replace( ' src', ' defer="defer" async="async" src', $tag );
3512 3703 }
3513 3704
3514 3705 return $tag;
3515 3706 }
@@ -3523,13 +3714,20 @@
3523 3714 global $frm_vars;
3524 3715
3525 3716 FrmStylesController::enqueue_css();
3526 3717
3527 - if ( ! FrmAppHelper::is_admin() && $location !== 'header' && ! empty( $frm_vars['forms_loaded'] ) ) {
3528 - // load formidable js
3529 - wp_enqueue_script( 'formidable' );
3718 + if ( FrmAppHelper::is_admin() || $location === 'header' || empty( $frm_vars['forms_loaded'] ) ) {
3719 + return;
3720 + }
3530 3721
3531 - FrmHoneypot::maybe_print_honeypot_js();
3722 + // Load formidable js
3723 + wp_enqueue_script( 'formidable' );
3724 +
3725 + FrmHoneypot::maybe_print_honeypot_js();
3726 +
3727 + if ( ! method_exists( 'FrmProFormsHelper', 'load_currency_js' ) ) {
3728 + // Load currency JS if Pro is not installed.
3729 + FrmFormsHelper::load_currency_js();
3532 3730 }
3533 3731 }
3534 3732
3535 3733 /**
@@ -3540,9 +3738,9 @@
3540 3738 *
3541 3739 * @return void
3542 3740 */
3543 3741 private static function maybe_minimize_form( $atts, &$content ) {
3544 - // check if minimizing is turned on
3742 + // Check if minimizing is turned on
3545 3743 if ( self::is_minification_on( $atts ) ) {
3546 3744 $content = str_replace( array( "\r\n", "\r", "\n", "\t", ' ' ), '', $content );
3547 3745 }
3548 3746 }
@@ -3660,9 +3858,9 @@
3660 3858 }
3661 3859
3662 3860 check_ajax_referer( 'frm_ajax', 'nonce' );
3663 3861
3664 - $html = FrmAppHelper::clip(
3862 + $html = FrmAppHelper::clip(
3665 3863 function () {
3666 3864 FrmAppHelper::maybe_autocomplete_pages_options(
3667 3865 array(
3668 3866 'field_name' => 'frm_page_dropdown',
@@ -3671,18 +3869,48 @@
3671 3869 )
3672 3870 );
3673 3871 }
3674 3872 );
3675 - $post_type_object = get_post_type_object( 'page' );
3676 3873 wp_send_json(
3677 3874 array(
3678 3875 'html' => $html,
3679 - 'edit_page_url' => admin_url( sprintf( $post_type_object->_edit_link . '&action=edit', 0 ) ),
3876 + 'edit_page_url' => admin_url( sprintf( get_post_type_object( 'page' )->_edit_link . '&action=edit', 0 ) ),
3680 3877 )
3681 3878 );
3682 3879 }
3683 3880
3684 3881 /**
3882 + * Prints necessary templates for the forms list page.
3883 + *
3884 + * @since 6.32
3885 + *
3886 + * @return void
3887 + */
3888 + public static function print_forms_list_templates() {
3889 + if ( ! FrmAppHelper::on_form_listing_page() ) {
3890 + return;
3891 + }
3892 +
3893 + $screen = get_current_screen();
3894 +
3895 + if ( ! $screen ) {
3896 + return;
3897 + }
3898 +
3899 + $columns = get_column_headers( $screen );
3900 + $hidden = get_hidden_columns( $screen );
3901 + $skip_cols = array( 'cb', 'name', 'settings' );
3902 + $per_page = get_user_option( 'formidable_page_formidable_per_page' );
3903 + $show_screen_options = $screen->show_screen_options();
3904 +
3905 + if ( $per_page < 1 ) {
3906 + $per_page = 20;
3907 + }
3908 +
3909 + include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/forms-list-settings.php';
3910 + }
3911 +
3912 + /**
3685 3913 * @deprecated 4.0
3686 3914 *
3687 3915 * @param array $values
3688 3916 *
@@ -3690,6 +3918,17 @@
3690 3918 */
3691 3919 public static function create( $values = array() ) {
3692 3920 _deprecated_function( __METHOD__, '4.0', 'FrmFormsController::update' );
3693 3921 self::update( $values );
3922 + }
3923 +
3924 + /**
3925 + * @deprecated 6.33
3926 + *
3927 + * @param array $values
3928 + *
3929 + * @return void
3930 + */
3931 + public static function render_spam_settings( $values ) {
3932 + _deprecated_function( __METHOD__, '6.33' );
3694 3933 }
3695 3934 }