PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.11
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.11
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 / FrmAppController.php

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

1,368 lines 38.2 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 FrmAppController {
7
8 /**
9 * @return void
10 */
11 public static function menu() {
12 FrmAppHelper::maybe_add_permissions();
13 if ( ! current_user_can( 'frm_view_forms' ) ) {
14 return;
15 }
16
17 $menu_name = FrmAppHelper::get_menu_name();
18 add_menu_page( 'Formidable', $menu_name, 'frm_view_forms', 'formidable', 'FrmFormsController::route', self::menu_icon(), self::get_menu_position() );
19 }
20
21 /**
22 * @return int
23 */
24 private static function get_menu_position() {
25 return (int) apply_filters( 'frm_menu_position', 29 );
26 }
27
28 /**
29 * @since 3.05
30 */
31 private static function menu_icon() {
32 $icon = FrmAppHelper::svg_logo(
33 array(
34 'fill' => '#a0a5aa',
35 'orange' => '#a0a5aa',
36 )
37 );
38 $icon = 'data:image/svg+xml;base64,' . base64_encode( $icon );
39
40 return apply_filters( 'frm_icon', $icon );
41 }
42
43 /**
44 * @since 3.0
45 */
46 public static function add_admin_class( $classes ) {
47 if ( self::is_white_page() ) {
48 $classes .= ' frm-white-body ';
49 $classes .= self::get_os();
50
51 $page = str_replace( 'formidable-', '', FrmAppHelper::simple_get( 'page', 'sanitize_title' ) );
52 if ( empty( $page ) || $page === 'formidable' ) {
53 $action = FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
54 if ( in_array( $action, array( 'settings', 'edit', 'list' ) ) ) {
55 $page .= $action;
56 } else {
57 $page = $action;
58 }
59 }
60 if ( ! empty( $page ) ) {
61 $classes .= ' frm-admin-page-' . $page;
62 }
63 }
64
65 if ( self::is_grey_page() ) {
66 $classes .= ' frm-grey-body ';
67 }
68
69 if ( FrmAppHelper::is_full_screen() ) {
70 $full_screen_on = self::get_full_screen_setting();
71 $add_class = '';
72 if ( $full_screen_on ) {
73 $add_class = ' frm-full-screen is-fullscreen-mode';
74
75 // Load the CSS for .is-fullscreen-mode.
76 wp_enqueue_style( 'wp-edit-post' );
77 }
78 $classes .= apply_filters( 'frm_admin_full_screen_class', $add_class );
79 }
80
81 if ( ! FrmAppHelper::pro_is_installed() ) {
82 $classes .= ' frm-lite ';
83 }
84
85 if ( get_user_setting( 'unfold' ) && 'f' !== get_user_setting( 'mfold' ) ) {
86 $classes .= ' frm-unfold ';
87 }
88
89 return $classes;
90 }
91
92 /**
93 * Get the full screen mode setting from the block editor.
94 *
95 * @since 6.1
96 *
97 * @return bool
98 */
99 private static function get_full_screen_setting() {
100 global $wpdb;
101 $meta_key = $wpdb->get_blog_prefix() . 'persisted_preferences';
102
103 $prefs = get_user_meta( get_current_user_id(), $meta_key, true );
104 if ( $prefs && isset( $prefs['core/edit-post']['fullscreenMode'] ) ) {
105 return $prefs['core/edit-post']['fullscreenMode'];
106 }
107
108 return true;
109 }
110
111 /**
112 * @since 4.0
113 *
114 * @return string
115 */
116 private static function get_os() {
117 $agent = strtolower( FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' ) );
118 $os = '';
119 if ( strpos( $agent, 'mac' ) !== false ) {
120 $os = ' osx';
121 } elseif ( strpos( $agent, 'linux' ) !== false ) {
122 $os = ' linux';
123 } elseif ( strpos( $agent, 'windows' ) !== false ) {
124 $os = ' windows';
125 }
126 return $os;
127 }
128
129 /**
130 * @since 3.0
131 */
132 private static function is_white_page() {
133 $white_pages = array(
134 'formidable',
135 'formidable-entries',
136 'formidable-views',
137 'formidable-views-editor',
138 'formidable-pro-upgrade',
139 'formidable-addons',
140 'formidable-import',
141 'formidable-settings',
142 'formidable-styles',
143 'formidable-styles2',
144 'formidable-inbox',
145 FrmFormTemplatesController::PAGE_SLUG,
146 FrmOnboardingWizardController::PAGE_SLUG,
147 );
148
149 if ( ! class_exists( 'FrmTransHooksController', false ) && ! FrmTransLiteAppHelper::should_fallback_to_paypal() ) {
150 // Only consider the payments page as a "white page" when the Payments submodule is off.
151 // Otherwise this causes a lot of styling issues when the Stripe add-on (or Authorize.Net) is active.
152
153 // Add an extra check to avoid white page styling on the PayPal "edit" action.
154 // We fallback to the PayPal add on for the "edit" action since Stripe Lite does not have an edit view.
155 if ( ! in_array( FrmAppHelper::simple_get( 'action' ), array( 'edit', 'new' ), true ) || ! is_callable( 'FrmPaymentsController::route' ) ) {
156 $white_pages[] = 'formidable-payments';
157 }
158 }
159
160 $is_white_page = self::is_page_in_list( $white_pages ) || self::is_grey_page() || FrmAppHelper::is_view_builder_page();
161
162 /**
163 * Allow another add on to style a page as a Formidable "white page", which adds a white background color.
164 *
165 * @since 5.3
166 *
167 * @param bool $is_white_page
168 */
169 $is_white_page = apply_filters( 'frm_is_white_page', $is_white_page );
170
171 return $is_white_page;
172 }
173
174 /**
175 * Add a grey bg instead of white.
176 *
177 * @since 6.8
178 *
179 * @return bool
180 */
181 private static function is_grey_page() {
182 $grey_pages = array(
183 'formidable-applications',
184 'formidable-dashboard',
185 );
186
187 $is_grey_page = self::is_page_in_list( $grey_pages );
188
189 /**
190 * Filter to change FF wrapper background to grey.
191 *
192 * @since 6.8
193 *
194 * @param bool $is_grey_page
195 * @return bool
196 */
197 return apply_filters( 'frm_is_grey_page', $is_grey_page );
198 }
199
200 /**
201 * @since 6.8
202 *
203 * @param array $pages A list of page names to check.
204 * @return bool
205 */
206 private static function is_page_in_list( $pages ) {
207 $get_page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
208 return in_array( $get_page, $pages, true );
209 }
210
211 /**
212 * @return void
213 */
214 public static function load_wp_admin_style() {
215 FrmAppHelper::load_font_style();
216 }
217
218 /**
219 * @param int|object $form
220 * @param bool $show_nav
221 * @param string $title
222 *
223 * @psalm-param 'hide'|'show' $title
224 *
225 * @return void
226 */
227 public static function get_form_nav( $form, $show_nav = false, $title = 'show' ) {
228 $show_nav = FrmAppHelper::get_param( 'show_nav', $show_nav, 'get', 'absint' );
229 if ( empty( $show_nav ) || ! $form ) {
230 return;
231 }
232
233 FrmForm::maybe_get_form( $form );
234 if ( ! is_object( $form ) ) {
235 return;
236 }
237
238 $id = $form->id;
239 $current_page = self::get_current_page();
240 $nav_items = self::get_form_nav_items( $form );
241
242 include FrmAppHelper::plugin_path() . '/classes/views/shared/form-nav.php';
243 }
244
245 /**
246 * @return string
247 */
248 private static function get_current_page() {
249 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
250 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title', 'None' );
251 $current_page = isset( $_GET['page'] ) ? $page : $post_type;
252
253 if ( FrmAppHelper::is_view_builder_page() ) {
254 $current_page = 'frm_display';
255 }
256
257 return $current_page;
258 }
259
260 /**
261 * @param object $form
262 * @return array
263 */
264 private static function get_form_nav_items( $form ) {
265 $id = $form->parent_form_id ? $form->parent_form_id : $form->id;
266
267 $nav_items = array(
268 array(
269 'link' => FrmForm::get_edit_link( $id ),
270 'label' => __( 'Build', 'formidable' ),
271 'current' => array( 'edit', 'new', 'duplicate' ),
272 'page' => 'formidable',
273 'permission' => 'frm_edit_forms',
274 ),
275 array(
276 'link' => FrmStylesHelper::get_list_url( $id ),
277 'label' => __( 'Style', 'formidable' ),
278 'current' => array(),
279 'page' => 'formidable-styles',
280 'permission' => 'frm_edit_forms',
281 ),
282 array(
283 'link' => admin_url( 'admin.php?page=formidable&frm_action=settings&id=' . absint( $id ) ),
284 'label' => __( 'Settings', 'formidable' ),
285 'current' => array( 'settings' ),
286 'page' => 'formidable',
287 'permission' => 'frm_edit_forms',
288 ),
289 array(
290 'link' => admin_url( 'admin.php?page=formidable-entries&frm_action=list&form=' . absint( $id ) ),
291 'label' => __( 'Entries', 'formidable' ),
292 'current' => array(),
293 'page' => 'formidable-entries',
294 'permission' => 'frm_view_entries',
295 ),
296 );
297
298 $views_installed = is_callable( 'FrmProAppHelper::views_is_installed' ) ? FrmProAppHelper::views_is_installed() : FrmAppHelper::pro_is_installed();
299
300 if ( ! $views_installed ) {
301 $nav_items[] = array(
302 'link' => admin_url( 'admin.php?page=formidable-views&form=' . absint( $id ) ),
303 'label' => __( 'Views', 'formidable' ),
304 'current' => array(),
305 'page' => 'formidable-views',
306 'permission' => 'frm_view_entries',
307 'atts' => array(
308 'class' => 'frm_noallow',
309 ),
310 );
311 }
312
313 // Let people know reports and views exist.
314 if ( ! FrmAppHelper::pro_is_installed() ) {
315 $nav_items[] = array(
316 'link' => admin_url( 'admin.php?page=formidable&frm_action=lite-reports&form=' . absint( $id ) ),
317 'label' => __( 'Reports', 'formidable' ),
318 'current' => array( 'reports' ),
319 'page' => 'formidable',
320 'permission' => 'frm_view_entries',
321 'atts' => array(
322 'class' => 'frm_noallow',
323 ),
324 );
325 }
326
327 $nav_args = array(
328 'form_id' => $id,
329 'form' => $form,
330 );
331
332 return (array) apply_filters( 'frm_form_nav_list', $nav_items, $nav_args );
333 }
334
335 // Adds a settings link to the plugins page
336 /**
337 * @return array
338 */
339 public static function settings_link( $links ) {
340 $settings = array();
341
342 if ( ! FrmAppHelper::pro_is_installed() ) {
343 $label = FrmAddonsController::is_license_expired() ? __( 'Renew', 'formidable' ) : __( 'Upgrade to Pro', 'formidable' );
344 $settings[] = '<a href="' . esc_url( FrmAppHelper::admin_upgrade_link( 'plugin-row' ) ) . '" target="_blank" rel="noopener"><b style="color:#1da867;font-weight:700;">' . esc_html( $label ) . '</b></a>';
345 }
346
347 $settings[] = '<a href="' . esc_url( admin_url( 'admin.php?page=formidable' ) ) . '">' . __( 'Build a Form', 'formidable' ) . '</a>';
348
349 return array_merge( $settings, $links );
350 }
351
352 /**
353 * @return void
354 */
355 public static function pro_get_started_headline() {
356 self::review_request();
357 FrmAppHelper::min_pro_version_notice( '4.0' );
358 }
359
360 /**
361 * Add admin notices as needed for reviews
362 *
363 * @since 3.04.03
364 *
365 * @return void
366 */
367 private static function review_request() {
368 $reviews = new FrmReviews();
369 $reviews->review_request();
370 }
371
372 /**
373 * Save the request to hide the review
374 *
375 * @since 3.04.03
376 *
377 * @return void
378 */
379 public static function dismiss_review() {
380 FrmAppHelper::permission_check( 'frm_change_settings' );
381 check_ajax_referer( 'frm_ajax', 'nonce' );
382
383 $reviews = new FrmReviews();
384 $reviews->dismiss_review();
385 }
386
387 /**
388 * @since 3.04.02
389 *
390 * @return void
391 */
392 public static function include_upgrade_overlay() {
393 self::enqueue_dialog_assets();
394 add_action( 'admin_footer', 'FrmAppController::upgrade_overlay_html' );
395 }
396
397 /**
398 * Enqueue scripts and styles required for modals.
399 *
400 * @since 5.3
401 *
402 * @return void
403 */
404 public static function enqueue_dialog_assets() {
405 wp_enqueue_script( 'jquery-ui-dialog' );
406 wp_enqueue_style( 'jquery-ui-dialog' );
407 }
408
409 /**
410 * @since 3.06.03
411 *
412 * @return void
413 */
414 public static function upgrade_overlay_html() {
415 $is_pro = FrmAppHelper::pro_is_installed();
416 $upgrade_link = array(
417 'medium' => 'builder',
418 'content' => 'upgrade',
419 );
420 $default_link = FrmAppHelper::admin_upgrade_link( $upgrade_link );
421 $plugin_path = FrmAppHelper::plugin_path();
422 $shared_path = $plugin_path . '/classes/views/shared/';
423
424 include $shared_path . 'upgrade_overlay.php';
425 include $shared_path . 'confirm-overlay.php';
426 }
427
428 /**
429 * Create a basic form with an email field.
430 *
431 * @param string $form_key
432 * @param string $title
433 * @param string $description
434 * @return void
435 */
436 public static function api_email_form( $form_key, $title = '', $description = '' ) {
437 $user = wp_get_current_user();
438 $args = array(
439 'api_url' => 'https://sandbox.formidableforms.com/api/wp-json/frm/v2/forms/' . $form_key . '?return=html&exclude_script=jquery&exclude_style=formidable-css',
440 'title' => $title,
441 'description' => $description,
442 );
443 require FrmAppHelper::plugin_path() . '/classes/views/form-templates/modals/leave-email-modal.php';
444 }
445
446 /**
447 * @return void
448 */
449 public static function include_info_overlay() {
450 self::enqueue_dialog_assets();
451 add_action( 'admin_footer', 'FrmAppController::info_overlay_html' );
452 }
453
454 /**
455 * @return void
456 */
457 public static function info_overlay_html() {
458 include FrmAppHelper::plugin_path() . '/classes/views/shared/info-overlay.php';
459 }
460
461 /**
462 * @since 3.04.02
463 *
464 * @return void
465 */
466 public static function remove_upsells() {
467 remove_action( 'frm_before_settings', 'FrmSettingsController::license_box' );
468 remove_action( 'frm_after_settings', 'FrmSettingsController::settings_cta' );
469 remove_action( 'frm_add_form_style_tab_options', 'FrmFormsController::add_form_style_tab_options' );
470 remove_action( 'frm_after_field_options', 'FrmFormsController::logic_tip' );
471 }
472
473 /**
474 * If there are CURL problems on this server, wp_remote_post won't work for installing
475 * Use a javascript fallback instead.
476 *
477 * @since 2.0.3
478 *
479 * @return void
480 */
481 public static function install_js_fallback() {
482 FrmAppHelper::load_admin_wide_js();
483 ?>
484 <div id="frm_install_message"></div>
485 <script>jQuery(document).ready( frm_install_now );</script>
486 <?php
487 }
488
489 /**
490 * Check if the database is outdated
491 *
492 * @since 2.0.1
493 * @return bool
494 */
495 public static function needs_update() {
496 $needs_upgrade = self::compare_for_update(
497 array(
498 'option' => 'frm_db_version',
499 'new_db_version' => FrmAppHelper::$db_version,
500 'new_plugin_version' => FrmAppHelper::plugin_version(),
501 )
502 );
503
504 if ( ! $needs_upgrade ) {
505 $needs_upgrade = apply_filters( 'frm_db_needs_upgrade', $needs_upgrade );
506 }
507
508 return $needs_upgrade;
509 }
510
511 /**
512 * Check both version number and DB number for changes
513 *
514 * @since 3.0.04
515 *
516 * @param array $atts
517 * @return bool
518 */
519 public static function compare_for_update( $atts ) {
520 $db_version = get_option( $atts['option'] );
521
522 if ( strpos( $db_version, '-' ) === false ) {
523 $needs_upgrade = true;
524 } else {
525 $last_upgrade = explode( '-', $db_version );
526 $needs_db_upgrade = (int) $last_upgrade[1] < (int) $atts['new_db_version'];
527 $new_version = version_compare( $last_upgrade[0], $atts['new_plugin_version'], '<' );
528 $needs_upgrade = $needs_db_upgrade || $new_version;
529 }
530
531 return $needs_upgrade;
532 }
533
534 /**
535 * Check for database update and trigger js loading
536 *
537 * @since 2.0.1
538 *
539 * @return void
540 */
541 public static function admin_init() {
542 if ( FrmAppHelper::get_param( 'delete_all' ) && FrmAppHelper::is_admin_page( 'formidable' ) && 'trash' === FrmAppHelper::get_param( 'form_type' ) ) {
543 FrmFormsController::delete_all();
544 }
545
546 if ( FrmAppHelper::is_admin_page( 'formidable' ) && 'duplicate' === FrmAppHelper::get_param( 'frm_action' ) ) {
547 FrmFormsController::duplicate();
548 }
549
550 if ( FrmAppHelper::is_style_editor_page() && 'save' === FrmAppHelper::get_param( 'frm_action' ) ) {
551 // Hook in earlier than FrmStylesController::route so we can redirect before the headers have been sent.
552 FrmStylesController::save_style();
553 }
554
555 // Register personal data hooks.
556 new FrmPersonalData();
557
558 if ( ! FrmAppHelper::doing_ajax() && self::needs_update() ) {
559 self::network_upgrade_site();
560 }
561
562 if ( ! FrmAppHelper::doing_ajax() ) {
563 // don't continue during ajax calls
564 self::admin_js();
565 }
566
567 self::trigger_page_load_hooks();
568
569 if ( FrmAppHelper::is_admin_page( 'formidable' ) ) {
570 // Redirect to the "Form Templates" page if the 'frm_action' parameter matches specific actions.
571 // This provides backward compatibility for old addons that use legacy modal templates.
572 $action = FrmAppHelper::get_param( 'frm_action' );
573 $trigger_name_modal = FrmAppHelper::get_param( 'triggerNewFormModal' );
574 if ( $trigger_name_modal || in_array( $action, array( 'add_new', 'list_templates' ), true ) ) {
575 $application_id = FrmAppHelper::simple_get( 'applicationId', 'absint' );
576 $url_param = $application_id ? '&applicationId=' . $application_id : '';
577
578 wp_safe_redirect( admin_url( 'admin.php?page=' . FrmFormTemplatesController::PAGE_SLUG . $url_param ) );
579 exit;
580 }
581
582 FrmInbox::maybe_disable_screen_options();
583 }
584
585 self::maybe_add_ip_warning();
586 self::maybe_add_deprecated_message();
587 }
588
589 /**
590 * Get the current page and check for a possible function to trigger.
591 * If a class name matches the page name, and the class has a load_page() method, trigger it.
592 *
593 * @since 6.8
594 *
595 * @return void
596 */
597 private static function trigger_page_load_hooks() {
598 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
599 if ( strpos( $page, 'formidable-' ) !== 0 ) {
600 // Only trigger hooks on Formidable pages.
601 return;
602 }
603
604 $page = str_replace( array( 'formidable-', '-' ), array( '', ' ' ), $page );
605 $page = str_replace( ' ', '', ucwords( $page ) );
606 $class = 'Frm' . $page . 'Controller';
607 if ( class_exists( $class ) && method_exists( $class, 'load_page' ) ) {
608 call_user_func( array( $class, 'load_page' ) );
609 }
610 }
611
612 /**
613 * Show a warning for the IP address setting if it hasn't been set.
614 *
615 * @since 6.1
616 *
617 * @return void
618 */
619 private static function maybe_add_ip_warning() {
620 $settings = FrmAppHelper::get_settings();
621 if ( false !== $settings->custom_header_ip ) {
622 // The setting has been changed from the false default (to either 1 or 0), so stop showing the message.
623 return;
624 }
625
626 if ( ! self::is_behind_proxy() ) {
627 // This message is only applicable when using a reverse proxy.
628 return;
629 }
630
631 if ( FrmAppHelper::get_post_param( 'frm_action', '', 'sanitize_text_field' ) ) {
632 // Avoid the message on a POST action. We don't want to show the message if we're saving global settings.
633 return;
634 }
635
636 $global_settings_link = admin_url( 'admin.php?page=formidable-settings' ) . '#frm_custom_header_ip';
637 $message = sprintf(
638 // Translators: 1: Global Settings Link
639 __( 'IP addresses in form submissions may no longer be accurate! If you are experiencing issues, we recommend going to %1$s and enabling the "Use custom headers when retrieving IPs with form submissions." setting.', 'formidable' ),
640 '<a href="' . esc_url( $global_settings_link ) . '">' . __( 'Global Settings', 'formidable' ) . '</a>'
641 );
642 $option_name = 'frm_dismiss_ip_address_notice';
643 FrmAppHelper::add_dismissable_warning_message( $message, $option_name );
644 }
645
646 /**
647 * Check if any reverse proxy headers are set.
648 *
649 * @since 6.1
650 *
651 * @return bool
652 */
653 private static function is_behind_proxy() {
654 $custom_headers = FrmAppHelper::get_custom_header_keys_for_ip();
655 foreach ( $custom_headers as $header ) {
656 if ( 'REMOTE_ADDR' === $header ) {
657 // We want to check every key but REMOTE_ADDR. REMOTE_ATTR is not unique to reverse proxy servers.
658 continue;
659 }
660
661 $ip = trim( FrmAppHelper::get_server_value( $header ) );
662 // Return true for anything that isn't empty but ignoring values like ::1.
663 if ( $ip && 0 !== strpos( $ip, '::' ) ) {
664 return true;
665 }
666 }
667
668 return false;
669 }
670
671 /**
672 * @return void
673 */
674 public static function admin_js() {
675 $plugin_url = FrmAppHelper::plugin_url();
676 $version = FrmAppHelper::plugin_version();
677
678 FrmAppHelper::load_admin_wide_js();
679
680 // Register component assets early to ensure they can be enqueued later in controllers.
681 wp_register_style( 'formidable-animations', $plugin_url . '/css/admin/animations.css', array(), $version );
682
683 if ( class_exists( 'FrmOverlayController' ) ) {
684 // This should always exist.
685 // But it may not have loaded properly when updating the plugin.
686 FrmOverlayController::register_assets();
687 }
688
689 wp_register_style( 'formidable_admin_global', $plugin_url . '/css/admin/frm_admin_global.css', array(), $version );
690 wp_enqueue_style( 'formidable_admin_global' );
691
692 wp_register_style( 'formidable-admin', $plugin_url . '/css/frm_admin.css', array(), $version );
693 wp_register_style( 'formidable-grids', $plugin_url . '/css/frm_grids.css', array(), $version );
694
695 wp_register_script( 'formidable_dom', $plugin_url . '/js/admin/dom.js', array( 'jquery', 'jquery-ui-dialog', 'wp-i18n' ), $version, true );
696 wp_register_script( 'formidable_embed', $plugin_url . '/js/admin/embed.js', array( 'formidable_dom', 'jquery-ui-autocomplete' ), $version, true );
697 self::register_popper1();
698 wp_register_script( 'bootstrap_tooltip', $plugin_url . '/js/bootstrap.min.js', array( 'jquery', 'popper' ), '4.6.1', true );
699 wp_register_script( 'formidable_settings', $plugin_url . '/js/admin/settings.js', array(), $version, true );
700
701 if ( self::should_show_floating_links() ) {
702 self::enqueue_floating_links( $plugin_url, $version );
703 }
704
705 $dependencies = array(
706 'formidable_admin_global',
707 'jquery',
708 'jquery-ui-core',
709 'jquery-ui-draggable',
710 'jquery-ui-sortable',
711 'bootstrap_tooltip',
712 'bootstrap-multiselect',
713 'wp-i18n',
714 // Required in WP versions older than 5.7
715 'wp-hooks',
716 'formidable_dom',
717 'formidable_embed',
718 );
719
720 if ( FrmAppHelper::is_style_editor_page( 'edit' ) ) {
721 // We only need to load the color picker when editing styles.
722 $dependencies[] = 'wp-color-picker';
723 }
724
725 wp_register_script( 'formidable_admin', $plugin_url . '/js/formidable_admin.js', $dependencies, $version, true );
726
727 if ( FrmAppHelper::on_form_listing_page() ) {
728 // For the existing page dropdown in the Form embed modal.
729 wp_enqueue_script( 'jquery-ui-autocomplete' );
730 }
731
732 wp_register_script( 'bootstrap-multiselect', $plugin_url . '/js/bootstrap-multiselect.js', array( 'jquery', 'bootstrap_tooltip', 'popper' ), '1.1.1', true );
733
734 if ( ! class_exists( 'FrmTransHooksController', false ) ) {
735 /**
736 * Gateway fields are included for add-on compatibility but we do not want it to be visible.
737 * They do however need to be visible when the payments submodule is active.
738 */
739 wp_add_inline_style(
740 'formidable-admin',
741 '#frm_builder_page li[data-ftype="gateway"] { display: none; }'
742 );
743 }
744
745 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
746 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
747
748 global $pagenow;
749 if ( strpos( $page, 'formidable' ) === 0 || ( $pagenow === 'edit.php' && $post_type === 'frm_display' ) ) {
750
751 wp_enqueue_script( 'admin-widgets' );
752 wp_enqueue_style( 'widgets' );
753 self::maybe_deregister_popper2();
754 wp_enqueue_script( 'formidable_admin' );
755 wp_enqueue_script( 'formidable_embed' );
756 FrmAppHelper::localize_script( 'admin' );
757
758 wp_enqueue_style( 'formidable-animations' );
759 wp_enqueue_style( 'formidable-admin' );
760 if ( 'formidable-styles' !== $page && 'formidable-styles2' !== $page ) {
761 wp_enqueue_style( 'formidable-grids' );
762 self::maybe_enqueue_dropzone_css( $page );
763 } else {
764 wp_enqueue_style( 'formidable-grids' );
765 }
766
767 if ( 'formidable-entries' === $page ) {
768 // Load front end js for entries.
769 wp_enqueue_script( 'formidable' );
770
771 // Registers and enqueues the entries page scripts.
772 wp_register_script( 'formidable_entries', $plugin_url . '/js/admin/entries.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
773 wp_enqueue_script( 'formidable_entries' );
774 }
775
776 do_action( 'frm_enqueue_builder_scripts' );
777 self::include_upgrade_overlay();
778 self::include_info_overlay();
779 } elseif ( FrmAppHelper::is_view_builder_page() ) {
780 if ( isset( $_REQUEST['post_type'] ) ) {
781 $post_type = sanitize_title( wp_unslash( $_REQUEST['post_type'] ) );
782 } elseif ( isset( $_REQUEST['post'] ) && absint( $_REQUEST['post'] ) ) {
783 $post = get_post( absint( wp_unslash( $_REQUEST['post'] ) ) );
784 if ( ! $post ) {
785 return;
786 }
787 $post_type = $post->post_type;
788 } else {
789 return;
790 }
791
792 if ( $post_type === 'frm_display' ) {
793 self::enqueue_legacy_views_assets();
794 }
795 }//end if
796
797 if ( 'formidable-addons' === $page ) {
798 wp_register_script( 'formidable_addons', $plugin_url . '/js/admin/addons.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
799 wp_enqueue_script( 'formidable_addons' );
800 }
801 }
802
803 /**
804 * Avoid loading dropzone CSS on the form list page. It isn't required there.
805 *
806 * @since 6.11
807 *
808 * @param string $page
809 * @return void
810 */
811 private static function maybe_enqueue_dropzone_css( $page ) {
812 if ( ! FrmAppHelper::pro_is_installed() ) {
813 return;
814 }
815
816 $should_avoid_loading_dropzone = 'formidable' === $page && ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
817 if ( ! $should_avoid_loading_dropzone ) {
818 wp_enqueue_style( 'formidable-dropzone' );
819 }
820 }
821
822 /**
823 * The floating links are not shown on every page.
824 * They are also not shown if white labeling is being used.
825 *
826 * @since 6.8.4
827 *
828 * @return bool
829 */
830 private static function should_show_floating_links() {
831 if ( ! FrmAppHelper::is_formidable_branding() ) {
832 return false;
833 }
834
835 return FrmAppHelper::is_formidable_admin() &&
836 ! FrmAppHelper::is_style_editor_page() &&
837 ! FrmAppHelper::is_admin_page( 'formidable-views-editor' ) &&
838 ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
839 }
840
841 /**
842 * @since 6.3.2
843 *
844 * @return void
845 */
846 public static function admin_enqueue_scripts() {
847 self::load_wp_admin_style();
848 self::maybe_force_formidable_block_on_gutenberg_page();
849 }
850
851 /**
852 * Enqueue required assets for the Legacy Views editor (Views v4.x).
853 *
854 * @since 6.1.2
855 *
856 * @return void
857 */
858 private static function enqueue_legacy_views_assets() {
859 wp_enqueue_style( 'formidable-grids' );
860 wp_enqueue_script( 'jquery-ui-draggable' );
861 self::maybe_deregister_popper2();
862 wp_enqueue_script( 'formidable_admin' );
863 wp_add_inline_style(
864 'formidable-admin',
865 '
866 .frm-white-body.post-type-frm_display .columns-2 {
867 display: block;
868 overflow: visible;
869 }
870
871 .frm-white-body.post-type-frm_display .columns-2 > div {
872 overflow-y: hidden;
873 }
874
875 .frm-white-body.post-type-frm_display #titlediv #title-prompt-text {
876 padding: 3px 0 0 10px;
877 }
878
879 .post-type-frm_display #field-search-input,
880 .post-type-frm_display #advanced-search-input {
881 flex: 1;
882 }
883 '
884 );
885 wp_enqueue_style( 'formidable-admin' );
886 FrmAppHelper::localize_script( 'admin' );
887 self::include_info_overlay();
888 }
889
890 /**
891 * Fix a Duplicator Pro conflict because it uses Popper 2. See issue #3459.
892 *
893 * @since 5.2.02.01
894 *
895 * @return void
896 */
897 private static function maybe_deregister_popper2() {
898 global $wp_scripts;
899
900 if ( ! array_key_exists( 'popper', $wp_scripts->registered ) ) {
901 return;
902 }
903
904 $popper = $wp_scripts->registered['popper'];
905 if ( version_compare( $popper->ver, '2.0', '>=' ) ) {
906 wp_deregister_script( 'popper' );
907 self::register_popper1();
908 }
909 }
910
911 /**
912 * Register Popper required for Bootstrap 4.
913 *
914 * @since 5.2.02.01
915 *
916 * @return void
917 */
918 private static function register_popper1() {
919 wp_register_script( 'popper', FrmAppHelper::plugin_url() . '/js/popper.min.js', array( 'jquery' ), '1.16.0', true );
920 }
921
922 /**
923 * Automatically insert a Formidable block when loading Gutenberg when $_GET['frmForm' is set.
924 *
925 * @since 5.2
926 *
927 * @return void
928 */
929 private static function maybe_force_formidable_block_on_gutenberg_page() {
930 global $pagenow;
931 if ( 'post.php' !== $pagenow ) {
932 return;
933 }
934
935 $form_id = FrmAppHelper::simple_get( 'frmForm', 'absint' );
936 if ( ! $form_id ) {
937 return;
938 }
939
940 self::add_js_to_inject_gutenberg_block( 'formidable/simple-form', 'formId', $form_id );
941 }
942
943 /**
944 * @since 5.3
945 *
946 * @param string $block_name
947 * @param string $object_key
948 * @param array|string $object_id
949 *
950 * @return void
951 */
952 public static function add_js_to_inject_gutenberg_block( $block_name, $object_key, $object_id ) {
953 require FrmAppHelper::plugin_path() . '/classes/views/shared/edit-page-js.php';
954 }
955
956 /**
957 * @return void
958 */
959 public static function load_lang() {
960 load_plugin_textdomain( 'formidable', false, FrmAppHelper::plugin_folder() . '/languages/' );
961 }
962
963 /**
964 * Check if the styles are updated when a form is loaded on the front-end
965 *
966 * @since 3.0.1
967 *
968 * @return void
969 */
970 public static function maybe_update_styles() {
971 if ( self::needs_update() ) {
972 self::network_upgrade_site();
973 }
974 }
975
976 /**
977 * @since 3.0
978 *
979 * @return void
980 */
981 public static function create_rest_routes() {
982 $args = array(
983 'methods' => 'GET',
984 'callback' => 'FrmAppController::api_install',
985 'permission_callback' => __CLASS__ . '::can_update_db',
986 );
987
988 register_rest_route( 'frm-admin/v1', '/install', $args );
989
990 $args = array(
991 'methods' => 'GET',
992 'callback' => 'FrmAddonsController::install_addon_api',
993 'permission_callback' => 'FrmAddonsController::can_install_addon_api',
994 );
995
996 register_rest_route( 'frm-admin/v1', '/install-addon', $args );
997 }
998
999 /**
1000 * Make sure the install is only being run when we tell it to.
1001 * We don't want to run manually by people calling the API.
1002 *
1003 * @since 4.06.02
1004 */
1005 public static function can_update_db() {
1006 return get_transient( 'frm_updating_api' );
1007 }
1008
1009 /**
1010 * Run silent upgrade on each site in the network during a network upgrade.
1011 * Update database settings for all sites in a network during network upgrade process.
1012 *
1013 * @since 2.0.1
1014 *
1015 * @param int $blog_id Blog ID.
1016 *
1017 * @return void
1018 */
1019 public static function network_upgrade_site( $blog_id = 0 ) {
1020 // Flag to check if install is happening as intended.
1021 set_transient( 'frm_updating_api', true, MINUTE_IN_SECONDS );
1022 $request = new WP_REST_Request( 'GET', '/frm-admin/v1/install' );
1023
1024 self::maybe_add_wp_site_health();
1025
1026 if ( $blog_id ) {
1027 switch_to_blog( $blog_id );
1028 $response = rest_do_request( $request );
1029 restore_current_blog();
1030 } else {
1031 $response = rest_do_request( $request );
1032 }
1033
1034 if ( $response->is_error() ) {
1035 // if the remove post fails, use javascript instead
1036 add_action( 'admin_notices', 'FrmAppController::install_js_fallback' );
1037 }
1038 }
1039
1040 /**
1041 * Make sure WP_Site_Health has been included because it is required when calling rest_do_request.
1042 * Check first that the file exists because WP_Site_Health was only introduced in WordPress 5.2.
1043 *
1044 * @return void
1045 */
1046 private static function maybe_add_wp_site_health() {
1047 if ( ! class_exists( 'WP_Site_Health' ) ) {
1048 $wp_site_health_path = ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
1049 if ( file_exists( $wp_site_health_path ) ) {
1050 require_once $wp_site_health_path;
1051 }
1052 }
1053 }
1054
1055 /**
1056 * @since 3.0
1057 *
1058 * @return true
1059 */
1060 public static function api_install() {
1061 delete_transient( 'frm_updating_api' );
1062 if ( self::needs_update() ) {
1063 $running = get_option( 'frm_install_running' );
1064 if ( false === $running || $running < strtotime( '-5 minutes' ) ) {
1065 update_option( 'frm_install_running', time(), 'no' );
1066 self::install();
1067 delete_option( 'frm_install_running' );
1068 }
1069 }
1070
1071 return true;
1072 }
1073
1074 /**
1075 * Silent database upgrade (no redirect).
1076 * Called via ajax request during network upgrade process.
1077 *
1078 * @since 2.0.1
1079 *
1080 * @return void
1081 */
1082 public static function ajax_install() {
1083 FrmAppHelper::permission_check( 'frm_change_settings' );
1084 check_ajax_referer( 'frm_ajax', 'nonce' );
1085 self::api_install();
1086 wp_die();
1087 }
1088
1089 /**
1090 * @return void
1091 */
1092 public static function install() {
1093 $frmdb = new FrmMigrate();
1094 $frmdb->upgrade();
1095 }
1096
1097 /**
1098 * @return void
1099 */
1100 public static function uninstall() {
1101 FrmAppHelper::permission_check( 'administrator' );
1102 check_ajax_referer( 'frm_ajax', 'nonce' );
1103
1104 $frmdb = new FrmMigrate();
1105 $frmdb->uninstall();
1106
1107 // Disable the plugin and redirect after uninstall so the tables don't get added right back.
1108 $plugins = array( FrmAppHelper::plugin_folder() . '/formidable.php', 'formidable-pro/formidable-pro.php' );
1109 deactivate_plugins( $plugins, false, false );
1110 echo esc_url_raw( admin_url( 'plugins.php?deactivate=true' ) );
1111
1112 wp_die();
1113 }
1114
1115 public static function drop_tables( $tables ) {
1116 global $wpdb;
1117 $tables[] = $wpdb->prefix . 'frm_fields';
1118 $tables[] = $wpdb->prefix . 'frm_forms';
1119 $tables[] = $wpdb->prefix . 'frm_items';
1120 $tables[] = $wpdb->prefix . 'frm_item_metas';
1121
1122 return $tables;
1123 }
1124
1125 /**
1126 * @return void
1127 */
1128 public static function deauthorize() {
1129 FrmAppHelper::permission_check( 'frm_change_settings' );
1130 check_ajax_referer( 'frm_ajax', 'nonce' );
1131
1132 delete_option( 'frmpro-credentials' );
1133 delete_option( 'frmpro-authorized' );
1134 delete_site_option( 'frmpro-credentials' );
1135 delete_site_option( 'frmpro-authorized' );
1136 wp_die();
1137 }
1138
1139 /**
1140 * This is triggered when Formidable is activated.
1141 *
1142 * @return void
1143 */
1144 public static function handle_activation() {
1145 self::maybe_activate_payment_cron();
1146 }
1147
1148 /**
1149 * The payment cron is unscheduled when Formidable is deactivated.
1150 * We need to add it back again on activation if Stripe is configured.
1151 *
1152 * @since 6.5
1153 *
1154 * @return void
1155 */
1156 private static function maybe_activate_payment_cron() {
1157 if ( ! FrmStrpLiteConnectHelper::stripe_connect_is_setup() ) {
1158 return;
1159 }
1160
1161 FrmTransLiteAppController::maybe_schedule_cron();
1162 }
1163
1164 public static function set_footer_text( $text ) {
1165 if ( FrmAppHelper::is_formidable_admin() ) {
1166 $text = '';
1167 }
1168
1169 return $text;
1170 }
1171
1172 /**
1173 * Add admin footer links.
1174 *
1175 * @since 6.4.1
1176 *
1177 * @return void
1178 */
1179 public static function add_admin_footer_links() {
1180 if ( self::should_show_footer_links() ) {
1181 include FrmAppHelper::plugin_path() . '/classes/views/shared/admin-footer-links.php';
1182 }
1183 }
1184
1185 /**
1186 * Check if the footer links should be shown.
1187 *
1188 * @since 6.7
1189 *
1190 * @return bool
1191 */
1192 private static function should_show_footer_links() {
1193 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
1194 $is_formidable_page = FrmAppHelper::is_formidable_admin() || 'frm_logs' === $post_type;
1195 $show_footer_links = $is_formidable_page;
1196 if ( FrmAppHelper::is_full_screen() || ! FrmAppHelper::is_formidable_branding() ) {
1197 $show_footer_links = false;
1198 }
1199
1200 /**
1201 * Filter whether to show the Formidable footer links.
1202 *
1203 * @since 6.7
1204 *
1205 * @param bool $show_footer_links
1206 * @return bool
1207 */
1208 return apply_filters( 'frm_show_footer_links', $show_footer_links );
1209 }
1210
1211 /**
1212 * Show an error modal and terminate the script execution.
1213 *
1214 * @since 6.7
1215 *
1216 * @param array $error_args Arguments that control the behavior of the error modal.
1217 *
1218 * @return void
1219 */
1220 public static function show_error_modal( $error_args ) {
1221 $defaults = array(
1222 'title' => '',
1223 'body' => '',
1224 'cancel_url' => '',
1225 'cancel_classes' => '',
1226 'continue_url' => '',
1227 'continue_classes' => '',
1228 'icon' => 'frm_lock_simple',
1229 );
1230
1231 $error_args = wp_parse_args( $error_args, $defaults );
1232 if ( ! isset( $error_args['cancel_text'] ) && ! empty( $error_args['cancel_url'] ) ) {
1233 $error_args['cancel_text'] = __( 'Cancel', 'formidable' );
1234 }
1235
1236 if ( ! isset( $error_args['continue_text'] ) && ! empty( $error_args['continue_url'] ) ) {
1237 $error_args['continue_text'] = __( 'Continue', 'formidable' );
1238 }
1239
1240 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/error-modal.php';
1241 }
1242
1243 /**
1244 * Handles Floating Links' scripts and styles enqueueing.
1245 *
1246 * @since 6.4
1247 *
1248 * @param string $plugin_url URL of the plugin.
1249 * @param string $version Current version of the plugin.
1250 * @return void
1251 */
1252 private static function enqueue_floating_links( $plugin_url, $version ) {
1253 if ( ! $plugin_url || ! $version ) {
1254 // If any required parameters are missing, exit early.
1255 return;
1256 }
1257
1258 // Enqueue the Floating Links styles.
1259 wp_enqueue_style( 's11-floating-links', $plugin_url . '/css/packages/s11-floating-links.css', array(), $version );
1260
1261 // Enqueue the Floating Links script.
1262 wp_enqueue_script( 's11-floating-links', $plugin_url . '/js/packages/floating-links/s11-floating-links.js', array(), $version, true );
1263
1264 // Enqueue the config script.
1265 wp_enqueue_script( 's11-floating-links-config', $plugin_url . '/js/packages/floating-links/config.js', array( 'wp-i18n' ), $version, true );
1266
1267 if ( function_exists( 'wp_set_script_translations' ) ) {
1268 wp_set_script_translations( 's11-floating-links-config', 's11-' );
1269 }
1270
1271 $floating_links_data = array(
1272 'proIsInstalled' => FrmAppHelper::pro_is_installed(),
1273 );
1274 wp_localize_script( 's11-floating-links-config', 's11FloatingLinksData', $floating_links_data );
1275
1276 /**
1277 * Prompt Pro to load additional floating links scripts.
1278 * This is used to include images in the Inbox SlideIn when Pro is active.
1279 *
1280 * @since 6.8.4
1281 */
1282 do_action( 'frm_enqueue_floating_links' );
1283 }
1284
1285 /**
1286 * @return void
1287 */
1288 private static function maybe_add_deprecated_message() {
1289 $settings = FrmAppHelper::get_settings();
1290
1291 if ( ! empty( $settings->use_html ) ) {
1292 // Dont' show a message if Use HTML 5 is already enabled.
1293 return;
1294 }
1295
1296 if ( FrmAppHelper::is_admin_page( 'formidable-settings' ) ) {
1297 add_action(
1298 'frm_update_settings',
1299 function ( $params ) {
1300 if ( ! empty( $params['frm_use_html'] ) ) {
1301 $inbox = new FrmInbox();
1302 $inbox->dismiss( 'deprecated_use_html' );
1303 }
1304 }
1305 );
1306 // Don't show the message on global settings.
1307 return;
1308 }
1309
1310 $url = admin_url( 'admin.php?page=formidable-settings&t=misc_settings' );
1311
1312 add_filter(
1313 'frm_message_list',
1314 /**
1315 * @param array $messages
1316 * @return array
1317 */
1318 function ( $messages ) use ( $url ) {
1319 $messages[] = '<p>The option to use HTML5 in forms is currently disabled. In a future release, this setting will be removed and using HTML5 will be a requirement. <a href="' . esc_url( $url ) . '">Click here to enable it in Global Settings now</a>.</p>';
1320 return $messages;
1321 }
1322 );
1323
1324 $inbox = new FrmInbox();
1325 $inbox->add_message(
1326 array(
1327 'key' => 'deprecated_use_html',
1328 'force' => true,
1329 'subject' => 'The option to use HTML5 in forms will soon be removed',
1330 'message' => 'The option to use HTML5 in forms is currently disabled. In a future release, this setting will be removed and using HTML5 will be a requirement.',
1331 'icon' => 'frm_report_problem_icon',
1332 'cta' => '<a class="button-secondary frm-button-secondary" href="' . esc_url( $url ) . '">Enable in Global Settings</a>',
1333 )
1334 );
1335 }
1336
1337 /**
1338 * Include icons on page for Embed Form modal.
1339 *
1340 * @since 5.2
1341 *
1342 * @return void
1343 */
1344 public static function include_embed_form_icons() {
1345 _deprecated_function( __METHOD__, '5.3' );
1346 }
1347
1348 /**
1349 * @deprecated 1.07.05 This is still referenced in the API add on as of v1.13.
1350 * @codeCoverageIgnore
1351 *
1352 * @param array $atts
1353 * @return string
1354 */
1355 public static function get_form_shortcode( $atts ) {
1356 _deprecated_function( __FUNCTION__, '1.07.05', 'FrmFormsController::get_form_shortcode' );
1357 return FrmFormsController::get_form_shortcode( $atts );
1358 }
1359
1360 /**
1361 * @deprecated 3.0 This is still referenced in https://formidableforms.com/knowledgebase/php-examples/ as of May 8, 2024.
1362 * @codeCoverageIgnore
1363 */
1364 public static function page_route( $content ) {
1365 return FrmDeprecated::page_route( $content );
1366 }
1367 }
1368