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

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