PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.10
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.10
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.10, at classes/controllers/FrmAppController.php

1,349 lines 37.7 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 wp_enqueue_style( 'formidable-dropzone' );
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 * The floating links are not shown on every page.
805 * They are also not shown if white labeling is being used.
806 *
807 * @since 6.8.4
808 *
809 * @return bool
810 */
811 private static function should_show_floating_links() {
812 if ( ! FrmAppHelper::is_formidable_branding() ) {
813 return false;
814 }
815
816 return FrmAppHelper::is_formidable_admin() &&
817 ! FrmAppHelper::is_style_editor_page() &&
818 ! FrmAppHelper::is_admin_page( 'formidable-views-editor' ) &&
819 ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
820 }
821
822 /**
823 * @since 6.3.2
824 *
825 * @return void
826 */
827 public static function admin_enqueue_scripts() {
828 self::load_wp_admin_style();
829 self::maybe_force_formidable_block_on_gutenberg_page();
830 }
831
832 /**
833 * Enqueue required assets for the Legacy Views editor (Views v4.x).
834 *
835 * @since 6.1.2
836 *
837 * @return void
838 */
839 private static function enqueue_legacy_views_assets() {
840 wp_enqueue_style( 'formidable-grids' );
841 wp_enqueue_script( 'jquery-ui-draggable' );
842 self::maybe_deregister_popper2();
843 wp_enqueue_script( 'formidable_admin' );
844 wp_add_inline_style(
845 'formidable-admin',
846 '
847 .frm-white-body.post-type-frm_display .columns-2 {
848 display: block;
849 overflow: visible;
850 }
851
852 .frm-white-body.post-type-frm_display .columns-2 > div {
853 overflow-y: hidden;
854 }
855
856 .frm-white-body.post-type-frm_display #titlediv #title-prompt-text {
857 padding: 3px 0 0 10px;
858 }
859
860 .post-type-frm_display #field-search-input,
861 .post-type-frm_display #advanced-search-input {
862 flex: 1;
863 }
864 '
865 );
866 wp_enqueue_style( 'formidable-admin' );
867 FrmAppHelper::localize_script( 'admin' );
868 self::include_info_overlay();
869 }
870
871 /**
872 * Fix a Duplicator Pro conflict because it uses Popper 2. See issue #3459.
873 *
874 * @since 5.2.02.01
875 *
876 * @return void
877 */
878 private static function maybe_deregister_popper2() {
879 global $wp_scripts;
880
881 if ( ! array_key_exists( 'popper', $wp_scripts->registered ) ) {
882 return;
883 }
884
885 $popper = $wp_scripts->registered['popper'];
886 if ( version_compare( $popper->ver, '2.0', '>=' ) ) {
887 wp_deregister_script( 'popper' );
888 self::register_popper1();
889 }
890 }
891
892 /**
893 * Register Popper required for Bootstrap 4.
894 *
895 * @since 5.2.02.01
896 *
897 * @return void
898 */
899 private static function register_popper1() {
900 wp_register_script( 'popper', FrmAppHelper::plugin_url() . '/js/popper.min.js', array( 'jquery' ), '1.16.0', true );
901 }
902
903 /**
904 * Automatically insert a Formidable block when loading Gutenberg when $_GET['frmForm' is set.
905 *
906 * @since 5.2
907 *
908 * @return void
909 */
910 private static function maybe_force_formidable_block_on_gutenberg_page() {
911 global $pagenow;
912 if ( 'post.php' !== $pagenow ) {
913 return;
914 }
915
916 $form_id = FrmAppHelper::simple_get( 'frmForm', 'absint' );
917 if ( ! $form_id ) {
918 return;
919 }
920
921 self::add_js_to_inject_gutenberg_block( 'formidable/simple-form', 'formId', $form_id );
922 }
923
924 /**
925 * @since 5.3
926 *
927 * @param string $block_name
928 * @param string $object_key
929 * @param array|string $object_id
930 *
931 * @return void
932 */
933 public static function add_js_to_inject_gutenberg_block( $block_name, $object_key, $object_id ) {
934 require FrmAppHelper::plugin_path() . '/classes/views/shared/edit-page-js.php';
935 }
936
937 /**
938 * @return void
939 */
940 public static function load_lang() {
941 load_plugin_textdomain( 'formidable', false, FrmAppHelper::plugin_folder() . '/languages/' );
942 }
943
944 /**
945 * Check if the styles are updated when a form is loaded on the front-end
946 *
947 * @since 3.0.1
948 *
949 * @return void
950 */
951 public static function maybe_update_styles() {
952 if ( self::needs_update() ) {
953 self::network_upgrade_site();
954 }
955 }
956
957 /**
958 * @since 3.0
959 *
960 * @return void
961 */
962 public static function create_rest_routes() {
963 $args = array(
964 'methods' => 'GET',
965 'callback' => 'FrmAppController::api_install',
966 'permission_callback' => __CLASS__ . '::can_update_db',
967 );
968
969 register_rest_route( 'frm-admin/v1', '/install', $args );
970
971 $args = array(
972 'methods' => 'GET',
973 'callback' => 'FrmAddonsController::install_addon_api',
974 'permission_callback' => 'FrmAddonsController::can_install_addon_api',
975 );
976
977 register_rest_route( 'frm-admin/v1', '/install-addon', $args );
978 }
979
980 /**
981 * Make sure the install is only being run when we tell it to.
982 * We don't want to run manually by people calling the API.
983 *
984 * @since 4.06.02
985 */
986 public static function can_update_db() {
987 return get_transient( 'frm_updating_api' );
988 }
989
990 /**
991 * Run silent upgrade on each site in the network during a network upgrade.
992 * Update database settings for all sites in a network during network upgrade process.
993 *
994 * @since 2.0.1
995 *
996 * @param int $blog_id Blog ID.
997 *
998 * @return void
999 */
1000 public static function network_upgrade_site( $blog_id = 0 ) {
1001 // Flag to check if install is happening as intended.
1002 set_transient( 'frm_updating_api', true, MINUTE_IN_SECONDS );
1003 $request = new WP_REST_Request( 'GET', '/frm-admin/v1/install' );
1004
1005 self::maybe_add_wp_site_health();
1006
1007 if ( $blog_id ) {
1008 switch_to_blog( $blog_id );
1009 $response = rest_do_request( $request );
1010 restore_current_blog();
1011 } else {
1012 $response = rest_do_request( $request );
1013 }
1014
1015 if ( $response->is_error() ) {
1016 // if the remove post fails, use javascript instead
1017 add_action( 'admin_notices', 'FrmAppController::install_js_fallback' );
1018 }
1019 }
1020
1021 /**
1022 * Make sure WP_Site_Health has been included because it is required when calling rest_do_request.
1023 * Check first that the file exists because WP_Site_Health was only introduced in WordPress 5.2.
1024 *
1025 * @return void
1026 */
1027 private static function maybe_add_wp_site_health() {
1028 if ( ! class_exists( 'WP_Site_Health' ) ) {
1029 $wp_site_health_path = ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
1030 if ( file_exists( $wp_site_health_path ) ) {
1031 require_once $wp_site_health_path;
1032 }
1033 }
1034 }
1035
1036 /**
1037 * @since 3.0
1038 *
1039 * @return true
1040 */
1041 public static function api_install() {
1042 delete_transient( 'frm_updating_api' );
1043 if ( self::needs_update() ) {
1044 $running = get_option( 'frm_install_running' );
1045 if ( false === $running || $running < strtotime( '-5 minutes' ) ) {
1046 update_option( 'frm_install_running', time(), 'no' );
1047 self::install();
1048 delete_option( 'frm_install_running' );
1049 }
1050 }
1051
1052 return true;
1053 }
1054
1055 /**
1056 * Silent database upgrade (no redirect).
1057 * Called via ajax request during network upgrade process.
1058 *
1059 * @since 2.0.1
1060 *
1061 * @return void
1062 */
1063 public static function ajax_install() {
1064 FrmAppHelper::permission_check( 'frm_change_settings' );
1065 check_ajax_referer( 'frm_ajax', 'nonce' );
1066 self::api_install();
1067 wp_die();
1068 }
1069
1070 /**
1071 * @return void
1072 */
1073 public static function install() {
1074 $frmdb = new FrmMigrate();
1075 $frmdb->upgrade();
1076 }
1077
1078 /**
1079 * @return void
1080 */
1081 public static function uninstall() {
1082 FrmAppHelper::permission_check( 'administrator' );
1083 check_ajax_referer( 'frm_ajax', 'nonce' );
1084
1085 $frmdb = new FrmMigrate();
1086 $frmdb->uninstall();
1087
1088 // Disable the plugin and redirect after uninstall so the tables don't get added right back.
1089 $plugins = array( FrmAppHelper::plugin_folder() . '/formidable.php', 'formidable-pro/formidable-pro.php' );
1090 deactivate_plugins( $plugins, false, false );
1091 echo esc_url_raw( admin_url( 'plugins.php?deactivate=true' ) );
1092
1093 wp_die();
1094 }
1095
1096 public static function drop_tables( $tables ) {
1097 global $wpdb;
1098 $tables[] = $wpdb->prefix . 'frm_fields';
1099 $tables[] = $wpdb->prefix . 'frm_forms';
1100 $tables[] = $wpdb->prefix . 'frm_items';
1101 $tables[] = $wpdb->prefix . 'frm_item_metas';
1102
1103 return $tables;
1104 }
1105
1106 /**
1107 * @return void
1108 */
1109 public static function deauthorize() {
1110 FrmAppHelper::permission_check( 'frm_change_settings' );
1111 check_ajax_referer( 'frm_ajax', 'nonce' );
1112
1113 delete_option( 'frmpro-credentials' );
1114 delete_option( 'frmpro-authorized' );
1115 delete_site_option( 'frmpro-credentials' );
1116 delete_site_option( 'frmpro-authorized' );
1117 wp_die();
1118 }
1119
1120 /**
1121 * This is triggered when Formidable is activated.
1122 *
1123 * @return void
1124 */
1125 public static function handle_activation() {
1126 self::maybe_activate_payment_cron();
1127 }
1128
1129 /**
1130 * The payment cron is unscheduled when Formidable is deactivated.
1131 * We need to add it back again on activation if Stripe is configured.
1132 *
1133 * @since 6.5
1134 *
1135 * @return void
1136 */
1137 private static function maybe_activate_payment_cron() {
1138 if ( ! FrmStrpLiteConnectHelper::stripe_connect_is_setup() ) {
1139 return;
1140 }
1141
1142 FrmTransLiteAppController::maybe_schedule_cron();
1143 }
1144
1145 public static function set_footer_text( $text ) {
1146 if ( FrmAppHelper::is_formidable_admin() ) {
1147 $text = '';
1148 }
1149
1150 return $text;
1151 }
1152
1153 /**
1154 * Add admin footer links.
1155 *
1156 * @since 6.4.1
1157 *
1158 * @return void
1159 */
1160 public static function add_admin_footer_links() {
1161 if ( self::should_show_footer_links() ) {
1162 include FrmAppHelper::plugin_path() . '/classes/views/shared/admin-footer-links.php';
1163 }
1164 }
1165
1166 /**
1167 * Check if the footer links should be shown.
1168 *
1169 * @since 6.7
1170 *
1171 * @return bool
1172 */
1173 private static function should_show_footer_links() {
1174 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
1175 $is_formidable_page = FrmAppHelper::is_formidable_admin() || 'frm_logs' === $post_type;
1176 $show_footer_links = $is_formidable_page;
1177 if ( FrmAppHelper::is_full_screen() || ! FrmAppHelper::is_formidable_branding() ) {
1178 $show_footer_links = false;
1179 }
1180
1181 /**
1182 * Filter whether to show the Formidable footer links.
1183 *
1184 * @since 6.7
1185 *
1186 * @param bool $show_footer_links
1187 * @return bool
1188 */
1189 return apply_filters( 'frm_show_footer_links', $show_footer_links );
1190 }
1191
1192 /**
1193 * Show an error modal and terminate the script execution.
1194 *
1195 * @since 6.7
1196 *
1197 * @param array $error_args Arguments that control the behavior of the error modal.
1198 *
1199 * @return void
1200 */
1201 public static function show_error_modal( $error_args ) {
1202 $defaults = array(
1203 'title' => '',
1204 'body' => '',
1205 'cancel_url' => '',
1206 'cancel_classes' => '',
1207 'continue_url' => '',
1208 'continue_classes' => '',
1209 'icon' => 'frm_lock_simple',
1210 );
1211
1212 $error_args = wp_parse_args( $error_args, $defaults );
1213 if ( ! isset( $error_args['cancel_text'] ) && ! empty( $error_args['cancel_url'] ) ) {
1214 $error_args['cancel_text'] = __( 'Cancel', 'formidable' );
1215 }
1216
1217 if ( ! isset( $error_args['continue_text'] ) && ! empty( $error_args['continue_url'] ) ) {
1218 $error_args['continue_text'] = __( 'Continue', 'formidable' );
1219 }
1220
1221 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/error-modal.php';
1222 }
1223
1224 /**
1225 * Handles Floating Links' scripts and styles enqueueing.
1226 *
1227 * @since 6.4
1228 *
1229 * @param string $plugin_url URL of the plugin.
1230 * @param string $version Current version of the plugin.
1231 * @return void
1232 */
1233 private static function enqueue_floating_links( $plugin_url, $version ) {
1234 if ( ! $plugin_url || ! $version ) {
1235 // If any required parameters are missing, exit early.
1236 return;
1237 }
1238
1239 // Enqueue the Floating Links styles.
1240 wp_enqueue_style( 's11-floating-links', $plugin_url . '/css/packages/s11-floating-links.css', array(), $version );
1241
1242 // Enqueue the Floating Links script.
1243 wp_enqueue_script( 's11-floating-links', $plugin_url . '/js/packages/floating-links/s11-floating-links.js', array(), $version, true );
1244
1245 // Enqueue the config script.
1246 wp_enqueue_script( 's11-floating-links-config', $plugin_url . '/js/packages/floating-links/config.js', array( 'wp-i18n' ), $version, true );
1247
1248 if ( function_exists( 'wp_set_script_translations' ) ) {
1249 wp_set_script_translations( 's11-floating-links-config', 's11-' );
1250 }
1251
1252 $floating_links_data = array(
1253 'proIsInstalled' => FrmAppHelper::pro_is_installed(),
1254 );
1255 wp_localize_script( 's11-floating-links-config', 's11FloatingLinksData', $floating_links_data );
1256
1257 /**
1258 * Prompt Pro to load additional floating links scripts.
1259 * This is used to include images in the Inbox SlideIn when Pro is active.
1260 *
1261 * @since 6.8.4
1262 */
1263 do_action( 'frm_enqueue_floating_links' );
1264 }
1265
1266 /**
1267 * @return void
1268 */
1269 private static function maybe_add_deprecated_message() {
1270 $settings = FrmAppHelper::get_settings();
1271
1272 if ( ! empty( $settings->use_html ) ) {
1273 // Dont' show a message if Use HTML 5 is already enabled.
1274 return;
1275 }
1276
1277 if ( FrmAppHelper::is_admin_page( 'formidable-settings' ) ) {
1278 add_action(
1279 'frm_update_settings',
1280 function ( $params ) {
1281 if ( ! empty( $params['frm_use_html'] ) ) {
1282 $inbox = new FrmInbox();
1283 $inbox->dismiss( 'deprecated_use_html' );
1284 }
1285 }
1286 );
1287 // Don't show the message on global settings.
1288 return;
1289 }
1290
1291 $url = admin_url( 'admin.php?page=formidable-settings&t=misc_settings' );
1292
1293 add_filter(
1294 'frm_message_list',
1295 /**
1296 * @param array $messages
1297 * @return array
1298 */
1299 function ( $messages ) use ( $url ) {
1300 $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>';
1301 return $messages;
1302 }
1303 );
1304
1305 $inbox = new FrmInbox();
1306 $inbox->add_message(
1307 array(
1308 'key' => 'deprecated_use_html',
1309 'force' => true,
1310 'subject' => 'The option to use HTML5 in forms will soon be removed',
1311 '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.',
1312 'icon' => 'frm_report_problem_icon',
1313 'cta' => '<a class="button-secondary frm-button-secondary" href="' . esc_url( $url ) . '">Enable in Global Settings</a>',
1314 )
1315 );
1316 }
1317
1318 /**
1319 * Include icons on page for Embed Form modal.
1320 *
1321 * @since 5.2
1322 *
1323 * @return void
1324 */
1325 public static function include_embed_form_icons() {
1326 _deprecated_function( __METHOD__, '5.3' );
1327 }
1328
1329 /**
1330 * @deprecated 1.07.05 This is still referenced in the API add on as of v1.13.
1331 * @codeCoverageIgnore
1332 *
1333 * @param array $atts
1334 * @return string
1335 */
1336 public static function get_form_shortcode( $atts ) {
1337 _deprecated_function( __FUNCTION__, '1.07.05', 'FrmFormsController::get_form_shortcode' );
1338 return FrmFormsController::get_form_shortcode( $atts );
1339 }
1340
1341 /**
1342 * @deprecated 3.0 This is still referenced in https://formidableforms.com/knowledgebase/php-examples/ as of May 8, 2024.
1343 * @codeCoverageIgnore
1344 */
1345 public static function page_route( $content ) {
1346 return FrmDeprecated::page_route( $content );
1347 }
1348 }
1349