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

1,724 lines 46.4 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
14 if ( ! current_user_can( 'frm_view_forms' ) ) {
15 return;
16 }
17
18 $menu_name = FrmAppHelper::get_menu_name();
19
20 if ( in_array( $menu_name, array( 'Formidable', 'Forms' ), true ) ) {
21 $menu_name .= wp_kses_post( FrmInboxController::get_notice_count() );
22 }
23
24 add_menu_page( 'Formidable', $menu_name, 'frm_view_forms', 'formidable', 'FrmFormsController::route', self::menu_icon(), self::get_menu_position() );
25 }
26
27 /**
28 * @return int
29 */
30 private static function get_menu_position() {
31 return (int) apply_filters( 'frm_menu_position', 29 );
32 }
33
34 /**
35 * @since 3.05
36 *
37 * @return string
38 */
39 private static function menu_icon() {
40 $icon = FrmAppHelper::svg_logo(
41 array(
42 'fill' => '#a0a5aa',
43 'orange' => '#a0a5aa',
44 )
45 );
46 $icon = 'data:image/svg+xml;base64,' . base64_encode( $icon );
47
48 return apply_filters( 'frm_icon', $icon );
49 }
50
51 /**
52 * @since 3.0
53 *
54 * @param string $classes
55 *
56 * @return string
57 */
58 public static function add_admin_class( $classes ) {
59 if ( self::is_white_page() ) {
60 $classes .= ' frm-white-body ';
61 $classes .= self::get_os();
62
63 $page = str_replace( 'formidable-', '', FrmAppHelper::simple_get( 'page', 'sanitize_title' ) );
64
65 if ( ! $page || $page === 'formidable' ) {
66 $action = FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
67
68 if ( in_array( $action, array( 'settings', 'edit', 'list' ), true ) ) {
69 $page .= $action;
70 } else {
71 $page = $action;
72 }
73 }
74
75 if ( $page ) {
76 $classes .= ' frm-admin-page-' . $page;
77 }
78 }
79
80 if ( self::is_grey_page() ) {
81 $classes .= ' frm-grey-body ';
82 }
83
84 if ( FrmAppHelper::is_full_screen() ) {
85 $add_class = '';
86
87 if ( self::get_full_screen_setting() ) {
88 $add_class = ' frm-full-screen is-fullscreen-mode';
89
90 // Load the CSS for .is-fullscreen-mode.
91 wp_enqueue_style( 'wp-edit-post' );
92 }
93
94 $classes .= apply_filters( 'frm_admin_full_screen_class', $add_class );
95 }
96
97 if ( ! FrmAppHelper::pro_is_installed() ) {
98 $classes .= ' frm-lite ';
99 }
100
101 if ( get_user_setting( 'unfold' ) && 'f' !== get_user_setting( 'mfold' ) ) {
102 $classes .= ' frm-unfold ';
103 }
104
105 return $classes;
106 }
107
108 /**
109 * Get the full screen mode setting from the block editor.
110 *
111 * @since 6.1
112 *
113 * @return bool
114 */
115 private static function get_full_screen_setting() {
116 global $wpdb;
117 $meta_key = $wpdb->get_blog_prefix() . 'persisted_preferences';
118 $prefs = get_user_meta( get_current_user_id(), $meta_key, true );
119
120 if ( $prefs && isset( $prefs['core/edit-post']['fullscreenMode'] ) ) {
121 return $prefs['core/edit-post']['fullscreenMode'];
122 }
123
124 return true;
125 }
126
127 /**
128 * @since 4.0
129 *
130 * @return string
131 */
132 private static function get_os() {
133 $agent = strtolower( FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' ) );
134 $os = '';
135
136 if ( str_contains( $agent, 'mac' ) ) {
137 $os = ' osx';
138 } elseif ( str_contains( $agent, 'linux' ) ) {
139 $os = ' linux';
140 } elseif ( str_contains( $agent, 'windows' ) ) {
141 $os = ' windows';
142 }
143
144 return $os;
145 }
146
147 /**
148 * @since 3.0
149 *
150 * @return bool
151 */
152 private static function is_white_page() {
153 $white_pages = array(
154 'formidable',
155 'formidable-entries',
156 'formidable-views',
157 'formidable-views-editor',
158 'formidable-addons',
159 'formidable-import',
160 'formidable-settings',
161 'formidable-styles',
162 'formidable-styles2',
163 'formidable-inbox',
164 FrmFormTemplatesController::PAGE_SLUG,
165 FrmOnboardingWizardController::PAGE_SLUG,
166 );
167
168 if ( self::is_white_payments_page() ) {
169 $white_pages[] = 'formidable-payments';
170 }
171
172 $is_white_page = self::is_page_in_list( $white_pages ) || self::is_grey_page() || FrmAppHelper::is_view_builder_page();
173
174 /**
175 * Allow another add on to style a page as a Formidable "white page", which adds a white background color.
176 *
177 * @since 5.3
178 *
179 * @param bool $is_white_page
180 */
181 return apply_filters( 'frm_is_white_page', $is_white_page );
182 }
183
184 /**
185 * Check if the payments page should be styled as a white page.
186 * Fallback to the Stripe, Authorize.Net, or PayPal add on for the "edit" action since
187 * Stripe Lite does not have an edit view. Also fallback for bulk deleting, since that
188 * isn't built into Lite. The pages we fall back to should not be styled as white pages.
189 *
190 * @since 6.27
191 *
192 * @return bool
193 */
194 private static function is_white_payments_page() {
195 $action = FrmAppHelper::simple_get( 'action', 'sanitize_title' );
196 $on_edit_page = in_array( $action, array( 'edit', 'new' ), true );
197 return ! $on_edit_page && 'bulk_delete' !== $action;
198 }
199
200 /**
201 * Add a grey bg instead of white.
202 *
203 * @since 6.8
204 *
205 * @return bool
206 */
207 private static function is_grey_page() {
208 $grey_pages = array(
209 'formidable-applications',
210 'formidable-dashboard',
211 'formidable-views',
212 );
213
214 $is_grey_page = self::is_page_in_list( $grey_pages );
215
216 /**
217 * Filter to change FF wrapper background to grey.
218 *
219 * @since 6.8
220 *
221 * @param bool $is_grey_page
222 *
223 * @return bool
224 */
225 return apply_filters( 'frm_is_grey_page', $is_grey_page );
226 }
227
228 /**
229 * @since 6.8
230 *
231 * @param array $pages A list of page names to check.
232 *
233 * @return bool
234 */
235 private static function is_page_in_list( $pages ) {
236 $get_page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
237 return in_array( $get_page, $pages, true );
238 }
239
240 /**
241 * @return void
242 */
243 public static function load_wp_admin_style() {
244 FrmAppHelper::load_font_style();
245 }
246
247 /**
248 * @param int|object $form
249 * @param bool $show_nav
250 * @param string $title
251 *
252 * @psalm-param 'hide'|'show' $title
253 *
254 * @return void
255 */
256 public static function get_form_nav( $form, $show_nav = false, $title = 'show' ) {
257 $show_nav = FrmAppHelper::get_param( 'show_nav', $show_nav, 'get', 'absint' );
258
259 if ( ! $show_nav || ! $form ) {
260 return;
261 }
262
263 FrmForm::maybe_get_form( $form );
264
265 if ( ! is_object( $form ) ) {
266 return;
267 }
268
269 $id = $form->id;
270 $current_page = self::get_current_page();
271 $nav_items = self::get_form_nav_items( $form );
272
273 include FrmAppHelper::plugin_path() . '/classes/views/shared/form-nav.php';
274 }
275
276 /**
277 * @return string
278 */
279 private static function get_current_page() {
280 if ( FrmAppHelper::is_view_builder_page() ) {
281 return 'frm_display';
282 }
283
284 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
285 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title', 'None' );
286
287 return isset( $_GET['page'] ) ? $page : $post_type;
288 }
289
290 /**
291 * @param object $form
292 *
293 * @return array
294 */
295 private static function get_form_nav_items( $form ) {
296 $id = $form->parent_form_id ? $form->parent_form_id : $form->id;
297
298 $nav_items = array(
299 array(
300 'link' => FrmForm::get_edit_link( $id ),
301 'label' => __( 'Build', 'formidable' ),
302 'current' => array( 'edit', 'new', 'duplicate' ),
303 'page' => 'formidable',
304 'permission' => 'frm_edit_forms',
305 ),
306 array(
307 'link' => FrmStylesHelper::get_list_url( $id ),
308 'label' => __( 'Style', 'formidable' ),
309 'current' => array(),
310 'page' => 'formidable-styles',
311 'permission' => 'frm_edit_forms',
312 ),
313 array(
314 'link' => admin_url( 'admin.php?page=formidable&frm_action=settings&id=' . absint( $id ) ),
315 'label' => __( 'Settings', 'formidable' ),
316 'current' => array( 'settings' ),
317 'page' => 'formidable',
318 'permission' => 'frm_edit_forms',
319 ),
320 array(
321 'link' => admin_url( 'admin.php?page=formidable-entries&frm_action=list&form=' . absint( $id ) ),
322 'label' => __( 'Entries', 'formidable' ),
323 'current' => array(),
324 'page' => 'formidable-entries',
325 'permission' => 'frm_view_entries',
326 ),
327 );
328
329 $views_installed = is_callable( 'FrmProAppHelper::views_is_installed' ) && FrmProAppHelper::views_is_installed();
330
331 if ( ! $views_installed ) {
332 $nav_items[] = array(
333 'link' => admin_url( 'admin.php?page=formidable-views&form=' . absint( $id ) ),
334 'label' => __( 'Views', 'formidable' ),
335 'current' => array(),
336 'page' => 'formidable-views',
337 'permission' => 'frm_view_entries',
338 'atts' => array(
339 'class' => 'frm_noallow',
340 ),
341 );
342 }
343
344 // Let people know reports and views exist.
345 if ( ! FrmAppHelper::pro_is_installed() ) {
346 $nav_items[] = array(
347 'link' => admin_url( 'admin.php?page=formidable&frm_action=lite-reports&form=' . absint( $id ) ),
348 'label' => __( 'Reports', 'formidable' ),
349 'current' => array( 'reports' ),
350 'page' => 'formidable',
351 'permission' => 'frm_view_entries',
352 'atts' => array(
353 'class' => 'frm_noallow',
354 ),
355 );
356 }
357
358 $nav_args = array(
359 'form_id' => $id,
360 'form' => $form,
361 );
362
363 return (array) apply_filters( 'frm_form_nav_list', $nav_items, $nav_args );
364 }
365
366 /**
367 * Adds a settings link to the plugins page
368 *
369 * @param array $links
370 *
371 * @return array
372 */
373 public static function settings_link( $links ) {
374 $settings = array();
375
376 if ( ! FrmAppHelper::pro_is_installed() ) {
377 if ( FrmAddonsController::is_license_expired() ) {
378 $label = __( 'Renew', 'formidable' );
379 } else {
380 $label = FrmSalesApi::get_best_sale_value( 'plugin_page_cta_text' );
381
382 if ( ! $label ) {
383 $label = __( 'Upgrade to Pro', 'formidable' );
384 }
385 }
386
387 $upgrade_link = FrmSalesApi::get_best_sale_value( 'plugin_page_cta_link' );
388
389 if ( $upgrade_link ) {
390 $upgrade_link = FrmAppHelper::maybe_add_missing_utm( $upgrade_link, array( 'medium' => 'plugin-row' ) );
391 } else {
392 $upgrade_link = FrmAppHelper::admin_upgrade_link( 'plugin-row' );
393 }
394
395 $settings[] = '<a href="' . esc_url( $upgrade_link ) . '" target="_blank" rel="noopener"><b style="color:#1da867;font-weight:700;">' . esc_html( $label ) . '</b></a>';
396 }//end if
397
398 $settings[] = '<a href="' . esc_url( admin_url( 'admin.php?page=formidable' ) ) . '">' . esc_html__( 'Build a Form', 'formidable' ) . '</a>';
399
400 return array_merge( $settings, $links );
401 }
402
403 /**
404 * @return void
405 */
406 public static function pro_get_started_headline() {
407 self::review_request();
408 FrmAppHelper::min_pro_version_notice( '6.20' );
409 }
410
411 /**
412 * Add admin notices as needed for reviews
413 *
414 * @since 3.04.03
415 *
416 * @return void
417 */
418 private static function review_request() {
419 $reviews = new FrmReviews();
420 $reviews->review_request();
421 }
422
423 /**
424 * Save the request to hide the review
425 *
426 * @since 3.04.03
427 *
428 * @return void
429 */
430 public static function dismiss_review() {
431 FrmAppHelper::permission_check( 'frm_change_settings' );
432 check_ajax_referer( 'frm_ajax', 'nonce' );
433
434 $reviews = new FrmReviews();
435 $reviews->dismiss_review();
436 }
437
438 /**
439 * @since 3.04.02
440 *
441 * @return void
442 */
443 public static function include_upgrade_overlay() {
444 self::enqueue_dialog_assets();
445 add_action( 'admin_footer', 'FrmAppController::upgrade_overlay_html' );
446 }
447
448 /**
449 * Enqueue scripts and styles required for modals.
450 *
451 * @since 5.3
452 *
453 * @return void
454 */
455 public static function enqueue_dialog_assets() {
456 wp_enqueue_script( 'jquery-ui-dialog' );
457 wp_enqueue_style( 'jquery-ui-dialog' );
458 }
459
460 /**
461 * @since 3.06.03
462 *
463 * @return void
464 */
465 public static function upgrade_overlay_html() {
466 $is_pro = FrmAppHelper::pro_is_installed();
467 $upgrade_link = array(
468 'medium' => 'builder',
469 'content' => 'upgrade',
470 );
471 $default_link = FrmAppHelper::admin_upgrade_link( $upgrade_link );
472 $plugin_path = FrmAppHelper::plugin_path();
473 $shared_path = $plugin_path . '/classes/views/shared/';
474
475 include $shared_path . 'upgrade_overlay.php';
476 include $shared_path . 'confirm-overlay.php';
477 }
478
479 /**
480 * Create a basic form with an email field.
481 *
482 * @param string $form_key
483 * @param string $title
484 * @param string $description
485 *
486 * @return void
487 */
488 public static function api_email_form( $form_key, $title = '', $description = '' ) {
489 $user = wp_get_current_user();
490 $args = array(
491 'api_url' => 'https://sandbox.formidableforms.com/api/wp-json/frm/v2/forms/' . $form_key . '?return=html&exclude_script=jquery&exclude_style=formidable-css',
492 'title' => $title,
493 'description' => $description,
494 );
495 require FrmAppHelper::plugin_path() . '/classes/views/form-templates/modals/leave-email-modal.php';
496 }
497
498 /**
499 * @return void
500 */
501 public static function include_info_overlay() {
502 self::enqueue_dialog_assets();
503 add_action( 'admin_footer', 'FrmAppController::info_overlay_html' );
504 }
505
506 /**
507 * @return void
508 */
509 public static function info_overlay_html() {
510 include FrmAppHelper::plugin_path() . '/classes/views/shared/info-overlay.php';
511 }
512
513 /**
514 * @since 3.04.02
515 *
516 * @return void
517 */
518 public static function remove_upsells() {
519 remove_action( 'frm_before_settings', 'FrmSettingsController::license_box' );
520 remove_action( 'frm_after_settings_tabs', 'FrmSettingsController::settings_cta' );
521 remove_action( 'frm_after_field_options', 'FrmFormsController::logic_tip' );
522 }
523
524 /**
525 * If there are CURL problems on this server, wp_remote_post won't work for installing
526 * Use a javascript fallback instead.
527 *
528 * @since 2.0.3
529 *
530 * @return void
531 */
532 public static function install_js_fallback() {
533 FrmAppHelper::load_admin_wide_js();
534 // phpcs:disable Generic.WhiteSpace.ScopeIndent
535 ?>
536 <div id="frm_install_message"></div>
537 <script>jQuery(document).ready( frm_install_now );</script>
538 <?php
539 // phpcs:enable Generic.WhiteSpace.ScopeIndent
540 }
541
542 /**
543 * Check if the database is outdated
544 *
545 * @since 2.0.1
546 *
547 * @return bool
548 */
549 public static function needs_update() {
550 $needs_upgrade = self::compare_for_update(
551 array(
552 'option' => 'frm_db_version',
553 'new_db_version' => FrmAppHelper::$db_version,
554 'new_plugin_version' => FrmAppHelper::plugin_version(),
555 )
556 );
557
558 if ( ! $needs_upgrade ) {
559 return apply_filters( 'frm_db_needs_upgrade', $needs_upgrade );
560 }
561
562 return $needs_upgrade;
563 }
564
565 /**
566 * Check both version number and DB number for changes
567 *
568 * @since 3.0.04
569 *
570 * @param array $atts
571 *
572 * @return bool
573 */
574 public static function compare_for_update( $atts ) {
575 $db_version = get_option( $atts['option'] );
576
577 if ( ! str_contains( $db_version, '-' ) ) {
578 return true;
579 }
580
581 $last_upgrade = explode( '-', $db_version );
582 $needs_db_upgrade = (int) $last_upgrade[1] < (int) $atts['new_db_version'];
583
584 if ( $needs_db_upgrade ) {
585 return true;
586 }
587
588 // New plugin version.
589 return version_compare( $last_upgrade[0], $atts['new_plugin_version'], '<' );
590 }
591
592 /**
593 * Check for database update and trigger js loading
594 *
595 * @since 2.0.1
596 *
597 * @return void
598 */
599 public static function admin_init() {
600 if ( FrmAppHelper::get_param( 'delete_all' ) && FrmAppHelper::is_admin_page( 'formidable' ) && 'trash' === FrmAppHelper::get_param( 'form_type' ) ) {
601 FrmFormsController::delete_all();
602 }
603
604 if ( FrmAppHelper::is_admin_page( 'formidable' ) && 'duplicate' === FrmAppHelper::get_param( 'frm_action' ) ) {
605 FrmFormsController::duplicate();
606 }
607
608 if ( FrmAppHelper::is_admin_page( 'formidable' ) && FrmAppHelper::simple_get( 'frm_add_tables' ) ) {
609 self::add_missing_tables();
610 }
611
612 if ( FrmAppHelper::is_style_editor_page() && 'save' === FrmAppHelper::get_param( 'frm_action' ) ) {
613 // Hook in earlier than FrmStylesController::route so we can redirect before the headers have been sent.
614 FrmStylesController::save_style();
615 }
616
617 if ( 'formidable-pro-upgrade' === FrmAppHelper::get_param( 'page' ) && ! FrmAppHelper::pro_is_installed() && current_user_can( 'frm_view_forms' ) ) {
618 $redirect = FrmSalesApi::get_best_sale_value( 'menu_cta_link' );
619 $utm = array(
620 'campaign' => 'upgrade',
621 'content' => 'submenu-upgrade',
622 );
623
624 $redirect = $redirect ? FrmAppHelper::maybe_add_missing_utm( $redirect, $utm ) : FrmAppHelper::admin_upgrade_link( $utm );
625
626 wp_redirect( $redirect );
627 die();
628 }
629
630 // Register personal data hooks.
631 new FrmPersonalData();
632
633 if ( ! FrmAppHelper::doing_ajax() && self::needs_update() ) {
634 self::network_upgrade_site();
635 }
636
637 if ( ! FrmAppHelper::doing_ajax() ) {
638 // Don't continue during ajax calls
639 self::admin_js();
640 }
641
642 self::trigger_page_load_hooks();
643
644 if ( ! FrmAppHelper::is_admin_page( 'formidable' ) ) {
645 return;
646 }
647
648 // Redirect to the "Form Templates" page if the 'frm_action' parameter matches specific actions.
649 // This provides backward compatibility for old addons that use legacy modal templates.
650 $action = FrmAppHelper::get_param( 'frm_action' );
651 $trigger_name_modal = FrmAppHelper::get_param( 'triggerNewFormModal' );
652
653 if ( $trigger_name_modal || in_array( $action, array( 'add_new', 'list_templates' ), true ) ) {
654 $application_id = FrmAppHelper::simple_get( 'applicationId', 'absint' );
655 $url_param = $application_id ? '&applicationId=' . $application_id : '';
656
657 wp_safe_redirect( admin_url( 'admin.php?page=' . FrmFormTemplatesController::PAGE_SLUG . $url_param ) );
658 exit;
659 }
660
661 FrmInbox::maybe_disable_screen_options();
662 }
663
664 /**
665 * Get the current page and check for a possible function to trigger.
666 * If a class name matches the page name, and the class has a load_page() method, trigger it.
667 *
668 * @since 6.8
669 *
670 * @return void
671 */
672 private static function trigger_page_load_hooks() {
673 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
674
675 if ( ! str_starts_with( $page, 'formidable-' ) ) {
676 // Only trigger hooks on Formidable pages.
677 return;
678 }
679
680 $page = str_replace( array( 'formidable-', '-' ), array( '', ' ' ), $page );
681 $page = str_replace( ' ', '', ucwords( $page ) );
682 $class = 'Frm' . $page . 'Controller';
683
684 if ( class_exists( $class ) && method_exists( $class, 'load_page' ) ) {
685 call_user_func( array( $class, 'load_page' ) );
686 }
687 }
688
689 /**
690 * @return void
691 */
692 public static function admin_js() {
693 $plugin_url = FrmAppHelper::plugin_url();
694 $version = FrmAppHelper::plugin_version();
695 $is_pro_min_v6_28 = FrmAppHelper::pro_is_installed() && FrmAppHelper::meets_min_pro_version( '6.28' );
696 $frm_components_dependencies = $is_pro_min_v6_28 ? array( 'formidable_admin', 'formidable-pro-web-components' ) : array( 'formidable_admin' );
697
698 FrmAppHelper::load_admin_wide_js();
699 // Register component assets early to ensure they can be enqueued later in controllers.
700 wp_register_style( 'formidable-animations', $plugin_url . '/css/admin/animations.css', array(), $version );
701
702 if ( class_exists( 'FrmOverlayController' ) ) {
703 // This should always exist.
704 // But it may not have loaded properly when updating the plugin.
705 FrmOverlayController::register_assets();
706 }
707
708 wp_register_style( 'formidable_admin_global', $plugin_url . '/css/admin/frm_admin_global.css', array(), $version );
709 wp_enqueue_style( 'formidable_admin_global' );
710
711 wp_register_style( 'formidable-admin', $plugin_url . '/css/frm_admin.css', array(), $version );
712 wp_register_style( 'formidable-grids', $plugin_url . '/css/frm_grids.css', array(), $version );
713
714 wp_register_script( 'formidable_dom', $plugin_url . '/js/admin/dom.js', array( 'jquery', 'jquery-ui-dialog', 'wp-i18n' ), $version, true );
715 wp_register_script( 'formidable_embed', $plugin_url . '/js/admin/embed.js', array( 'formidable_dom', 'jquery-ui-autocomplete' ), $version, true );
716 self::register_popper2();
717 wp_register_script( 'bootstrap_tooltip', $plugin_url . '/js/bootstrap.min.js', array( 'jquery', 'popper' ), '5.0.2', true );
718
719 $settings_js_vars = array(
720 'currencies' => FrmCurrencyHelper::get_currencies(),
721 );
722 wp_register_script( 'formidable_settings', $plugin_url . '/js/admin/settings.js', array(), $version, true );
723 wp_localize_script( 'formidable_settings', 'frmSettings', $settings_js_vars );
724 wp_register_script( 'formidable-web-components', $plugin_url . '/js/formidable-web-components.js', $frm_components_dependencies, $version, true );
725
726 if ( self::should_show_floating_links() ) {
727 self::enqueue_floating_links( $plugin_url, $version );
728 }
729
730 wp_register_script( 'formidable_admin', $plugin_url . '/js/formidable_admin.js', self::get_admin_js_dependencies(), $version, true );
731
732 if ( FrmAppHelper::on_form_listing_page() ) {
733 // For the existing page dropdown in the Form embed modal.
734 wp_enqueue_script( 'jquery-ui-autocomplete' );
735 }
736
737 wp_register_script( 'bootstrap-multiselect', $plugin_url . '/js/bootstrap-multiselect.js', array( 'jquery', 'bootstrap_tooltip', 'popper' ), '2.0', true );
738
739 if ( ! class_exists( 'FrmTransHooksController', false ) ) {
740 FrmTransLiteAppController::hide_gateway_fields_in_builder();
741 }
742
743 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
744 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
745
746 global $pagenow;
747
748 if ( str_starts_with( $page, 'formidable' ) || ( $pagenow === 'edit.php' && $post_type === 'frm_display' ) ) {
749 self::enqueue_global_settings_scripts( $page );
750
751 wp_enqueue_script( 'admin-widgets' );
752 wp_enqueue_style( 'widgets' );
753 self::maybe_deregister_popper1();
754 wp_enqueue_script( 'formidable_admin' );
755 wp_set_script_translations( 'formidable_admin', 'formidable' );
756 wp_enqueue_script( 'formidable_embed' );
757 wp_set_script_translations( 'formidable_embed', 'formidable' );
758 FrmAppHelper::localize_script( 'admin' );
759
760 wp_enqueue_style( 'formidable-animations' );
761 wp_enqueue_style( 'formidable-admin' );
762
763 if ( 'formidable-styles' !== $page && 'formidable-styles2' !== $page ) {
764 wp_enqueue_style( 'formidable-grids' );
765 self::maybe_enqueue_dropzone_css( $page );
766 } else {
767 wp_enqueue_style( 'formidable-grids' );
768 }
769
770 if ( 'formidable-entries' === $page ) {
771 // Load front end js for entries.
772 wp_enqueue_script( 'formidable' );
773
774 // Registers and enqueues the entries page scripts.
775 wp_register_script( 'formidable_entries', $plugin_url . '/js/admin/entries.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
776 wp_enqueue_script( 'formidable_entries' );
777 }
778
779 do_action( 'frm_enqueue_builder_scripts' );
780 self::maybe_enqueue_legacy_paypal_assets();
781 self::include_upgrade_overlay();
782 self::include_info_overlay();
783 } elseif ( FrmAppHelper::is_view_builder_page() ) {
784 if ( isset( $_REQUEST['post_type'] ) ) {
785 $post_type = sanitize_title( wp_unslash( $_REQUEST['post_type'] ) );
786 } elseif ( isset( $_REQUEST['post'] ) && absint( $_REQUEST['post'] ) ) {
787 $post = get_post( absint( wp_unslash( $_REQUEST['post'] ) ) );
788
789 if ( ! $post ) {
790 return;
791 }
792
793 $post_type = $post->post_type;
794 } else {
795 return;
796 }
797
798 if ( $post_type === 'frm_display' ) {
799 self::enqueue_legacy_views_assets();
800 }
801 }//end if
802
803 if ( 'formidable-addons' === $page ) {
804 wp_register_script( 'formidable_addons', $plugin_url . '/js/admin/addons.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
805 wp_enqueue_script( 'formidable_addons' );
806 }
807
808 self::enqueue_builder_assets( $plugin_url, $version );
809 }
810
811 /**
812 * @since 6.27
813 *
814 * @return array
815 */
816 private static function get_admin_js_dependencies() {
817 $dependencies = array(
818 'formidable_admin_global',
819 'jquery',
820 'jquery-ui-core',
821 'jquery-ui-draggable',
822 'jquery-ui-sortable',
823 'bootstrap_tooltip',
824 'bootstrap-multiselect',
825 'wp-i18n',
826 // Required in WP versions older than 5.7
827 'wp-hooks',
828 'formidable_dom',
829 'formidable_embed',
830 );
831
832 if ( FrmAppHelper::is_style_editor_page( 'edit' ) ) {
833 // We only need to load the color picker when editing styles.
834 $dependencies[] = 'wp-color-picker';
835 }
836
837 return $dependencies;
838 }
839
840 /**
841 * Enqueue the Form Builder assets.
842 *
843 * @since 6.24
844 *
845 * @param string $plugin_url The plugin URL.
846 * @param string $version The plugin version.
847 *
848 * @return void
849 */
850 private static function enqueue_builder_assets( $plugin_url, $version ) {
851 wp_register_style( 'formidable-settings-components', $plugin_url . '/css/admin/frm-settings-components.css', array( 'formidable-admin', 'formidable-grids' ), $version );
852 wp_register_script( 'formidable-settings-components', $plugin_url . '/js/formidable-settings-components.js', array( 'formidable_admin' ), $version, true );
853
854 if ( ! FrmAppHelper::is_form_builder_page() ) {
855 return;
856 }
857
858 wp_enqueue_style( 'formidable-settings-components' );
859 wp_enqueue_script( 'formidable-settings-components' );
860 }
861
862 /**
863 * Enqueues global settings scripts.
864 *
865 * @param string $page The `page` param in URL.
866 *
867 * @return void
868 */
869 private static function enqueue_global_settings_scripts( $page ) {
870 if ( 'formidable-settings' !== $page ) {
871 return;
872 }
873
874 wp_enqueue_style( 'wp-color-picker' );
875 wp_enqueue_script( 'formidable_settings' );
876 }
877
878 /**
879 * Avoid loading dropzone CSS on the form list page. It isn't required there.
880 *
881 * @since 6.11
882 *
883 * @param string $page
884 *
885 * @return void
886 */
887 private static function maybe_enqueue_dropzone_css( $page ) {
888 if ( ! FrmAppHelper::pro_is_installed() ) {
889 return;
890 }
891
892 $should_avoid_loading_dropzone = 'formidable' === $page && ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
893
894 if ( ! $should_avoid_loading_dropzone ) {
895 wp_enqueue_style( 'formidable-dropzone' );
896 }
897 }
898
899 /**
900 * The floating links are not shown on every page.
901 * They are also not shown if white labeling is being used.
902 *
903 * @since 6.8.4
904 *
905 * @return bool
906 */
907 private static function should_show_floating_links() {
908 if ( ! FrmAppHelper::is_formidable_branding() ) {
909 return false;
910 }
911
912 $should_show = FrmAppHelper::is_formidable_admin() && ! FrmAppHelper::is_style_editor_page() && ! FrmAppHelper::is_admin_page( 'formidable-views-editor' ) && ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
913
914 /**
915 * Filters whether the floating links should be displayed.
916 *
917 * @since 6.25.1
918 *
919 * @param bool $should_show Whether the floating links should be shown.
920 */
921 return apply_filters( 'frm_should_show_floating_links', $should_show );
922 }
923
924 /**
925 * @since 6.3.2
926 *
927 * @return void
928 */
929 public static function admin_enqueue_scripts() {
930 self::load_wp_admin_style();
931 self::maybe_force_formidable_block_on_gutenberg_page();
932
933 if ( FrmAppHelper::is_admin_page( 'formidable-settings' ) ) {
934 wp_enqueue_style( FrmDashboardController::PAGE_SLUG, FrmAppHelper::plugin_url() . '/css/admin/dashboard.css', array(), FrmAppHelper::plugin_version() );
935 }
936
937 FrmUsageController::load_scripts();
938 }
939
940 /**
941 * Enqueue legacy PayPal action settings styles when the PayPal add-on is active.
942 *
943 * @since 6.31
944 *
945 * @return void
946 */
947 private static function maybe_enqueue_legacy_paypal_assets() {
948 if ( ! FrmAppHelper::is_form_builder_page() || ! class_exists( 'FrmPaymentsController' ) ) {
949 return;
950 }
951
952 wp_register_style(
953 'formidable-legacy-paypal',
954 FrmAppHelper::plugin_url() . '/css/admin/frm-legacy-paypal.css',
955 array( 'formidable-admin' ),
956 FrmAppHelper::plugin_version()
957 );
958 wp_enqueue_style( 'formidable-legacy-paypal' );
959 }
960
961 /**
962 * Enqueue required assets for the Legacy Views editor (Views v4.x).
963 *
964 * @since 6.1.2
965 *
966 * @return void
967 */
968 private static function enqueue_legacy_views_assets() {
969 wp_enqueue_style( 'formidable-grids' );
970 wp_enqueue_script( 'jquery-ui-draggable' );
971 self::maybe_deregister_popper1();
972 wp_enqueue_script( 'formidable_admin' );
973 wp_add_inline_style(
974 'formidable-admin',
975 '
976 .frm-white-body.post-type-frm_display .columns-2 {
977 display: block;
978 overflow: visible;
979 }
980
981 .frm-white-body.post-type-frm_display .columns-2 > div {
982 overflow-y: hidden;
983 }
984
985 .frm-white-body.post-type-frm_display #titlediv #title-prompt-text {
986 padding: 3px 0 0 10px;
987 }
988
989 .post-type-frm_display #field-search-input,
990 .post-type-frm_display #advanced-search-input {
991 flex: 1;
992 }
993 '
994 );
995 wp_enqueue_style( 'formidable-admin' );
996 wp_enqueue_script( 'formidable_legacy_views', FrmAppHelper::plugin_url() . '/js/admin/legacy-views.js', array( 'jquery', 'formidable_admin' ), FrmAppHelper::plugin_version() ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
997 FrmAppHelper::localize_script( 'admin' );
998 self::include_info_overlay();
999 }
1000
1001 /**
1002 * Unregister Popper if the registered version is outdated.
1003 *
1004 * @since 6.26
1005 *
1006 * @return void
1007 */
1008 private static function maybe_deregister_popper1() {
1009 global $wp_scripts;
1010
1011 if ( ! array_key_exists( 'popper', $wp_scripts->registered ) ) {
1012 return;
1013 }
1014
1015 $popper = $wp_scripts->registered['popper'];
1016
1017 if ( ! version_compare( $popper->ver, '2.0', '<' ) ) {
1018 return;
1019 }
1020
1021 wp_deregister_script( 'popper' );
1022 self::register_popper2();
1023 }
1024
1025 /**
1026 * Register Popper required for Bootstrap 5.
1027 *
1028 * @since 6.26
1029 *
1030 * @return void
1031 */
1032 private static function register_popper2() {
1033 if ( ! self::should_register_popper() ) {
1034 return;
1035 }
1036 wp_register_script( 'popper', FrmAppHelper::plugin_url() . '/js/popper.min.js', array(), '2.11.8', true );
1037 }
1038
1039 /**
1040 * Only register popper on Formidable pages.
1041 * This helps to avoid popper conflicts on other plugin pages, including the WP Bakery page editor.
1042 *
1043 * @since 6.11.1
1044 *
1045 * @return bool
1046 */
1047 private static function should_register_popper() {
1048 global $pagenow;
1049
1050 $post_id = FrmAppHelper::simple_get( 'post', 'absint' );
1051
1052 if ( 'post.php' === $pagenow && $post_id && 'frm_display' === get_post_type( $post_id ) ) {
1053 return true;
1054 }
1055
1056 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
1057 $is_views_post_type = 'frm_display' === $post_type;
1058
1059 if ( in_array( $pagenow, array( 'post-new.php', 'edit.php' ), true ) && $is_views_post_type ) {
1060 return true;
1061 }
1062
1063 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
1064
1065 if ( str_starts_with( $page, 'formidable' ) ) {
1066 return true;
1067 }
1068
1069 return in_array( $pagenow, array( 'term.php', 'edit-tags.php' ), true ) && FrmAppHelper::simple_get( 'taxonomy' ) === 'frm_application';
1070 }
1071
1072 /**
1073 * Automatically insert a Formidable block when loading Gutenberg when $_GET['frmForm' is set.
1074 *
1075 * @since 5.2
1076 *
1077 * @return void
1078 */
1079 private static function maybe_force_formidable_block_on_gutenberg_page() {
1080 global $pagenow;
1081
1082 if ( 'post.php' !== $pagenow ) {
1083 return;
1084 }
1085
1086 $form_id = FrmAppHelper::simple_get( 'frmForm', 'absint' );
1087
1088 if ( ! $form_id ) {
1089 return;
1090 }
1091
1092 self::add_js_to_inject_gutenberg_block( 'formidable/simple-form', 'formId', $form_id );
1093 }
1094
1095 /**
1096 * @since 5.3
1097 *
1098 * @param string $block_name
1099 * @param string $object_key
1100 * @param array|string $object_id
1101 *
1102 * @return void
1103 */
1104 public static function add_js_to_inject_gutenberg_block( $block_name, $object_key, $object_id ) {
1105 require FrmAppHelper::plugin_path() . '/classes/views/shared/edit-page-js.php';
1106 }
1107
1108 /**
1109 * @return void
1110 */
1111 public static function load_lang() {
1112 load_plugin_textdomain( 'formidable', false, FrmAppHelper::plugin_folder() . '/languages/' );
1113 }
1114
1115 /**
1116 * Check if the styles are updated when a form is loaded on the front-end
1117 *
1118 * @since 3.0.1
1119 *
1120 * @return void
1121 */
1122 public static function maybe_update_styles() {
1123 if ( self::needs_update() ) {
1124 self::network_upgrade_site();
1125 }
1126 }
1127
1128 /**
1129 * @since 3.0
1130 *
1131 * @return void
1132 */
1133 public static function create_rest_routes() {
1134 $args = array(
1135 'methods' => 'GET',
1136 'callback' => 'FrmAppController::api_install',
1137 'permission_callback' => self::class . '::can_update_db',
1138 );
1139
1140 register_rest_route( 'frm-admin/v1', '/install', $args );
1141
1142 $args = array(
1143 'methods' => 'GET',
1144 'callback' => 'FrmAddonsController::install_addon_api',
1145 'permission_callback' => 'FrmAddonsController::can_install_addon_api',
1146 );
1147
1148 register_rest_route( 'frm-admin/v1', '/install-addon', $args );
1149 }
1150
1151 /**
1152 * Make sure the install is only being run when we tell it to.
1153 * We don't want to run manually by people calling the API.
1154 *
1155 * @since 4.06.02
1156 *
1157 * @return bool
1158 */
1159 public static function can_update_db() {
1160 return get_transient( 'frm_updating_api' );
1161 }
1162
1163 /**
1164 * Run silent upgrade on each site in the network during a network upgrade.
1165 * Update database settings for all sites in a network during network upgrade process.
1166 *
1167 * @since 2.0.1
1168 *
1169 * @param int $blog_id Blog ID.
1170 *
1171 * @return void
1172 */
1173 public static function network_upgrade_site( $blog_id = 0 ) {
1174 // Flag to check if install is happening as intended.
1175 set_transient( 'frm_updating_api', true, MINUTE_IN_SECONDS );
1176 $request = new WP_REST_Request( 'GET', '/frm-admin/v1/install' );
1177
1178 self::maybe_add_wp_site_health();
1179
1180 if ( $blog_id ) {
1181 switch_to_blog( $blog_id );
1182 $response = rest_do_request( $request );
1183 restore_current_blog();
1184 } else {
1185 $response = rest_do_request( $request );
1186 }
1187
1188 if ( $response->is_error() ) {
1189 // If the remove post fails, use javascript instead
1190 add_action( 'admin_notices', 'FrmAppController::install_js_fallback' );
1191 }
1192 }
1193
1194 /**
1195 * Make sure WP_Site_Health has been included because it is required when calling rest_do_request.
1196 * Check first that the file exists because WP_Site_Health was only introduced in WordPress 5.2.
1197 *
1198 * @return void
1199 */
1200 private static function maybe_add_wp_site_health() {
1201 if ( class_exists( 'WP_Site_Health' ) ) {
1202 return;
1203 }
1204
1205 $wp_site_health_path = ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
1206
1207 if ( file_exists( $wp_site_health_path ) ) {
1208 require_once $wp_site_health_path;
1209 }
1210 }
1211
1212 /**
1213 * @since 3.0
1214 *
1215 * @return true
1216 */
1217 public static function api_install() {
1218 delete_transient( 'frm_updating_api' );
1219
1220 if ( self::needs_update() ) {
1221 $running = get_option( 'frm_install_running' );
1222
1223 if ( false === $running || $running < strtotime( '-5 minutes' ) ) {
1224 update_option( 'frm_install_running', time(), false );
1225 self::install();
1226 delete_option( 'frm_install_running' );
1227 }
1228 }
1229
1230 return true;
1231 }
1232
1233 /**
1234 * Silent database upgrade (no redirect).
1235 * Called via ajax request during network upgrade process.
1236 *
1237 * @since 2.0.1
1238 *
1239 * @return void
1240 */
1241 public static function ajax_install() {
1242 FrmAppHelper::permission_check( 'frm_change_settings' );
1243 check_ajax_referer( 'frm_ajax', 'nonce' );
1244 self::api_install();
1245 wp_die();
1246 }
1247
1248 /**
1249 * @return void
1250 */
1251 public static function install() {
1252 $frmdb = new FrmMigrate();
1253 $frmdb->upgrade();
1254 }
1255
1256 /**
1257 * @return void
1258 */
1259 public static function uninstall() {
1260 FrmAppHelper::permission_check( 'administrator' );
1261 check_ajax_referer( 'frm_ajax', 'nonce' );
1262
1263 $frmdb = new FrmMigrate();
1264 $frmdb->uninstall();
1265
1266 // Disable the plugin and redirect after uninstall so the tables don't get added right back.
1267 $plugins = array( FrmAppHelper::plugin_folder() . '/formidable.php', 'formidable-pro/formidable-pro.php' );
1268 deactivate_plugins( $plugins, false, false );
1269 echo esc_url_raw( admin_url( 'plugins.php?deactivate=true' ) );
1270
1271 wp_die();
1272 }
1273
1274 /**
1275 * @param array $tables
1276 *
1277 * @return array
1278 */
1279 public static function drop_tables( $tables ) {
1280 global $wpdb;
1281 $tables[] = $wpdb->prefix . 'frm_fields';
1282 $tables[] = $wpdb->prefix . 'frm_forms';
1283 $tables[] = $wpdb->prefix . 'frm_items';
1284 $tables[] = $wpdb->prefix . 'frm_item_metas';
1285
1286 return $tables;
1287 }
1288
1289 /**
1290 * @return void
1291 */
1292 public static function deauthorize() {
1293 FrmAppHelper::permission_check( 'frm_change_settings' );
1294 check_ajax_referer( 'frm_ajax', 'nonce' );
1295
1296 delete_option( 'frmpro-credentials' );
1297 delete_option( 'frmpro-authorized' );
1298 delete_site_option( 'frmpro-credentials' );
1299 delete_site_option( 'frmpro-authorized' );
1300 wp_die();
1301 }
1302
1303 /**
1304 * This is triggered when Formidable is activated.
1305 *
1306 * @return void
1307 */
1308 public static function handle_activation() {
1309 self::maybe_activate_payment_cron();
1310 }
1311
1312 /**
1313 * The payment cron is unscheduled when Formidable is deactivated.
1314 * We need to add it back again on activation if Stripe is configured.
1315 *
1316 * @since 6.5
1317 *
1318 * @return void
1319 */
1320 private static function maybe_activate_payment_cron() {
1321 if ( ! FrmStrpLiteConnectHelper::stripe_connect_is_setup() ) {
1322 return;
1323 }
1324
1325 FrmTransLiteAppController::maybe_schedule_cron();
1326 }
1327
1328 /**
1329 * @param string $text
1330 *
1331 * @return string
1332 */
1333 public static function set_footer_text( $text ) {
1334 return FrmAppHelper::is_formidable_admin() ? '' : $text;
1335 }
1336
1337 /**
1338 * Add admin footer links.
1339 *
1340 * @since 6.4.1
1341 *
1342 * @return void
1343 */
1344 public static function add_admin_footer_links() {
1345 FrmFormsController::include_device_too_small_message();
1346
1347 if ( self::should_show_footer_links() ) {
1348 include FrmAppHelper::plugin_path() . '/classes/views/shared/admin-footer-links.php';
1349 }
1350 }
1351
1352 /**
1353 * Check if the footer links should be shown.
1354 *
1355 * @since 6.7
1356 *
1357 * @return bool
1358 */
1359 private static function should_show_footer_links() {
1360 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
1361 $is_formidable_page = FrmAppHelper::is_formidable_admin() || 'frm_logs' === $post_type;
1362 $show_footer_links = $is_formidable_page;
1363
1364 if ( FrmAppHelper::is_full_screen() || ! FrmAppHelper::is_formidable_branding() ) {
1365 $show_footer_links = false;
1366 }
1367
1368 /**
1369 * Filter whether to show the Formidable footer links.
1370 *
1371 * @since 6.7
1372 *
1373 * @param bool $show_footer_links
1374 *
1375 * @return bool
1376 */
1377 return apply_filters( 'frm_show_footer_links', $show_footer_links );
1378 }
1379
1380 /**
1381 * Show an error modal and terminate the script execution.
1382 *
1383 * @since 6.7
1384 *
1385 * @param array $error_args Arguments that control the behavior of the error modal.
1386 *
1387 * @return void
1388 */
1389 public static function show_error_modal( $error_args ) {
1390 add_filter( 'frm_show_footer_links', '__return_false' );
1391
1392 $defaults = array(
1393 'title' => '',
1394 'body' => '',
1395 'cancel_url' => '',
1396 'cancel_classes' => '',
1397 'continue_url' => '',
1398 'continue_classes' => '',
1399 'icon' => 'frm_lock_simple',
1400 );
1401
1402 $error_args = wp_parse_args( $error_args, $defaults );
1403
1404 if ( ! isset( $error_args['cancel_text'] ) && ! empty( $error_args['cancel_url'] ) ) {
1405 $error_args['cancel_text'] = __( 'Cancel', 'formidable' );
1406 }
1407
1408 if ( ! isset( $error_args['continue_text'] ) && ! empty( $error_args['continue_url'] ) ) {
1409 $error_args['continue_text'] = __( 'Continue', 'formidable' );
1410 }
1411
1412 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/error-modal.php';
1413 }
1414
1415 /**
1416 * Handles Floating Links' scripts and styles enqueueing.
1417 *
1418 * @since 6.4
1419 *
1420 * @param string $plugin_url URL of the plugin.
1421 * @param string $version Current version of the plugin.
1422 *
1423 * @return void
1424 */
1425 private static function enqueue_floating_links( $plugin_url, $version ) {
1426 if ( ! $plugin_url || ! $version ) {
1427 // If any required parameters are missing, exit early.
1428 return;
1429 }
1430
1431 // Enqueue the Floating Links styles.
1432 wp_enqueue_style( 's11-floating-links', $plugin_url . '/css/packages/s11-floating-links.css', array(), $version );
1433
1434 // Enqueue the Floating Links script.
1435 wp_enqueue_script( 's11-floating-links', $plugin_url . '/js/packages/floating-links/s11-floating-links.js', array( 'formidable_admin' ), $version, true );
1436
1437 // Enqueue the config script.
1438 wp_enqueue_script( 's11-floating-links-config', $plugin_url . '/js/packages/floating-links/config.js', array( 'wp-i18n' ), $version, true );
1439
1440 if ( function_exists( 'wp_set_script_translations' ) ) {
1441 wp_set_script_translations( 's11-floating-links-config', 's11-' );
1442 }
1443
1444 $upgrade_utm = array(
1445 'campaign' => 'floating-links',
1446 'content' => 'floating-links-upgrade',
1447 );
1448 $docs_utm = array(
1449 'campaign' => 'floating-links',
1450 'content' => 'floating-links-docs',
1451 );
1452 $floating_links_data = array(
1453 'proIsInstalled' => FrmAppHelper::pro_is_installed(),
1454 'upgradeUrl' => FrmAppHelper::admin_upgrade_link( $upgrade_utm ),
1455 'documentationUrl' => FrmAppHelper::admin_upgrade_link( $docs_utm, 'knowledgebase/' ),
1456 );
1457 wp_localize_script( 's11-floating-links-config', 's11FloatingLinksData', $floating_links_data );
1458
1459 /**
1460 * Prompt Pro to load additional floating links scripts.
1461 * This is used to include images in the Inbox SlideIn when Pro is active.
1462 *
1463 * @since 6.8.4
1464 */
1465 do_action( 'frm_enqueue_floating_links' );
1466 }
1467
1468 /**
1469 * Check if we are in our admin pages.
1470 *
1471 * @return bool
1472 */
1473 private static function in_our_pages() {
1474 global $current_screen, $pagenow;
1475
1476 if ( FrmAppHelper::is_formidable_admin() ) {
1477 return true;
1478 }
1479
1480 if ( ! empty( $current_screen->post_type ) && 'frm_logs' === $current_screen->post_type ) {
1481 return true;
1482 }
1483
1484 return in_array( $pagenow, array( 'term.php', 'edit-tags.php' ), true ) && 'frm_application' === FrmAppHelper::simple_get( 'taxonomy' );
1485 }
1486
1487 /**
1488 * Handles actions related to the current screen.
1489 *
1490 * @since 6.19
1491 *
1492 * @return void
1493 */
1494 public static function handle_current_screen() {
1495 if ( ! self::in_our_pages() ) {
1496 return;
1497 }
1498
1499 self::filter_admin_notices();
1500 self::remember_custom_sort();
1501 }
1502
1503 /**
1504 * Hide all third-parties admin notices only in our admin pages.
1505 *
1506 * @return void
1507 */
1508 public static function filter_admin_notices() {
1509 $actions = array(
1510 'admin_notices',
1511 'network_admin_notices',
1512 'user_admin_notices',
1513 'all_admin_notices',
1514 );
1515
1516 global $wp_filter;
1517
1518 foreach ( $actions as $action ) {
1519 if ( empty( $wp_filter[ $action ]->callbacks ) ) {
1520 continue;
1521 }
1522
1523 foreach ( $wp_filter[ $action ]->callbacks as $priority => $callbacks ) {
1524 foreach ( $callbacks as $callback_name => $callback ) {
1525 if ( self::is_our_callback_string( $callback_name ) || self::is_our_callback_array( $callback ) ) {
1526 continue;
1527 }
1528 unset( $wp_filter[ $action ]->callbacks[ $priority ][ $callback_name ] );
1529 }
1530 }
1531 }
1532 }
1533
1534 /**
1535 * Remembers and applies user-specific sorting preferences.
1536 *
1537 * @return void
1538 */
1539 private static function remember_custom_sort() {
1540 $meta_key = self::get_sort_pref_user_meta_key();
1541
1542 if ( false === $meta_key ) {
1543 return;
1544 }
1545
1546 $is_form_list = FrmAppHelper::is_admin_list_page();
1547 $is_entry_list = FrmAppHelper::is_admin_list_page( 'formidable-entries' );
1548
1549 if ( ! $is_form_list && ! $is_entry_list ) {
1550 return;
1551 }
1552
1553 $orderby = FrmAppHelper::get_param( 'orderby' );
1554
1555 if ( ! $orderby ) {
1556 return;
1557 }
1558
1559 $user_id = get_current_user_id();
1560 $order = FrmAppHelper::get_param( 'order' );
1561 $new_sort = array(
1562 'orderby' => $orderby,
1563 'order' => $order,
1564 );
1565 $previous_meta = get_user_meta( $user_id, $meta_key, true );
1566 $current_sort = $previous_meta;
1567 $form_id = $is_entry_list ? FrmAppHelper::simple_get( 'form', 'absint' ) : 0;
1568
1569 if ( is_array( $current_sort ) && $form_id && is_int( $form_id ) && isset( $current_sort[ $form_id ] ) ) {
1570 $current_sort = $current_sort[ $form_id ];
1571 }
1572
1573 if ( $new_sort === $current_sort ) {
1574 return;
1575 }
1576
1577 $new_meta = $new_sort;
1578
1579 if ( $is_entry_list && $form_id && is_int( $form_id ) ) {
1580 // Index meta by form ID.
1581 $temp_meta = is_array( $previous_meta ) ? $previous_meta : array();
1582 $temp_meta[ $form_id ] = $new_meta;
1583 $new_meta = $temp_meta;
1584 unset( $temp_meta );
1585 }
1586
1587 update_user_meta( $user_id, $meta_key, $new_meta );
1588 }
1589
1590 /**
1591 * Retrieve and apply any saved sorting preferences for the current screen.
1592 *
1593 * @since 6.19
1594 *
1595 * @param string $orderby Reference to the current 'orderby' parameter.
1596 * @param string $order Reference to the current 'order' parameter.
1597 *
1598 * @return void
1599 */
1600 public static function apply_saved_sort_preference( &$orderby, &$order ) {
1601 $meta_key = self::get_sort_pref_user_meta_key();
1602
1603 if ( false === $meta_key ) {
1604 return;
1605 }
1606
1607 $preferred_list_sort = get_user_meta( get_current_user_id(), $meta_key, true );
1608 $form_id = FrmAppHelper::simple_get( 'form', 'absint' );
1609
1610 if ( is_array( $preferred_list_sort ) && $form_id && is_int( $form_id ) && isset( $preferred_list_sort[ $form_id ] ) ) {
1611 $preferred_list_sort = $preferred_list_sort[ $form_id ];
1612 }
1613
1614 if ( ! is_array( $preferred_list_sort ) || empty( $preferred_list_sort['orderby'] ) ) {
1615 return;
1616 }
1617
1618 $orderby = $preferred_list_sort['orderby'];
1619
1620 if ( ! empty( $preferred_list_sort['order'] ) ) {
1621 $order = $preferred_list_sort['order'];
1622 }
1623 }
1624
1625 /**
1626 * Get a simple user meta key that only includes the screen ID.
1627 *
1628 * @since 6.25.1
1629 *
1630 * @return false|string
1631 */
1632 private static function get_sort_pref_user_meta_key() {
1633 if ( ! function_exists( 'get_current_screen' ) ) {
1634 return false;
1635 }
1636
1637 $screen = get_current_screen();
1638 return $screen ? 'frm_preferred_list_sort_' . $screen->id : false;
1639 }
1640
1641 /**
1642 * Validate that the callback name is ours not from third-party.
1643 *
1644 * @param string $callback_name WordPress callback name.
1645 *
1646 * @return bool
1647 */
1648 private static function is_our_callback_string( $callback_name ) {
1649 return 0 === stripos( $callback_name, 'frm' );
1650 }
1651
1652 /**
1653 * Validate that the callback array is ours not from third-party.
1654 *
1655 * @param array $callback WordPress callback array.
1656 *
1657 * @return bool
1658 */
1659 private static function is_our_callback_array( $callback ) {
1660 return ! empty( $callback['function'] ) && is_array( $callback['function'] ) && ! empty( $callback['function'][0] ) && self::is_our_callback_string( is_object( $callback['function'][0] ) ? get_class( $callback['function'][0] ) : $callback['function'][0] ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
1661 }
1662
1663 /**
1664 * In some cases, the DB tables may fail to install.
1665 * This function tries to add them again when the user clicks the link to try again
1666 * from the given inbox notice.
1667 *
1668 * @since 6.19
1669 */
1670 private static function add_missing_tables() {
1671 FrmAppHelper::permission_check( 'frm_view_forms' );
1672
1673 $error = FrmInbox::check_for_error();
1674
1675 if ( ! $error || 'failed-to-create-tables' !== $error['key'] ) {
1676 // Confirm the inbox item with this CTA exists.
1677 wp_safe_redirect( admin_url( 'admin.php?page=formidable' ) );
1678 exit;
1679 }
1680
1681 global $wpdb;
1682 $exists = $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->prefix . 'frm_forms' ) );
1683
1684 if ( $exists ) {
1685 // Exit early if the table already exists.
1686 wp_safe_redirect( admin_url( 'admin.php?page=formidable' ) );
1687 exit;
1688 }
1689
1690 delete_option( 'frm_db_version' );
1691 wp_safe_redirect( admin_url( 'admin.php?page=formidable' ) );
1692 exit;
1693 }
1694
1695 /**
1696 * Handles the small screen proceed action.
1697 *
1698 * @since 6.21
1699 *
1700 * @return void
1701 */
1702 public static function small_screen_proceed() {
1703 FrmAppHelper::permission_check( 'frm_view_forms' );
1704 check_ajax_referer( 'frm_ajax', 'nonce' );
1705 update_user_option( get_current_user_id(), 'frm_ignore_small_screen_warning', true );
1706 wp_send_json_success();
1707 }
1708
1709 /**
1710 * Enqueue the components scripts.
1711 *
1712 * @since 6.28
1713 *
1714 * @return void
1715 */
1716 public static function enqueue_components_scripts() {
1717 if ( is_callable( array( 'FrmProFormsController', 'enqueue_pro_web_components_script' ) ) ) {
1718 FrmProFormsController::enqueue_pro_web_components_script();
1719 }
1720
1721 wp_enqueue_script( 'formidable-web-components' );
1722 }
1723 }
1724