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

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