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

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