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

1,386 lines 38.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_style_editor_page() && 'save' === FrmAppHelper::get_param( 'frm_action' ) ) {
570 // Hook in earlier than FrmStylesController::route so we can redirect before the headers have been sent.
571 FrmStylesController::save_style();
572 }
573
574 if ( 'formidable-pro-upgrade' === FrmAppHelper::get_param( 'page' ) && ! FrmAppHelper::pro_is_installed() && current_user_can( 'frm_view_forms' ) ) {
575 $redirect = FrmSalesApi::get_best_sale_value( 'menu_cta_link' );
576 if ( ! $redirect ) {
577 $redirct = FrmAppHelper::admin_upgrade_link(
578 array(
579 'medium' => 'upgrade',
580 'content' => 'submenu-upgrade',
581 )
582 );
583 }
584
585 wp_redirect( $redirect );
586 die();
587 }
588
589 // Register personal data hooks.
590 new FrmPersonalData();
591
592 if ( ! FrmAppHelper::doing_ajax() && self::needs_update() ) {
593 self::network_upgrade_site();
594 }
595
596 if ( ! FrmAppHelper::doing_ajax() ) {
597 // don't continue during ajax calls
598 self::admin_js();
599 }
600
601 self::trigger_page_load_hooks();
602
603 if ( FrmAppHelper::is_admin_page( 'formidable' ) ) {
604 // Redirect to the "Form Templates" page if the 'frm_action' parameter matches specific actions.
605 // This provides backward compatibility for old addons that use legacy modal templates.
606 $action = FrmAppHelper::get_param( 'frm_action' );
607 $trigger_name_modal = FrmAppHelper::get_param( 'triggerNewFormModal' );
608 if ( $trigger_name_modal || in_array( $action, array( 'add_new', 'list_templates' ), true ) ) {
609 $application_id = FrmAppHelper::simple_get( 'applicationId', 'absint' );
610 $url_param = $application_id ? '&applicationId=' . $application_id : '';
611
612 wp_safe_redirect( admin_url( 'admin.php?page=' . FrmFormTemplatesController::PAGE_SLUG . $url_param ) );
613 exit;
614 }
615
616 FrmInbox::maybe_disable_screen_options();
617 }
618 }
619
620 /**
621 * Get the current page and check for a possible function to trigger.
622 * If a class name matches the page name, and the class has a load_page() method, trigger it.
623 *
624 * @since 6.8
625 *
626 * @return void
627 */
628 private static function trigger_page_load_hooks() {
629 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
630 if ( strpos( $page, 'formidable-' ) !== 0 ) {
631 // Only trigger hooks on Formidable pages.
632 return;
633 }
634
635 $page = str_replace( array( 'formidable-', '-' ), array( '', ' ' ), $page );
636 $page = str_replace( ' ', '', ucwords( $page ) );
637 $class = 'Frm' . $page . 'Controller';
638 if ( class_exists( $class ) && method_exists( $class, 'load_page' ) ) {
639 call_user_func( array( $class, 'load_page' ) );
640 }
641 }
642
643 /**
644 * @return void
645 */
646 public static function admin_js() {
647 $plugin_url = FrmAppHelper::plugin_url();
648 $version = FrmAppHelper::plugin_version();
649
650 FrmAppHelper::load_admin_wide_js();
651
652 // Register component assets early to ensure they can be enqueued later in controllers.
653 wp_register_style( 'formidable-animations', $plugin_url . '/css/admin/animations.css', array(), $version );
654
655 if ( class_exists( 'FrmOverlayController' ) ) {
656 // This should always exist.
657 // But it may not have loaded properly when updating the plugin.
658 FrmOverlayController::register_assets();
659 }
660
661 wp_register_style( 'formidable_admin_global', $plugin_url . '/css/admin/frm_admin_global.css', array(), $version );
662 wp_enqueue_style( 'formidable_admin_global' );
663
664 wp_register_style( 'formidable-admin', $plugin_url . '/css/frm_admin.css', array(), $version );
665 wp_register_style( 'formidable-grids', $plugin_url . '/css/frm_grids.css', array(), $version );
666
667 wp_register_script( 'formidable_dom', $plugin_url . '/js/admin/dom.js', array( 'jquery', 'jquery-ui-dialog', 'wp-i18n' ), $version, true );
668 wp_register_script( 'formidable_embed', $plugin_url . '/js/admin/embed.js', array( 'formidable_dom', 'jquery-ui-autocomplete' ), $version, true );
669 self::register_popper1();
670 wp_register_script( 'bootstrap_tooltip', $plugin_url . '/js/bootstrap.min.js', array( 'jquery', 'popper' ), '4.6.1', true );
671
672 $settings_js_vars = array(
673 'currencies' => FrmCurrencyHelper::get_currencies(),
674 );
675 wp_register_script( 'formidable_settings', $plugin_url . '/js/admin/settings.js', array(), $version, true );
676 wp_localize_script( 'formidable_settings', 'frmSettings', $settings_js_vars );
677
678 if ( self::should_show_floating_links() ) {
679 self::enqueue_floating_links( $plugin_url, $version );
680 }
681
682 $dependencies = array(
683 'formidable_admin_global',
684 'jquery',
685 'jquery-ui-core',
686 'jquery-ui-draggable',
687 'jquery-ui-sortable',
688 'bootstrap_tooltip',
689 'bootstrap-multiselect',
690 'wp-i18n',
691 // Required in WP versions older than 5.7
692 'wp-hooks',
693 'formidable_dom',
694 'formidable_embed',
695 );
696
697 if ( FrmAppHelper::is_style_editor_page( 'edit' ) ) {
698 // We only need to load the color picker when editing styles.
699 $dependencies[] = 'wp-color-picker';
700 }
701
702 wp_register_script( 'formidable_admin', $plugin_url . '/js/formidable_admin.js', $dependencies, $version, true );
703
704 if ( FrmAppHelper::on_form_listing_page() ) {
705 // For the existing page dropdown in the Form embed modal.
706 wp_enqueue_script( 'jquery-ui-autocomplete' );
707 }
708
709 wp_register_script( 'bootstrap-multiselect', $plugin_url . '/js/bootstrap-multiselect.js', array( 'jquery', 'bootstrap_tooltip', 'popper' ), '1.1.1', true );
710
711 if ( ! class_exists( 'FrmTransHooksController', false ) ) {
712 /**
713 * Gateway fields are included for add-on compatibility but we do not want it to be visible.
714 * They do however need to be visible when the payments submodule is active.
715 */
716 wp_add_inline_style(
717 'formidable-admin',
718 '#frm_builder_page li[data-ftype="gateway"] { display: none; }'
719 );
720 }
721
722 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
723 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
724
725 global $pagenow;
726 if ( strpos( $page, 'formidable' ) === 0 || ( $pagenow === 'edit.php' && $post_type === 'frm_display' ) ) {
727
728 wp_enqueue_script( 'admin-widgets' );
729 wp_enqueue_style( 'widgets' );
730 self::maybe_deregister_popper2();
731 wp_enqueue_script( 'formidable_admin' );
732 wp_set_script_translations( 'formidable_admin', 'formidable' );
733 wp_enqueue_script( 'formidable_embed' );
734 wp_set_script_translations( 'formidable_embed', 'formidable' );
735 FrmAppHelper::localize_script( 'admin' );
736
737 wp_enqueue_style( 'formidable-animations' );
738 wp_enqueue_style( 'formidable-admin' );
739 if ( 'formidable-styles' !== $page && 'formidable-styles2' !== $page ) {
740 wp_enqueue_style( 'formidable-grids' );
741 self::maybe_enqueue_dropzone_css( $page );
742 } else {
743 wp_enqueue_style( 'formidable-grids' );
744 }
745
746 if ( 'formidable-entries' === $page ) {
747 // Load front end js for entries.
748 wp_enqueue_script( 'formidable' );
749
750 // Registers and enqueues the entries page scripts.
751 wp_register_script( 'formidable_entries', $plugin_url . '/js/admin/entries.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
752 wp_enqueue_script( 'formidable_entries' );
753 }
754
755 do_action( 'frm_enqueue_builder_scripts' );
756 self::include_upgrade_overlay();
757 self::include_info_overlay();
758 } elseif ( FrmAppHelper::is_view_builder_page() ) {
759 if ( isset( $_REQUEST['post_type'] ) ) {
760 $post_type = sanitize_title( wp_unslash( $_REQUEST['post_type'] ) );
761 } elseif ( isset( $_REQUEST['post'] ) && absint( $_REQUEST['post'] ) ) {
762 $post = get_post( absint( wp_unslash( $_REQUEST['post'] ) ) );
763 if ( ! $post ) {
764 return;
765 }
766 $post_type = $post->post_type;
767 } else {
768 return;
769 }
770
771 if ( $post_type === 'frm_display' ) {
772 self::enqueue_legacy_views_assets();
773 }
774 }//end if
775
776 if ( 'formidable-addons' === $page ) {
777 wp_register_script( 'formidable_addons', $plugin_url . '/js/admin/addons.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
778 wp_enqueue_script( 'formidable_addons' );
779 }
780 }
781
782 /**
783 * Avoid loading dropzone CSS on the form list page. It isn't required there.
784 *
785 * @since 6.11
786 *
787 * @param string $page
788 * @return void
789 */
790 private static function maybe_enqueue_dropzone_css( $page ) {
791 if ( ! FrmAppHelper::pro_is_installed() ) {
792 return;
793 }
794
795 $should_avoid_loading_dropzone = 'formidable' === $page && ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
796 if ( ! $should_avoid_loading_dropzone ) {
797 wp_enqueue_style( 'formidable-dropzone' );
798 }
799 }
800
801 /**
802 * The floating links are not shown on every page.
803 * They are also not shown if white labeling is being used.
804 *
805 * @since 6.8.4
806 *
807 * @return bool
808 */
809 private static function should_show_floating_links() {
810 if ( ! FrmAppHelper::is_formidable_branding() ) {
811 return false;
812 }
813
814 return FrmAppHelper::is_formidable_admin() &&
815 ! FrmAppHelper::is_style_editor_page() &&
816 ! FrmAppHelper::is_admin_page( 'formidable-views-editor' ) &&
817 ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
818 }
819
820 /**
821 * @since 6.3.2
822 *
823 * @return void
824 */
825 public static function admin_enqueue_scripts() {
826 self::load_wp_admin_style();
827 self::maybe_force_formidable_block_on_gutenberg_page();
828
829 if ( FrmAppHelper::is_admin_page( 'formidable-settings' ) ) {
830 wp_enqueue_style( FrmDashboardController::PAGE_SLUG, FrmAppHelper::plugin_url() . '/css/admin/dashboard.css', array(), FrmAppHelper::plugin_version() );
831 }
832
833 FrmUsageController::load_scripts();
834 }
835
836 /**
837 * Enqueue required assets for the Legacy Views editor (Views v4.x).
838 *
839 * @since 6.1.2
840 *
841 * @return void
842 */
843 private static function enqueue_legacy_views_assets() {
844 wp_enqueue_style( 'formidable-grids' );
845 wp_enqueue_script( 'jquery-ui-draggable' );
846 self::maybe_deregister_popper2();
847 wp_enqueue_script( 'formidable_admin' );
848 wp_add_inline_style(
849 'formidable-admin',
850 '
851 .frm-white-body.post-type-frm_display .columns-2 {
852 display: block;
853 overflow: visible;
854 }
855
856 .frm-white-body.post-type-frm_display .columns-2 > div {
857 overflow-y: hidden;
858 }
859
860 .frm-white-body.post-type-frm_display #titlediv #title-prompt-text {
861 padding: 3px 0 0 10px;
862 }
863
864 .post-type-frm_display #field-search-input,
865 .post-type-frm_display #advanced-search-input {
866 flex: 1;
867 }
868 '
869 );
870 wp_enqueue_style( 'formidable-admin' );
871 FrmAppHelper::localize_script( 'admin' );
872 self::include_info_overlay();
873 }
874
875 /**
876 * Fix a Duplicator Pro conflict because it uses Popper 2. See issue #3459.
877 *
878 * @since 5.2.02.01
879 *
880 * @return void
881 */
882 private static function maybe_deregister_popper2() {
883 global $wp_scripts;
884
885 if ( ! array_key_exists( 'popper', $wp_scripts->registered ) ) {
886 return;
887 }
888
889 $popper = $wp_scripts->registered['popper'];
890 if ( version_compare( $popper->ver, '2.0', '>=' ) ) {
891 wp_deregister_script( 'popper' );
892 self::register_popper1();
893 }
894 }
895
896 /**
897 * Register Popper required for Bootstrap 4.
898 *
899 * @since 5.2.02.01
900 *
901 * @return void
902 */
903 private static function register_popper1() {
904 if ( ! self::should_register_popper() ) {
905 return;
906 }
907 wp_register_script( 'popper', FrmAppHelper::plugin_url() . '/js/popper.min.js', array( 'jquery' ), '1.16.0', true );
908 }
909
910 /**
911 * Only register popper on Formidable pages.
912 * This helps to avoid popper conflicts on other plugin pages, including the WP Bakery page editor.
913 *
914 * @since 6.11.1
915 *
916 * @return bool
917 */
918 private static function should_register_popper() {
919 global $pagenow;
920
921 $post_id = FrmAppHelper::simple_get( 'post', 'absint' );
922 if ( 'post.php' === $pagenow && $post_id && 'frm_display' === get_post_type( $post_id ) ) {
923 return true;
924 }
925
926 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
927 $is_views_post_type = 'frm_display' === $post_type;
928 if ( in_array( $pagenow, array( 'post-new.php', 'edit.php' ), true ) && $is_views_post_type ) {
929 return true;
930 }
931
932 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
933 if ( strpos( $page, 'formidable' ) === 0 ) {
934 return true;
935 }
936
937 return in_array( $pagenow, array( 'term.php', 'edit-tags.php' ), true ) && FrmAppHelper::simple_get( 'taxonomy' ) === 'frm_application';
938 }
939
940 /**
941 * Automatically insert a Formidable block when loading Gutenberg when $_GET['frmForm' is set.
942 *
943 * @since 5.2
944 *
945 * @return void
946 */
947 private static function maybe_force_formidable_block_on_gutenberg_page() {
948 global $pagenow;
949 if ( 'post.php' !== $pagenow ) {
950 return;
951 }
952
953 $form_id = FrmAppHelper::simple_get( 'frmForm', 'absint' );
954 if ( ! $form_id ) {
955 return;
956 }
957
958 self::add_js_to_inject_gutenberg_block( 'formidable/simple-form', 'formId', $form_id );
959 }
960
961 /**
962 * @since 5.3
963 *
964 * @param string $block_name
965 * @param string $object_key
966 * @param array|string $object_id
967 *
968 * @return void
969 */
970 public static function add_js_to_inject_gutenberg_block( $block_name, $object_key, $object_id ) {
971 require FrmAppHelper::plugin_path() . '/classes/views/shared/edit-page-js.php';
972 }
973
974 /**
975 * @return void
976 */
977 public static function load_lang() {
978 load_plugin_textdomain( 'formidable', false, FrmAppHelper::plugin_folder() . '/languages/' );
979 }
980
981 /**
982 * Check if the styles are updated when a form is loaded on the front-end
983 *
984 * @since 3.0.1
985 *
986 * @return void
987 */
988 public static function maybe_update_styles() {
989 if ( self::needs_update() ) {
990 self::network_upgrade_site();
991 }
992 }
993
994 /**
995 * @since 3.0
996 *
997 * @return void
998 */
999 public static function create_rest_routes() {
1000 $args = array(
1001 'methods' => 'GET',
1002 'callback' => 'FrmAppController::api_install',
1003 'permission_callback' => __CLASS__ . '::can_update_db',
1004 );
1005
1006 register_rest_route( 'frm-admin/v1', '/install', $args );
1007
1008 $args = array(
1009 'methods' => 'GET',
1010 'callback' => 'FrmAddonsController::install_addon_api',
1011 'permission_callback' => 'FrmAddonsController::can_install_addon_api',
1012 );
1013
1014 register_rest_route( 'frm-admin/v1', '/install-addon', $args );
1015 }
1016
1017 /**
1018 * Make sure the install is only being run when we tell it to.
1019 * We don't want to run manually by people calling the API.
1020 *
1021 * @since 4.06.02
1022 */
1023 public static function can_update_db() {
1024 return get_transient( 'frm_updating_api' );
1025 }
1026
1027 /**
1028 * Run silent upgrade on each site in the network during a network upgrade.
1029 * Update database settings for all sites in a network during network upgrade process.
1030 *
1031 * @since 2.0.1
1032 *
1033 * @param int $blog_id Blog ID.
1034 *
1035 * @return void
1036 */
1037 public static function network_upgrade_site( $blog_id = 0 ) {
1038 // Flag to check if install is happening as intended.
1039 set_transient( 'frm_updating_api', true, MINUTE_IN_SECONDS );
1040 $request = new WP_REST_Request( 'GET', '/frm-admin/v1/install' );
1041
1042 self::maybe_add_wp_site_health();
1043
1044 if ( $blog_id ) {
1045 switch_to_blog( $blog_id );
1046 $response = rest_do_request( $request );
1047 restore_current_blog();
1048 } else {
1049 $response = rest_do_request( $request );
1050 }
1051
1052 if ( $response->is_error() ) {
1053 // if the remove post fails, use javascript instead
1054 add_action( 'admin_notices', 'FrmAppController::install_js_fallback' );
1055 }
1056 }
1057
1058 /**
1059 * Make sure WP_Site_Health has been included because it is required when calling rest_do_request.
1060 * Check first that the file exists because WP_Site_Health was only introduced in WordPress 5.2.
1061 *
1062 * @return void
1063 */
1064 private static function maybe_add_wp_site_health() {
1065 if ( ! class_exists( 'WP_Site_Health' ) ) {
1066 $wp_site_health_path = ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
1067 if ( file_exists( $wp_site_health_path ) ) {
1068 require_once $wp_site_health_path;
1069 }
1070 }
1071 }
1072
1073 /**
1074 * @since 3.0
1075 *
1076 * @return true
1077 */
1078 public static function api_install() {
1079 delete_transient( 'frm_updating_api' );
1080 if ( self::needs_update() ) {
1081 $running = get_option( 'frm_install_running' );
1082 if ( false === $running || $running < strtotime( '-5 minutes' ) ) {
1083 update_option( 'frm_install_running', time(), 'no' );
1084 self::install();
1085 delete_option( 'frm_install_running' );
1086 }
1087 }
1088
1089 return true;
1090 }
1091
1092 /**
1093 * Silent database upgrade (no redirect).
1094 * Called via ajax request during network upgrade process.
1095 *
1096 * @since 2.0.1
1097 *
1098 * @return void
1099 */
1100 public static function ajax_install() {
1101 FrmAppHelper::permission_check( 'frm_change_settings' );
1102 check_ajax_referer( 'frm_ajax', 'nonce' );
1103 self::api_install();
1104 wp_die();
1105 }
1106
1107 /**
1108 * @return void
1109 */
1110 public static function install() {
1111 $frmdb = new FrmMigrate();
1112 $frmdb->upgrade();
1113 }
1114
1115 /**
1116 * @return void
1117 */
1118 public static function uninstall() {
1119 FrmAppHelper::permission_check( 'administrator' );
1120 check_ajax_referer( 'frm_ajax', 'nonce' );
1121
1122 $frmdb = new FrmMigrate();
1123 $frmdb->uninstall();
1124
1125 // Disable the plugin and redirect after uninstall so the tables don't get added right back.
1126 $plugins = array( FrmAppHelper::plugin_folder() . '/formidable.php', 'formidable-pro/formidable-pro.php' );
1127 deactivate_plugins( $plugins, false, false );
1128 echo esc_url_raw( admin_url( 'plugins.php?deactivate=true' ) );
1129
1130 wp_die();
1131 }
1132
1133 public static function drop_tables( $tables ) {
1134 global $wpdb;
1135 $tables[] = $wpdb->prefix . 'frm_fields';
1136 $tables[] = $wpdb->prefix . 'frm_forms';
1137 $tables[] = $wpdb->prefix . 'frm_items';
1138 $tables[] = $wpdb->prefix . 'frm_item_metas';
1139
1140 return $tables;
1141 }
1142
1143 /**
1144 * @return void
1145 */
1146 public static function deauthorize() {
1147 FrmAppHelper::permission_check( 'frm_change_settings' );
1148 check_ajax_referer( 'frm_ajax', 'nonce' );
1149
1150 delete_option( 'frmpro-credentials' );
1151 delete_option( 'frmpro-authorized' );
1152 delete_site_option( 'frmpro-credentials' );
1153 delete_site_option( 'frmpro-authorized' );
1154 wp_die();
1155 }
1156
1157 /**
1158 * This is triggered when Formidable is activated.
1159 *
1160 * @return void
1161 */
1162 public static function handle_activation() {
1163 self::maybe_activate_payment_cron();
1164 }
1165
1166 /**
1167 * The payment cron is unscheduled when Formidable is deactivated.
1168 * We need to add it back again on activation if Stripe is configured.
1169 *
1170 * @since 6.5
1171 *
1172 * @return void
1173 */
1174 private static function maybe_activate_payment_cron() {
1175 if ( ! FrmStrpLiteConnectHelper::stripe_connect_is_setup() ) {
1176 return;
1177 }
1178
1179 FrmTransLiteAppController::maybe_schedule_cron();
1180 }
1181
1182 public static function set_footer_text( $text ) {
1183 if ( FrmAppHelper::is_formidable_admin() ) {
1184 $text = '';
1185 }
1186
1187 return $text;
1188 }
1189
1190 /**
1191 * Add admin footer links.
1192 *
1193 * @since 6.4.1
1194 *
1195 * @return void
1196 */
1197 public static function add_admin_footer_links() {
1198 if ( self::should_show_footer_links() ) {
1199 include FrmAppHelper::plugin_path() . '/classes/views/shared/admin-footer-links.php';
1200 }
1201 }
1202
1203 /**
1204 * Check if the footer links should be shown.
1205 *
1206 * @since 6.7
1207 *
1208 * @return bool
1209 */
1210 private static function should_show_footer_links() {
1211 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
1212 $is_formidable_page = FrmAppHelper::is_formidable_admin() || 'frm_logs' === $post_type;
1213 $show_footer_links = $is_formidable_page;
1214 if ( FrmAppHelper::is_full_screen() || ! FrmAppHelper::is_formidable_branding() ) {
1215 $show_footer_links = false;
1216 }
1217
1218 /**
1219 * Filter whether to show the Formidable footer links.
1220 *
1221 * @since 6.7
1222 *
1223 * @param bool $show_footer_links
1224 * @return bool
1225 */
1226 return apply_filters( 'frm_show_footer_links', $show_footer_links );
1227 }
1228
1229 /**
1230 * Show an error modal and terminate the script execution.
1231 *
1232 * @since 6.7
1233 *
1234 * @param array $error_args Arguments that control the behavior of the error modal.
1235 *
1236 * @return void
1237 */
1238 public static function show_error_modal( $error_args ) {
1239 add_filter( 'frm_show_footer_links', '__return_false' );
1240
1241 $defaults = array(
1242 'title' => '',
1243 'body' => '',
1244 'cancel_url' => '',
1245 'cancel_classes' => '',
1246 'continue_url' => '',
1247 'continue_classes' => '',
1248 'icon' => 'frm_lock_simple',
1249 );
1250
1251 $error_args = wp_parse_args( $error_args, $defaults );
1252 if ( ! isset( $error_args['cancel_text'] ) && ! empty( $error_args['cancel_url'] ) ) {
1253 $error_args['cancel_text'] = __( 'Cancel', 'formidable' );
1254 }
1255
1256 if ( ! isset( $error_args['continue_text'] ) && ! empty( $error_args['continue_url'] ) ) {
1257 $error_args['continue_text'] = __( 'Continue', 'formidable' );
1258 }
1259
1260 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/error-modal.php';
1261 }
1262
1263 /**
1264 * Handles Floating Links' scripts and styles enqueueing.
1265 *
1266 * @since 6.4
1267 *
1268 * @param string $plugin_url URL of the plugin.
1269 * @param string $version Current version of the plugin.
1270 * @return void
1271 */
1272 private static function enqueue_floating_links( $plugin_url, $version ) {
1273 if ( ! $plugin_url || ! $version ) {
1274 // If any required parameters are missing, exit early.
1275 return;
1276 }
1277
1278 // Enqueue the Floating Links styles.
1279 wp_enqueue_style( 's11-floating-links', $plugin_url . '/css/packages/s11-floating-links.css', array(), $version );
1280
1281 // Enqueue the Floating Links script.
1282 wp_enqueue_script( 's11-floating-links', $plugin_url . '/js/packages/floating-links/s11-floating-links.js', array( 'formidable_admin' ), $version, true );
1283
1284 // Enqueue the config script.
1285 wp_enqueue_script( 's11-floating-links-config', $plugin_url . '/js/packages/floating-links/config.js', array( 'wp-i18n' ), $version, true );
1286
1287 if ( function_exists( 'wp_set_script_translations' ) ) {
1288 wp_set_script_translations( 's11-floating-links-config', 's11-' );
1289 }
1290
1291 $floating_links_data = array(
1292 'proIsInstalled' => FrmAppHelper::pro_is_installed(),
1293 );
1294 wp_localize_script( 's11-floating-links-config', 's11FloatingLinksData', $floating_links_data );
1295
1296 /**
1297 * Prompt Pro to load additional floating links scripts.
1298 * This is used to include images in the Inbox SlideIn when Pro is active.
1299 *
1300 * @since 6.8.4
1301 */
1302 do_action( 'frm_enqueue_floating_links' );
1303 }
1304
1305 /**
1306 * Check if we are in our admin pages.
1307 *
1308 * @return bool
1309 */
1310 private static function in_our_pages() {
1311 global $current_screen, $pagenow;
1312 if ( FrmAppHelper::is_formidable_admin() ) {
1313 return true;
1314 }
1315
1316 if ( ! empty( $current_screen->post_type ) && 'frm_logs' === $current_screen->post_type ) {
1317 return true;
1318 }
1319
1320 if ( in_array( $pagenow, array( 'term.php', 'edit-tags.php' ), true ) && 'frm_application' === FrmAppHelper::simple_get( 'taxonomy' ) ) {
1321 return true;
1322 }
1323
1324 return false;
1325 }
1326
1327 /**
1328 * Hide all third-parties admin notices only in our admin pages.
1329 *
1330 * @return void
1331 */
1332 public static function filter_admin_notices() {
1333 if ( ! self::in_our_pages() ) {
1334 return;
1335 }
1336
1337 $actions = array(
1338 'admin_notices',
1339 'network_admin_notices',
1340 'user_admin_notices',
1341 'all_admin_notices',
1342 );
1343
1344 global $wp_filter;
1345
1346 foreach ( $actions as $action ) {
1347 if ( empty( $wp_filter[ $action ]->callbacks ) ) {
1348 continue;
1349 }
1350 foreach ( $wp_filter[ $action ]->callbacks as $priority => $callbacks ) {
1351 foreach ( $callbacks as $callback_name => $callback ) {
1352 if ( self::is_our_callback_string( $callback_name ) || self::is_our_callback_array( $callback ) ) {
1353 continue;
1354 }
1355 unset( $wp_filter[ $action ]->callbacks[ $priority ][ $callback_name ] );
1356 }
1357 }
1358 }
1359 }
1360
1361 /**
1362 * Validate that the callback name is ours not from third-party.
1363 *
1364 * @param string $callback_name WordPress callback name.
1365 *
1366 * @return bool
1367 */
1368 private static function is_our_callback_string( $callback_name ) {
1369 return 0 === stripos( $callback_name, 'frm' );
1370 }
1371
1372 /**
1373 * Validate that the callback array is ours not from third-party.
1374 *
1375 * @param array $callback WordPress callback array.
1376 *
1377 * @return bool
1378 */
1379 private static function is_our_callback_array( $callback ) {
1380 return ! empty( $callback['function'] ) &&
1381 is_array( $callback['function'] ) &&
1382 ! empty( $callback['function'][0] ) &&
1383 self::is_our_callback_string( is_object( $callback['function'][0] ) ? get_class( $callback['function'][0] ) : $callback['function'][0] );
1384 }
1385 }
1386