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

1,307 lines 36.1 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 boolean
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 }
587
588 /**
589 * Get the current page and check for a possible function to trigger.
590 * If a class name matches the page name, and the class has a load_page() method, trigger it.
591 *
592 * @since 6.8
593 *
594 * @return void
595 */
596 private static function trigger_page_load_hooks() {
597 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
598 if ( strpos( $page, 'formidable-' ) !== 0 ) {
599 // Only trigger hooks on Formidable pages.
600 return;
601 }
602
603 $page = str_replace( array( 'formidable-', '-' ), array( '', ' ' ), $page );
604 $page = str_replace( ' ', '', ucwords( $page ) );
605 $class = 'Frm' . $page . 'Controller';
606 if ( class_exists( $class ) && method_exists( $class, 'load_page' ) ) {
607 call_user_func( array( $class, 'load_page' ) );
608 }
609 }
610
611 /**
612 * Show a warning for the IP address setting if it hasn't been set.
613 *
614 * @since 6.1
615 *
616 * @return void
617 */
618 private static function maybe_add_ip_warning() {
619 $settings = FrmAppHelper::get_settings();
620 if ( false !== $settings->custom_header_ip ) {
621 // The setting has been changed from the false default (to either 1 or 0), so stop showing the message.
622 return;
623 }
624
625 if ( ! self::is_behind_proxy() ) {
626 // This message is only applicable when using a reverse proxy.
627 return;
628 }
629
630 if ( FrmAppHelper::get_post_param( 'frm_action', '', 'sanitize_text_field' ) ) {
631 // Avoid the message on a POST action. We don't want to show the message if we're saving global settings.
632 return;
633 }
634
635 $global_settings_link = admin_url( 'admin.php?page=formidable-settings' ) . '#frm_custom_header_ip';
636 $message = sprintf(
637 // Translators: 1: Global Settings Link
638 __( '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' ),
639 '<a href="' . esc_url( $global_settings_link ) . '">Global Settings</a>'
640 );
641 $option_name = 'frm_dismiss_ip_address_notice';
642 FrmAppHelper::add_dismissable_warning_message( $message, $option_name );
643 }
644
645 /**
646 * Check if any reverse proxy headers are set.
647 *
648 * @since 6.1
649 *
650 * @return bool
651 */
652 private static function is_behind_proxy() {
653 $custom_headers = FrmAppHelper::get_custom_header_keys_for_ip();
654 foreach ( $custom_headers as $header ) {
655 if ( 'REMOTE_ADDR' === $header ) {
656 // We want to check every key but REMOTE_ADDR. REMOTE_ATTR is not unique to reverse proxy servers.
657 continue;
658 }
659
660 $ip = trim( FrmAppHelper::get_server_value( $header ) );
661 // Return true for anything that isn't empty but ignoring values like ::1.
662 if ( $ip && 0 !== strpos( $ip, '::' ) ) {
663 return true;
664 }
665 }
666
667 return false;
668 }
669
670 /**
671 * @return void
672 */
673 public static function admin_js() {
674 $plugin_url = FrmAppHelper::plugin_url();
675 $version = FrmAppHelper::plugin_version();
676
677 FrmAppHelper::load_admin_wide_js();
678
679 // Register component assets early to ensure they can be enqueued later in controllers.
680 wp_register_style( 'formidable-animations', $plugin_url . '/css/admin/animations.css', array(), $version );
681
682 if ( class_exists( 'FrmOverlayController' ) ) {
683 // This should always exist.
684 // But it may not have loaded properly when updating the plugin.
685 FrmOverlayController::register_assets();
686 }
687
688 wp_register_style( 'formidable_admin_global', $plugin_url . '/css/admin/frm_admin_global.css', array(), $version );
689 wp_enqueue_style( 'formidable_admin_global' );
690
691 wp_register_style( 'formidable-admin', $plugin_url . '/css/frm_admin.css', array(), $version );
692 wp_register_style( 'formidable-grids', $plugin_url . '/css/frm_grids.css', array(), $version );
693
694 wp_register_script( 'formidable_dom', $plugin_url . '/js/admin/dom.js', array( 'jquery', 'jquery-ui-dialog', 'wp-i18n' ), $version, true );
695 wp_register_script( 'formidable_embed', $plugin_url . '/js/admin/embed.js', array( 'formidable_dom', 'jquery-ui-autocomplete' ), $version, true );
696 self::register_popper1();
697 wp_register_script( 'bootstrap_tooltip', $plugin_url . '/js/bootstrap.min.js', array( 'jquery', 'popper' ), '4.6.1', true );
698 wp_register_script( 'formidable_settings', $plugin_url . '/js/admin/settings.js', array(), $version, true );
699
700 if ( self::should_show_floating_links() ) {
701 self::enqueue_floating_links( $plugin_url, $version );
702 }
703
704 $dependencies = array(
705 'formidable_admin_global',
706 'jquery',
707 'jquery-ui-core',
708 'jquery-ui-draggable',
709 'jquery-ui-sortable',
710 'bootstrap_tooltip',
711 'bootstrap-multiselect',
712 'wp-i18n',
713 // Required in WP versions older than 5.7
714 'wp-hooks',
715 'formidable_dom',
716 'formidable_embed',
717 );
718
719 if ( FrmAppHelper::is_style_editor_page( 'edit' ) ) {
720 // We only need to load the color picker when editing styles.
721 $dependencies[] = 'wp-color-picker';
722 }
723
724 wp_register_script( 'formidable_admin', $plugin_url . '/js/formidable_admin.js', $dependencies, $version, true );
725
726 if ( FrmAppHelper::on_form_listing_page() ) {
727 // For the existing page dropdown in the Form embed modal.
728 wp_enqueue_script( 'jquery-ui-autocomplete' );
729 }
730
731 wp_register_script( 'bootstrap-multiselect', $plugin_url . '/js/bootstrap-multiselect.js', array( 'jquery', 'bootstrap_tooltip', 'popper' ), '1.1.1', true );
732
733 if ( ! class_exists( 'FrmTransHooksController', false ) ) {
734 /**
735 * Gateway fields are included for add-on compatibility but we do not want it to be visible.
736 * They do however need to be visible when the payments submodule is active.
737 */
738 wp_add_inline_style(
739 'formidable-admin',
740 '#frm_builder_page li[data-ftype="gateway"] { display: none; }'
741 );
742 }
743
744 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
745 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
746
747 global $pagenow;
748 if ( strpos( $page, 'formidable' ) === 0 || ( $pagenow === 'edit.php' && $post_type === 'frm_display' ) ) {
749
750 wp_enqueue_script( 'admin-widgets' );
751 wp_enqueue_style( 'widgets' );
752 self::maybe_deregister_popper2();
753 wp_enqueue_script( 'formidable_admin' );
754 wp_enqueue_script( 'formidable_embed' );
755 FrmAppHelper::localize_script( 'admin' );
756
757 wp_enqueue_style( 'formidable-animations' );
758 wp_enqueue_style( 'formidable-admin' );
759 if ( 'formidable-styles' !== $page && 'formidable-styles2' !== $page ) {
760 wp_enqueue_style( 'formidable-grids' );
761 wp_enqueue_style( 'formidable-dropzone' );
762 } else {
763 wp_enqueue_style( 'formidable-grids' );
764 }
765
766 if ( 'formidable-entries' === $page ) {
767 // Load front end js for entries.
768 wp_enqueue_script( 'formidable' );
769
770 // Registers and enqueues the entries page scripts.
771 wp_register_script( 'formidable_entries', $plugin_url . '/js/admin/entries.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
772 wp_enqueue_script( 'formidable_entries' );
773 }
774
775 do_action( 'frm_enqueue_builder_scripts' );
776 self::include_upgrade_overlay();
777 self::include_info_overlay();
778 } elseif ( FrmAppHelper::is_view_builder_page() ) {
779 if ( isset( $_REQUEST['post_type'] ) ) {
780 $post_type = sanitize_title( wp_unslash( $_REQUEST['post_type'] ) );
781 } elseif ( isset( $_REQUEST['post'] ) && absint( $_REQUEST['post'] ) ) {
782 $post = get_post( absint( wp_unslash( $_REQUEST['post'] ) ) );
783 if ( ! $post ) {
784 return;
785 }
786 $post_type = $post->post_type;
787 } else {
788 return;
789 }
790
791 if ( $post_type === 'frm_display' ) {
792 self::enqueue_legacy_views_assets();
793 }
794 }//end if
795
796 if ( 'formidable-addons' === $page ) {
797 wp_register_script( 'formidable_addons', $plugin_url . '/js/admin/addons.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
798 wp_enqueue_script( 'formidable_addons' );
799 }
800 }
801
802 /**
803 * The floating links are not shown on every page.
804 * They are also not shown if white labeling is being used.
805 *
806 * @since 6.8.4
807 *
808 * @return bool
809 */
810 private static function should_show_floating_links() {
811 if ( ! FrmAppHelper::is_formidable_branding() ) {
812 return false;
813 }
814
815 return FrmAppHelper::is_formidable_admin() &&
816 ! FrmAppHelper::is_style_editor_page() &&
817 ! FrmAppHelper::is_admin_page( 'formidable-views-editor' ) &&
818 ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
819 }
820
821 /**
822 * @since 6.3.2
823 *
824 * @return void
825 */
826 public static function admin_enqueue_scripts() {
827 self::load_wp_admin_style();
828 self::maybe_force_formidable_block_on_gutenberg_page();
829 }
830
831 /**
832 * Enqueue required assets for the Legacy Views editor (Views v4.x).
833 *
834 * @since 6.1.2
835 *
836 * @return void
837 */
838 private static function enqueue_legacy_views_assets() {
839 wp_enqueue_style( 'formidable-grids' );
840 wp_enqueue_script( 'jquery-ui-draggable' );
841 self::maybe_deregister_popper2();
842 wp_enqueue_script( 'formidable_admin' );
843 wp_add_inline_style(
844 'formidable-admin',
845 '
846 .frm-white-body.post-type-frm_display .columns-2 {
847 display: block;
848 overflow: visible;
849 }
850
851 .frm-white-body.post-type-frm_display .columns-2 > div {
852 overflow-y: hidden;
853 }
854
855 .frm-white-body.post-type-frm_display #titlediv #title-prompt-text {
856 padding: 3px 0 0 10px;
857 }
858
859 .post-type-frm_display #field-search-input,
860 .post-type-frm_display #advanced-search-input {
861 flex: 1;
862 }
863 '
864 );
865 wp_enqueue_style( 'formidable-admin' );
866 FrmAppHelper::localize_script( 'admin' );
867 self::include_info_overlay();
868 }
869
870 /**
871 * Fix a Duplicator Pro conflict because it uses Popper 2. See issue #3459.
872 *
873 * @since 5.2.02.01
874 *
875 * @return void
876 */
877 private static function maybe_deregister_popper2() {
878 global $wp_scripts;
879
880 if ( ! array_key_exists( 'popper', $wp_scripts->registered ) ) {
881 return;
882 }
883
884 $popper = $wp_scripts->registered['popper'];
885 if ( version_compare( $popper->ver, '2.0', '>=' ) ) {
886 wp_deregister_script( 'popper' );
887 self::register_popper1();
888 }
889 }
890
891 /**
892 * Register Popper required for Bootstrap 4.
893 *
894 * @since 5.2.02.01
895 *
896 * @return void
897 */
898 private static function register_popper1() {
899 wp_register_script( 'popper', FrmAppHelper::plugin_url() . '/js/popper.min.js', array( 'jquery' ), '1.16.0', true );
900 }
901
902 /**
903 * Automatically insert a Formidable block when loading Gutenberg when $_GET['frmForm' is set.
904 *
905 * @since 5.2
906 *
907 * @return void
908 */
909 private static function maybe_force_formidable_block_on_gutenberg_page() {
910 global $pagenow;
911 if ( 'post.php' !== $pagenow ) {
912 return;
913 }
914
915 $form_id = FrmAppHelper::simple_get( 'frmForm', 'absint' );
916 if ( ! $form_id ) {
917 return;
918 }
919
920 self::add_js_to_inject_gutenberg_block( 'formidable/simple-form', 'formId', $form_id );
921 }
922
923 /**
924 * @since 5.3
925 *
926 * @param string $block_name
927 * @param string $object_key
928 * @param array|string $object_id
929 *
930 * @return void
931 */
932 public static function add_js_to_inject_gutenberg_block( $block_name, $object_key, $object_id ) {
933 require FrmAppHelper::plugin_path() . '/classes/views/shared/edit-page-js.php';
934 }
935
936 /**
937 * @return void
938 */
939 public static function load_lang() {
940 load_plugin_textdomain( 'formidable', false, FrmAppHelper::plugin_folder() . '/languages/' );
941 }
942
943 /**
944 * Check if the styles are updated when a form is loaded on the front-end
945 *
946 * @since 3.0.1
947 *
948 * @return void
949 */
950 public static function maybe_update_styles() {
951 if ( self::needs_update() ) {
952 self::network_upgrade_site();
953 }
954 }
955
956 /**
957 * @since 3.0
958 *
959 * @return void
960 */
961 public static function create_rest_routes() {
962 $args = array(
963 'methods' => 'GET',
964 'callback' => 'FrmAppController::api_install',
965 'permission_callback' => __CLASS__ . '::can_update_db',
966 );
967
968 register_rest_route( 'frm-admin/v1', '/install', $args );
969
970 $args = array(
971 'methods' => 'GET',
972 'callback' => 'FrmAddonsController::install_addon_api',
973 'permission_callback' => 'FrmAddonsController::can_install_addon_api',
974 );
975
976 register_rest_route( 'frm-admin/v1', '/install-addon', $args );
977 }
978
979 /**
980 * Make sure the install is only being run when we tell it to.
981 * We don't want to run manually by people calling the API.
982 *
983 * @since 4.06.02
984 */
985 public static function can_update_db() {
986 return get_transient( 'frm_updating_api' );
987 }
988
989 /**
990 * Run silent upgrade on each site in the network during a network upgrade.
991 * Update database settings for all sites in a network during network upgrade process.
992 *
993 * @since 2.0.1
994 *
995 * @param int $blog_id Blog ID.
996 *
997 * @return void
998 */
999 public static function network_upgrade_site( $blog_id = 0 ) {
1000 // Flag to check if install is happening as intended.
1001 set_transient( 'frm_updating_api', true, MINUTE_IN_SECONDS );
1002 $request = new WP_REST_Request( 'GET', '/frm-admin/v1/install' );
1003
1004 self::maybe_add_wp_site_health();
1005
1006 if ( $blog_id ) {
1007 switch_to_blog( $blog_id );
1008 $response = rest_do_request( $request );
1009 restore_current_blog();
1010 } else {
1011 $response = rest_do_request( $request );
1012 }
1013
1014 if ( $response->is_error() ) {
1015 // if the remove post fails, use javascript instead
1016 add_action( 'admin_notices', 'FrmAppController::install_js_fallback' );
1017 }
1018 }
1019
1020 /**
1021 * Make sure WP_Site_Health has been included because it is required when calling rest_do_request.
1022 * Check first that the file exists because WP_Site_Health was only introduced in WordPress 5.2.
1023 *
1024 * @return void
1025 */
1026 private static function maybe_add_wp_site_health() {
1027 if ( ! class_exists( 'WP_Site_Health' ) ) {
1028 $wp_site_health_path = ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
1029 if ( file_exists( $wp_site_health_path ) ) {
1030 require_once $wp_site_health_path;
1031 }
1032 }
1033 }
1034
1035 /**
1036 * @since 3.0
1037 *
1038 * @return true
1039 */
1040 public static function api_install() {
1041 delete_transient( 'frm_updating_api' );
1042 if ( self::needs_update() ) {
1043 $running = get_option( 'frm_install_running' );
1044 if ( false === $running || $running < strtotime( '-5 minutes' ) ) {
1045 update_option( 'frm_install_running', time(), 'no' );
1046 self::install();
1047 delete_option( 'frm_install_running' );
1048 }
1049 }
1050
1051 return true;
1052 }
1053
1054 /**
1055 * Silent database upgrade (no redirect).
1056 * Called via ajax request during network upgrade process.
1057 *
1058 * @since 2.0.1
1059 *
1060 * @return void
1061 */
1062 public static function ajax_install() {
1063 FrmAppHelper::permission_check( 'frm_change_settings' );
1064 check_ajax_referer( 'frm_ajax', 'nonce' );
1065 self::api_install();
1066 wp_die();
1067 }
1068
1069 /**
1070 * @return void
1071 */
1072 public static function install() {
1073 $frmdb = new FrmMigrate();
1074 $frmdb->upgrade();
1075 }
1076
1077 /**
1078 * @return void
1079 */
1080 public static function uninstall() {
1081 FrmAppHelper::permission_check( 'administrator' );
1082 check_ajax_referer( 'frm_ajax', 'nonce' );
1083
1084 $frmdb = new FrmMigrate();
1085 $frmdb->uninstall();
1086
1087 // Disable the plugin and redirect after uninstall so the tables don't get added right back.
1088 $plugins = array( FrmAppHelper::plugin_folder() . '/formidable.php', 'formidable-pro/formidable-pro.php' );
1089 deactivate_plugins( $plugins, false, false );
1090 echo esc_url_raw( admin_url( 'plugins.php?deactivate=true' ) );
1091
1092 wp_die();
1093 }
1094
1095 public static function drop_tables( $tables ) {
1096 global $wpdb;
1097 $tables[] = $wpdb->prefix . 'frm_fields';
1098 $tables[] = $wpdb->prefix . 'frm_forms';
1099 $tables[] = $wpdb->prefix . 'frm_items';
1100 $tables[] = $wpdb->prefix . 'frm_item_metas';
1101
1102 return $tables;
1103 }
1104
1105 /**
1106 * @return void
1107 */
1108 public static function deauthorize() {
1109 FrmAppHelper::permission_check( 'frm_change_settings' );
1110 check_ajax_referer( 'frm_ajax', 'nonce' );
1111
1112 delete_option( 'frmpro-credentials' );
1113 delete_option( 'frmpro-authorized' );
1114 delete_site_option( 'frmpro-credentials' );
1115 delete_site_option( 'frmpro-authorized' );
1116 wp_die();
1117 }
1118
1119 /**
1120 * This is triggered when Formidable is activated.
1121 *
1122 * @return void
1123 */
1124 public static function handle_activation() {
1125 self::maybe_activate_payment_cron();
1126 }
1127
1128 /**
1129 * The payment cron is unscheduled when Formidable is deactivated.
1130 * We need to add it back again on activation if Stripe is configured.
1131 *
1132 * @since 6.5
1133 *
1134 * @return void
1135 */
1136 private static function maybe_activate_payment_cron() {
1137 if ( ! FrmStrpLiteConnectHelper::stripe_connect_is_setup() ) {
1138 return;
1139 }
1140
1141 FrmTransLiteAppController::maybe_schedule_cron();
1142 }
1143
1144 public static function set_footer_text( $text ) {
1145 if ( FrmAppHelper::is_formidable_admin() ) {
1146 $text = '';
1147 }
1148
1149 return $text;
1150 }
1151
1152 /**
1153 * Add admin footer links.
1154 *
1155 * @since 6.4.1
1156 *
1157 * @return void
1158 */
1159 public static function add_admin_footer_links() {
1160 if ( self::should_show_footer_links() ) {
1161 include FrmAppHelper::plugin_path() . '/classes/views/shared/admin-footer-links.php';
1162 }
1163 }
1164
1165 /**
1166 * Check if the footer links should be shown.
1167 *
1168 * @since 6.7
1169 *
1170 * @return bool
1171 */
1172 private static function should_show_footer_links() {
1173 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
1174 $is_formidable_page = FrmAppHelper::is_formidable_admin() || 'frm_logs' === $post_type;
1175 $show_footer_links = $is_formidable_page;
1176 if ( FrmAppHelper::is_full_screen() || ! FrmAppHelper::is_formidable_branding() ) {
1177 $show_footer_links = false;
1178 }
1179
1180 /**
1181 * Filter whether to show the Formidable footer links.
1182 *
1183 * @since 6.7
1184 *
1185 * @param bool $show_footer_links
1186 * @return bool
1187 */
1188 return apply_filters( 'frm_show_footer_links', $show_footer_links );
1189 }
1190
1191 /**
1192 * Show an error modal and terminate the script execution.
1193 *
1194 * @since 6.7
1195 *
1196 * @param array $error_args Arguments that control the behavior of the error modal.
1197 *
1198 * @return void
1199 */
1200 public static function show_error_modal( $error_args ) {
1201 $defaults = array(
1202 'title' => '',
1203 'body' => '',
1204 'cancel_url' => '',
1205 'cancel_classes' => '',
1206 'continue_url' => '',
1207 'continue_classes' => '',
1208 'icon' => 'frm_lock_simple',
1209 );
1210
1211 $error_args = wp_parse_args( $error_args, $defaults );
1212 if ( ! isset( $error_args['cancel_text'] ) && ! empty( $error_args['cancel_url'] ) ) {
1213 $error_args['cancel_text'] = __( 'Cancel', 'formidable' );
1214 }
1215
1216 if ( ! isset( $error_args['continue_text'] ) && ! empty( $error_args['continue_url'] ) ) {
1217 $error_args['continue_text'] = __( 'Continue', 'formidable' );
1218 }
1219
1220 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/error-modal.php';
1221 }
1222
1223 /**
1224 * @deprecated 3.0.04
1225 *
1226 * @codeCoverageIgnore
1227 *
1228 * @return void
1229 */
1230 public static function activation_install() {
1231 FrmDeprecated::activation_install();
1232 }
1233
1234 /**
1235 * @deprecated 3.0
1236 * @codeCoverageIgnore
1237 */
1238 public static function page_route( $content ) {
1239 return FrmDeprecated::page_route( $content );
1240 }
1241
1242 /**
1243 * Include icons on page for Embed Form modal.
1244 *
1245 * @since 5.2
1246 *
1247 * @return void
1248 */
1249 public static function include_embed_form_icons() {
1250 _deprecated_function( __METHOD__, '5.3' );
1251 }
1252
1253 /**
1254 * @deprecated 1.07.05 This is still referenced in the API add on as of v1.13.
1255 * @codeCoverageIgnore
1256 *
1257 * @param array $atts
1258 * @return string
1259 */
1260 public static function get_form_shortcode( $atts ) {
1261 _deprecated_function( __FUNCTION__, '1.07.05', 'FrmFormsController::get_form_shortcode' );
1262 return FrmFormsController::get_form_shortcode( $atts );
1263 }
1264
1265 /**
1266 * Handles Floating Links' scripts and styles enqueueing.
1267 *
1268 * @since 6.4
1269 *
1270 * @param string $plugin_url URL of the plugin.
1271 * @param string $version Current version of the plugin.
1272 * @return void
1273 */
1274 private static function enqueue_floating_links( $plugin_url, $version ) {
1275 if ( ! $plugin_url || ! $version ) {
1276 // If any required parameters are missing, exit early.
1277 return;
1278 }
1279
1280 // Enqueue the Floating Links styles.
1281 wp_enqueue_style( 's11-floating-links', $plugin_url . '/css/packages/s11-floating-links.css', array(), $version );
1282
1283 // Enqueue the Floating Links script.
1284 wp_enqueue_script( 's11-floating-links', $plugin_url . '/js/packages/floating-links/s11-floating-links.js', array(), $version, true );
1285
1286 // Enqueue the config script.
1287 wp_enqueue_script( 's11-floating-links-config', $plugin_url . '/js/packages/floating-links/config.js', array( 'wp-i18n' ), $version, true );
1288
1289 if ( function_exists( 'wp_set_script_translations' ) ) {
1290 wp_set_script_translations( 's11-floating-links-config', 's11-' );
1291 }
1292
1293 $floating_links_data = array(
1294 'proIsInstalled' => FrmAppHelper::pro_is_installed(),
1295 );
1296 wp_localize_script( 's11-floating-links-config', 's11FloatingLinksData', $floating_links_data );
1297
1298 /**
1299 * Prompt Pro to load additional floating links scripts.
1300 * This is used to include images in the Inbox SlideIn when Pro is active.
1301 *
1302 * @since 6.8.4
1303 */
1304 do_action( 'frm_enqueue_floating_links' );
1305 }
1306 }
1307