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

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