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

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