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

1,552 lines 42.7 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.0' );
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 'medium' => '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 wp_enqueue_script( 'admin-widgets' );
736 wp_enqueue_style( 'widgets' );
737 self::maybe_deregister_popper2();
738 wp_enqueue_script( 'formidable_admin' );
739 wp_set_script_translations( 'formidable_admin', 'formidable' );
740 wp_enqueue_script( 'formidable_embed' );
741 wp_set_script_translations( 'formidable_embed', 'formidable' );
742 FrmAppHelper::localize_script( 'admin' );
743
744 wp_enqueue_style( 'formidable-animations' );
745 wp_enqueue_style( 'formidable-admin' );
746 if ( 'formidable-styles' !== $page && 'formidable-styles2' !== $page ) {
747 wp_enqueue_style( 'formidable-grids' );
748 self::maybe_enqueue_dropzone_css( $page );
749 } else {
750 wp_enqueue_style( 'formidable-grids' );
751 }
752
753 if ( 'formidable-entries' === $page ) {
754 // Load front end js for entries.
755 wp_enqueue_script( 'formidable' );
756
757 // Registers and enqueues the entries page scripts.
758 wp_register_script( 'formidable_entries', $plugin_url . '/js/admin/entries.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
759 wp_enqueue_script( 'formidable_entries' );
760 }
761
762 do_action( 'frm_enqueue_builder_scripts' );
763 self::include_upgrade_overlay();
764 self::include_info_overlay();
765 } elseif ( FrmAppHelper::is_view_builder_page() ) {
766 if ( isset( $_REQUEST['post_type'] ) ) {
767 $post_type = sanitize_title( wp_unslash( $_REQUEST['post_type'] ) );
768 } elseif ( isset( $_REQUEST['post'] ) && absint( $_REQUEST['post'] ) ) {
769 $post = get_post( absint( wp_unslash( $_REQUEST['post'] ) ) );
770 if ( ! $post ) {
771 return;
772 }
773 $post_type = $post->post_type;
774 } else {
775 return;
776 }
777
778 if ( $post_type === 'frm_display' ) {
779 self::enqueue_legacy_views_assets();
780 }
781 }//end if
782
783 if ( 'formidable-addons' === $page ) {
784 wp_register_script( 'formidable_addons', $plugin_url . '/js/admin/addons.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
785 wp_enqueue_script( 'formidable_addons' );
786 }
787
788 self::enqueue_builder_assets( $plugin_url, $version );
789 }
790
791 /**
792 * Enqueue the Form Builder assets.
793 *
794 * @since 6.24
795 *
796 * @param string $plugin_url The plugin URL.
797 * @param string $version The plugin version.
798 * @return void
799 */
800 private static function enqueue_builder_assets( $plugin_url, $version ) {
801 wp_register_style( 'formidable-settings-components', $plugin_url . '/css/admin/frm-settings-components.css', array( 'formidable-admin', 'formidable-grids' ), $version );
802 wp_register_script( 'formidable-settings-components', $plugin_url . '/js/formidable-settings-components.js', array( 'formidable_admin' ), $version, true );
803
804 if ( ! FrmAppHelper::is_form_builder_page() ) {
805 return;
806 }
807
808 wp_enqueue_style( 'formidable-settings-components' );
809 wp_enqueue_script( 'formidable-settings-components' );
810 }
811
812 /**
813 * Avoid loading dropzone CSS on the form list page. It isn't required there.
814 *
815 * @since 6.11
816 *
817 * @param string $page
818 * @return void
819 */
820 private static function maybe_enqueue_dropzone_css( $page ) {
821 if ( ! FrmAppHelper::pro_is_installed() ) {
822 return;
823 }
824
825 $should_avoid_loading_dropzone = 'formidable' === $page && ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
826 if ( ! $should_avoid_loading_dropzone ) {
827 wp_enqueue_style( 'formidable-dropzone' );
828 }
829 }
830
831 /**
832 * The floating links are not shown on every page.
833 * They are also not shown if white labeling is being used.
834 *
835 * @since 6.8.4
836 *
837 * @return bool
838 */
839 private static function should_show_floating_links() {
840 if ( ! FrmAppHelper::is_formidable_branding() ) {
841 return false;
842 }
843
844 return FrmAppHelper::is_formidable_admin() &&
845 ! FrmAppHelper::is_style_editor_page() &&
846 ! FrmAppHelper::is_admin_page( 'formidable-views-editor' ) &&
847 ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
848 }
849
850 /**
851 * @since 6.3.2
852 *
853 * @return void
854 */
855 public static function admin_enqueue_scripts() {
856 self::load_wp_admin_style();
857 self::maybe_force_formidable_block_on_gutenberg_page();
858
859 if ( FrmAppHelper::is_admin_page( 'formidable-settings' ) ) {
860 wp_enqueue_style( FrmDashboardController::PAGE_SLUG, FrmAppHelper::plugin_url() . '/css/admin/dashboard.css', array(), FrmAppHelper::plugin_version() );
861 }
862
863 FrmUsageController::load_scripts();
864 }
865
866 /**
867 * Enqueue required assets for the Legacy Views editor (Views v4.x).
868 *
869 * @since 6.1.2
870 *
871 * @return void
872 */
873 private static function enqueue_legacy_views_assets() {
874 wp_enqueue_style( 'formidable-grids' );
875 wp_enqueue_script( 'jquery-ui-draggable' );
876 self::maybe_deregister_popper2();
877 wp_enqueue_script( 'formidable_admin' );
878 wp_add_inline_style(
879 'formidable-admin',
880 '
881 .frm-white-body.post-type-frm_display .columns-2 {
882 display: block;
883 overflow: visible;
884 }
885
886 .frm-white-body.post-type-frm_display .columns-2 > div {
887 overflow-y: hidden;
888 }
889
890 .frm-white-body.post-type-frm_display #titlediv #title-prompt-text {
891 padding: 3px 0 0 10px;
892 }
893
894 .post-type-frm_display #field-search-input,
895 .post-type-frm_display #advanced-search-input {
896 flex: 1;
897 }
898 '
899 );
900 wp_enqueue_style( 'formidable-admin' );
901 wp_enqueue_script( 'formidable_legacy_views', FrmAppHelper::plugin_url() . '/js/admin/legacy-views.js', array( 'jquery', 'formidable_admin' ), FrmAppHelper::plugin_version() );
902 FrmAppHelper::localize_script( 'admin' );
903 self::include_info_overlay();
904 }
905
906 /**
907 * Fix a Duplicator Pro conflict because it uses Popper 2. See issue #3459.
908 *
909 * @since 5.2.02.01
910 *
911 * @return void
912 */
913 private static function maybe_deregister_popper2() {
914 global $wp_scripts;
915
916 if ( ! array_key_exists( 'popper', $wp_scripts->registered ) ) {
917 return;
918 }
919
920 $popper = $wp_scripts->registered['popper'];
921 if ( version_compare( $popper->ver, '2.0', '>=' ) ) {
922 wp_deregister_script( 'popper' );
923 self::register_popper1();
924 }
925 }
926
927 /**
928 * Register Popper required for Bootstrap 4.
929 *
930 * @since 5.2.02.01
931 *
932 * @return void
933 */
934 private static function register_popper1() {
935 if ( ! self::should_register_popper() ) {
936 return;
937 }
938 wp_register_script( 'popper', FrmAppHelper::plugin_url() . '/js/popper.min.js', array( 'jquery' ), '1.16.0', true );
939 }
940
941 /**
942 * Only register popper on Formidable pages.
943 * This helps to avoid popper conflicts on other plugin pages, including the WP Bakery page editor.
944 *
945 * @since 6.11.1
946 *
947 * @return bool
948 */
949 private static function should_register_popper() {
950 global $pagenow;
951
952 $post_id = FrmAppHelper::simple_get( 'post', 'absint' );
953 if ( 'post.php' === $pagenow && $post_id && 'frm_display' === get_post_type( $post_id ) ) {
954 return true;
955 }
956
957 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
958 $is_views_post_type = 'frm_display' === $post_type;
959 if ( in_array( $pagenow, array( 'post-new.php', 'edit.php' ), true ) && $is_views_post_type ) {
960 return true;
961 }
962
963 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
964 if ( strpos( $page, 'formidable' ) === 0 ) {
965 return true;
966 }
967
968 return in_array( $pagenow, array( 'term.php', 'edit-tags.php' ), true ) && FrmAppHelper::simple_get( 'taxonomy' ) === 'frm_application';
969 }
970
971 /**
972 * Automatically insert a Formidable block when loading Gutenberg when $_GET['frmForm' is set.
973 *
974 * @since 5.2
975 *
976 * @return void
977 */
978 private static function maybe_force_formidable_block_on_gutenberg_page() {
979 global $pagenow;
980 if ( 'post.php' !== $pagenow ) {
981 return;
982 }
983
984 $form_id = FrmAppHelper::simple_get( 'frmForm', 'absint' );
985 if ( ! $form_id ) {
986 return;
987 }
988
989 self::add_js_to_inject_gutenberg_block( 'formidable/simple-form', 'formId', $form_id );
990 }
991
992 /**
993 * @since 5.3
994 *
995 * @param string $block_name
996 * @param string $object_key
997 * @param array|string $object_id
998 *
999 * @return void
1000 */
1001 public static function add_js_to_inject_gutenberg_block( $block_name, $object_key, $object_id ) {
1002 require FrmAppHelper::plugin_path() . '/classes/views/shared/edit-page-js.php';
1003 }
1004
1005 /**
1006 * @return void
1007 */
1008 public static function load_lang() {
1009 load_plugin_textdomain( 'formidable', false, FrmAppHelper::plugin_folder() . '/languages/' );
1010 }
1011
1012 /**
1013 * Check if the styles are updated when a form is loaded on the front-end
1014 *
1015 * @since 3.0.1
1016 *
1017 * @return void
1018 */
1019 public static function maybe_update_styles() {
1020 if ( self::needs_update() ) {
1021 self::network_upgrade_site();
1022 }
1023 }
1024
1025 /**
1026 * @since 3.0
1027 *
1028 * @return void
1029 */
1030 public static function create_rest_routes() {
1031 $args = array(
1032 'methods' => 'GET',
1033 'callback' => 'FrmAppController::api_install',
1034 'permission_callback' => __CLASS__ . '::can_update_db',
1035 );
1036
1037 register_rest_route( 'frm-admin/v1', '/install', $args );
1038
1039 $args = array(
1040 'methods' => 'GET',
1041 'callback' => 'FrmAddonsController::install_addon_api',
1042 'permission_callback' => 'FrmAddonsController::can_install_addon_api',
1043 );
1044
1045 register_rest_route( 'frm-admin/v1', '/install-addon', $args );
1046 }
1047
1048 /**
1049 * Make sure the install is only being run when we tell it to.
1050 * We don't want to run manually by people calling the API.
1051 *
1052 * @since 4.06.02
1053 */
1054 public static function can_update_db() {
1055 return get_transient( 'frm_updating_api' );
1056 }
1057
1058 /**
1059 * Run silent upgrade on each site in the network during a network upgrade.
1060 * Update database settings for all sites in a network during network upgrade process.
1061 *
1062 * @since 2.0.1
1063 *
1064 * @param int $blog_id Blog ID.
1065 *
1066 * @return void
1067 */
1068 public static function network_upgrade_site( $blog_id = 0 ) {
1069 // Flag to check if install is happening as intended.
1070 set_transient( 'frm_updating_api', true, MINUTE_IN_SECONDS );
1071 $request = new WP_REST_Request( 'GET', '/frm-admin/v1/install' );
1072
1073 self::maybe_add_wp_site_health();
1074
1075 if ( $blog_id ) {
1076 switch_to_blog( $blog_id );
1077 $response = rest_do_request( $request );
1078 restore_current_blog();
1079 } else {
1080 $response = rest_do_request( $request );
1081 }
1082
1083 if ( $response->is_error() ) {
1084 // if the remove post fails, use javascript instead
1085 add_action( 'admin_notices', 'FrmAppController::install_js_fallback' );
1086 }
1087 }
1088
1089 /**
1090 * Make sure WP_Site_Health has been included because it is required when calling rest_do_request.
1091 * Check first that the file exists because WP_Site_Health was only introduced in WordPress 5.2.
1092 *
1093 * @return void
1094 */
1095 private static function maybe_add_wp_site_health() {
1096 if ( ! class_exists( 'WP_Site_Health' ) ) {
1097 $wp_site_health_path = ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
1098 if ( file_exists( $wp_site_health_path ) ) {
1099 require_once $wp_site_health_path;
1100 }
1101 }
1102 }
1103
1104 /**
1105 * @since 3.0
1106 *
1107 * @return true
1108 */
1109 public static function api_install() {
1110 delete_transient( 'frm_updating_api' );
1111 if ( self::needs_update() ) {
1112 $running = get_option( 'frm_install_running' );
1113 if ( false === $running || $running < strtotime( '-5 minutes' ) ) {
1114 update_option( 'frm_install_running', time(), 'no' );
1115 self::install();
1116 delete_option( 'frm_install_running' );
1117 }
1118 }
1119
1120 return true;
1121 }
1122
1123 /**
1124 * Silent database upgrade (no redirect).
1125 * Called via ajax request during network upgrade process.
1126 *
1127 * @since 2.0.1
1128 *
1129 * @return void
1130 */
1131 public static function ajax_install() {
1132 FrmAppHelper::permission_check( 'frm_change_settings' );
1133 check_ajax_referer( 'frm_ajax', 'nonce' );
1134 self::api_install();
1135 wp_die();
1136 }
1137
1138 /**
1139 * @return void
1140 */
1141 public static function install() {
1142 $frmdb = new FrmMigrate();
1143 $frmdb->upgrade();
1144 }
1145
1146 /**
1147 * @return void
1148 */
1149 public static function uninstall() {
1150 FrmAppHelper::permission_check( 'administrator' );
1151 check_ajax_referer( 'frm_ajax', 'nonce' );
1152
1153 $frmdb = new FrmMigrate();
1154 $frmdb->uninstall();
1155
1156 // Disable the plugin and redirect after uninstall so the tables don't get added right back.
1157 $plugins = array( FrmAppHelper::plugin_folder() . '/formidable.php', 'formidable-pro/formidable-pro.php' );
1158 deactivate_plugins( $plugins, false, false );
1159 echo esc_url_raw( admin_url( 'plugins.php?deactivate=true' ) );
1160
1161 wp_die();
1162 }
1163
1164 public static function drop_tables( $tables ) {
1165 global $wpdb;
1166 $tables[] = $wpdb->prefix . 'frm_fields';
1167 $tables[] = $wpdb->prefix . 'frm_forms';
1168 $tables[] = $wpdb->prefix . 'frm_items';
1169 $tables[] = $wpdb->prefix . 'frm_item_metas';
1170
1171 return $tables;
1172 }
1173
1174 /**
1175 * @return void
1176 */
1177 public static function deauthorize() {
1178 FrmAppHelper::permission_check( 'frm_change_settings' );
1179 check_ajax_referer( 'frm_ajax', 'nonce' );
1180
1181 delete_option( 'frmpro-credentials' );
1182 delete_option( 'frmpro-authorized' );
1183 delete_site_option( 'frmpro-credentials' );
1184 delete_site_option( 'frmpro-authorized' );
1185 wp_die();
1186 }
1187
1188 /**
1189 * This is triggered when Formidable is activated.
1190 *
1191 * @return void
1192 */
1193 public static function handle_activation() {
1194 self::maybe_activate_payment_cron();
1195 }
1196
1197 /**
1198 * The payment cron is unscheduled when Formidable is deactivated.
1199 * We need to add it back again on activation if Stripe is configured.
1200 *
1201 * @since 6.5
1202 *
1203 * @return void
1204 */
1205 private static function maybe_activate_payment_cron() {
1206 if ( ! FrmStrpLiteConnectHelper::stripe_connect_is_setup() ) {
1207 return;
1208 }
1209
1210 FrmTransLiteAppController::maybe_schedule_cron();
1211 }
1212
1213 public static function set_footer_text( $text ) {
1214 if ( FrmAppHelper::is_formidable_admin() ) {
1215 $text = '';
1216 }
1217
1218 return $text;
1219 }
1220
1221 /**
1222 * Add admin footer links.
1223 *
1224 * @since 6.4.1
1225 *
1226 * @return void
1227 */
1228 public static function add_admin_footer_links() {
1229 FrmFormsController::include_device_too_small_message();
1230 if ( self::should_show_footer_links() ) {
1231 include FrmAppHelper::plugin_path() . '/classes/views/shared/admin-footer-links.php';
1232 }
1233 }
1234
1235 /**
1236 * Check if the footer links should be shown.
1237 *
1238 * @since 6.7
1239 *
1240 * @return bool
1241 */
1242 private static function should_show_footer_links() {
1243 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
1244 $is_formidable_page = FrmAppHelper::is_formidable_admin() || 'frm_logs' === $post_type;
1245 $show_footer_links = $is_formidable_page;
1246 if ( FrmAppHelper::is_full_screen() || ! FrmAppHelper::is_formidable_branding() ) {
1247 $show_footer_links = false;
1248 }
1249
1250 /**
1251 * Filter whether to show the Formidable footer links.
1252 *
1253 * @since 6.7
1254 *
1255 * @param bool $show_footer_links
1256 * @return bool
1257 */
1258 return apply_filters( 'frm_show_footer_links', $show_footer_links );
1259 }
1260
1261 /**
1262 * Show an error modal and terminate the script execution.
1263 *
1264 * @since 6.7
1265 *
1266 * @param array $error_args Arguments that control the behavior of the error modal.
1267 *
1268 * @return void
1269 */
1270 public static function show_error_modal( $error_args ) {
1271 add_filter( 'frm_show_footer_links', '__return_false' );
1272
1273 $defaults = array(
1274 'title' => '',
1275 'body' => '',
1276 'cancel_url' => '',
1277 'cancel_classes' => '',
1278 'continue_url' => '',
1279 'continue_classes' => '',
1280 'icon' => 'frm_lock_simple',
1281 );
1282
1283 $error_args = wp_parse_args( $error_args, $defaults );
1284 if ( ! isset( $error_args['cancel_text'] ) && ! empty( $error_args['cancel_url'] ) ) {
1285 $error_args['cancel_text'] = __( 'Cancel', 'formidable' );
1286 }
1287
1288 if ( ! isset( $error_args['continue_text'] ) && ! empty( $error_args['continue_url'] ) ) {
1289 $error_args['continue_text'] = __( 'Continue', 'formidable' );
1290 }
1291
1292 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/error-modal.php';
1293 }
1294
1295 /**
1296 * Handles Floating Links' scripts and styles enqueueing.
1297 *
1298 * @since 6.4
1299 *
1300 * @param string $plugin_url URL of the plugin.
1301 * @param string $version Current version of the plugin.
1302 * @return void
1303 */
1304 private static function enqueue_floating_links( $plugin_url, $version ) {
1305 if ( ! $plugin_url || ! $version ) {
1306 // If any required parameters are missing, exit early.
1307 return;
1308 }
1309
1310 // Enqueue the Floating Links styles.
1311 wp_enqueue_style( 's11-floating-links', $plugin_url . '/css/packages/s11-floating-links.css', array(), $version );
1312
1313 // Enqueue the Floating Links script.
1314 wp_enqueue_script( 's11-floating-links', $plugin_url . '/js/packages/floating-links/s11-floating-links.js', array( 'formidable_admin' ), $version, true );
1315
1316 // Enqueue the config script.
1317 wp_enqueue_script( 's11-floating-links-config', $plugin_url . '/js/packages/floating-links/config.js', array( 'wp-i18n' ), $version, true );
1318
1319 if ( function_exists( 'wp_set_script_translations' ) ) {
1320 wp_set_script_translations( 's11-floating-links-config', 's11-' );
1321 }
1322
1323 $floating_links_data = array(
1324 'proIsInstalled' => FrmAppHelper::pro_is_installed(),
1325 );
1326 wp_localize_script( 's11-floating-links-config', 's11FloatingLinksData', $floating_links_data );
1327
1328 /**
1329 * Prompt Pro to load additional floating links scripts.
1330 * This is used to include images in the Inbox SlideIn when Pro is active.
1331 *
1332 * @since 6.8.4
1333 */
1334 do_action( 'frm_enqueue_floating_links' );
1335 }
1336
1337 /**
1338 * Check if we are in our admin pages.
1339 *
1340 * @return bool
1341 */
1342 private static function in_our_pages() {
1343 global $current_screen, $pagenow;
1344 if ( FrmAppHelper::is_formidable_admin() ) {
1345 return true;
1346 }
1347
1348 if ( ! empty( $current_screen->post_type ) && 'frm_logs' === $current_screen->post_type ) {
1349 return true;
1350 }
1351
1352 if ( in_array( $pagenow, array( 'term.php', 'edit-tags.php' ), true ) && 'frm_application' === FrmAppHelper::simple_get( 'taxonomy' ) ) {
1353 return true;
1354 }
1355
1356 return false;
1357 }
1358
1359 /**
1360 * Handles actions related to the current screen.
1361 *
1362 * @since 6.19
1363 *
1364 * @return void
1365 */
1366 public static function handle_current_screen() {
1367 if ( ! self::in_our_pages() ) {
1368 return;
1369 }
1370
1371 self::filter_admin_notices();
1372 self::remember_custom_sort();
1373 }
1374
1375 /**
1376 * Hide all third-parties admin notices only in our admin pages.
1377 *
1378 * @return void
1379 */
1380 public static function filter_admin_notices() {
1381 $actions = array(
1382 'admin_notices',
1383 'network_admin_notices',
1384 'user_admin_notices',
1385 'all_admin_notices',
1386 );
1387
1388 global $wp_filter;
1389
1390 foreach ( $actions as $action ) {
1391 if ( empty( $wp_filter[ $action ]->callbacks ) ) {
1392 continue;
1393 }
1394 foreach ( $wp_filter[ $action ]->callbacks as $priority => $callbacks ) {
1395 foreach ( $callbacks as $callback_name => $callback ) {
1396 if ( self::is_our_callback_string( $callback_name ) || self::is_our_callback_array( $callback ) ) {
1397 continue;
1398 }
1399 unset( $wp_filter[ $action ]->callbacks[ $priority ][ $callback_name ] );
1400 }
1401 }
1402 }
1403 }
1404
1405 /**
1406 * Remembers and applies user-specific sorting preferences.
1407 *
1408 * @return void
1409 */
1410 private static function remember_custom_sort() {
1411 $screen = get_current_screen();
1412 if ( ! $screen ) {
1413 return;
1414 }
1415
1416 if ( ! FrmAppHelper::is_admin_list_page() && ! FrmAppHelper::is_admin_list_page( 'formidable-entries' ) ) {
1417 return;
1418 }
1419
1420 $orderby = FrmAppHelper::get_param( 'orderby' );
1421
1422 if ( ! $orderby ) {
1423 return;
1424 }
1425
1426 $user_id = get_current_user_id();
1427 $meta_key = 'frm_preferred_list_sort_' . $screen->id;
1428 $order = FrmAppHelper::get_param( 'order' );
1429
1430 $new_sort = array(
1431 'orderby' => $orderby,
1432 'order' => $order,
1433 );
1434
1435 $current_sort = get_user_meta( $user_id, $meta_key, true );
1436
1437 if ( $new_sort !== $current_sort ) {
1438 update_user_meta(
1439 $user_id,
1440 $meta_key,
1441 array(
1442 'orderby' => $orderby,
1443 'order' => $order,
1444 )
1445 );
1446 }
1447 }
1448
1449 /**
1450 * Retrieve and apply any saved sorting preferences for the current screen.
1451 *
1452 * @since 6.19
1453 *
1454 * @param string &$orderby Reference to the current 'orderby' parameter.
1455 * @param string &$order Reference to the current 'order' parameter.
1456 * @return void
1457 */
1458 public static function apply_saved_sort_preference( &$orderby, &$order ) {
1459 if ( ! function_exists( 'get_current_screen' ) ) {
1460 return;
1461 }
1462
1463 $screen = get_current_screen();
1464 if ( ! $screen ) {
1465 return;
1466 }
1467
1468 $user_id = get_current_user_id();
1469 $preferred_list_sort = get_user_meta( $user_id, 'frm_preferred_list_sort_' . $screen->id, true );
1470
1471 if ( is_array( $preferred_list_sort ) && ! empty( $preferred_list_sort['orderby'] ) ) {
1472 $orderby = $preferred_list_sort['orderby'];
1473
1474 if ( ! empty( $preferred_list_sort['order'] ) ) {
1475 $order = $preferred_list_sort['order'];
1476 }
1477 }
1478 }
1479
1480 /**
1481 * Validate that the callback name is ours not from third-party.
1482 *
1483 * @param string $callback_name WordPress callback name.
1484 *
1485 * @return bool
1486 */
1487 private static function is_our_callback_string( $callback_name ) {
1488 return 0 === stripos( $callback_name, 'frm' );
1489 }
1490
1491 /**
1492 * Validate that the callback array is ours not from third-party.
1493 *
1494 * @param array $callback WordPress callback array.
1495 *
1496 * @return bool
1497 */
1498 private static function is_our_callback_array( $callback ) {
1499 return ! empty( $callback['function'] ) &&
1500 is_array( $callback['function'] ) &&
1501 ! empty( $callback['function'][0] ) &&
1502 self::is_our_callback_string( is_object( $callback['function'][0] ) ? get_class( $callback['function'][0] ) : $callback['function'][0] );
1503 }
1504
1505 /**
1506 * In some cases, the DB tables may fail to install.
1507 * This function tries to add them again when the user clicks the link to try again
1508 * from the given inbox notice.
1509 *
1510 * @since 6.19
1511 */
1512 private static function add_missing_tables() {
1513 FrmAppHelper::permission_check( 'frm_view_forms' );
1514
1515 $inbox = new FrmInbox();
1516 $error = $inbox->check_for_error();
1517
1518 if ( ! $error || 'failed-to-create-tables' !== $error['key'] ) {
1519 // Confirm the inbox item with this CTA exists.
1520 wp_safe_redirect( admin_url( 'admin.php?page=formidable' ) );
1521 exit;
1522 }
1523
1524 global $wpdb;
1525 $exists = $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->prefix . 'frm_forms' ) );
1526
1527 if ( $exists ) {
1528 // Exit early if the table already exists.
1529 wp_safe_redirect( admin_url( 'admin.php?page=formidable' ) );
1530 exit;
1531 }
1532
1533 delete_option( 'frm_db_version' );
1534 wp_safe_redirect( admin_url( 'admin.php?page=formidable' ) );
1535 exit;
1536 }
1537
1538 /**
1539 * Handles the small screen proceed action.
1540 *
1541 * @since 6.21
1542 *
1543 * @return void
1544 */
1545 public static function small_screen_proceed() {
1546 FrmAppHelper::permission_check( 'frm_view_forms' );
1547 check_ajax_referer( 'frm_ajax', 'nonce' );
1548 update_user_option( get_current_user_id(), 'frm_ignore_small_screen_warning', true );
1549 wp_send_json_success();
1550 }
1551 }
1552