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

1,306 lines 35.9 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 add_menu_page( 'Formidable', $menu_name, 'frm_view_forms', 'formidable', 'FrmFormsController::route', self::menu_icon(), self::get_menu_position() );
19 }
20
21 /**
22 * @return int
23 */
24 private static function get_menu_position() {
25 return (int) apply_filters( 'frm_menu_position', 29 );
26 }
27
28 /**
29 * @since 3.05
30 */
31 private static function menu_icon() {
32 $icon = FrmAppHelper::svg_logo(
33 array(
34 'fill' => '#a0a5aa',
35 'orange' => '#a0a5aa',
36 )
37 );
38 $icon = 'data:image/svg+xml;base64,' . base64_encode( $icon );
39
40 return apply_filters( 'frm_icon', $icon );
41 }
42
43 /**
44 * @since 3.0
45 */
46 public static function add_admin_class( $classes ) {
47 if ( self::is_white_page() ) {
48 $classes .= ' frm-white-body ';
49 $classes .= self::get_os();
50
51 $page = str_replace( 'formidable-', '', FrmAppHelper::simple_get( 'page', 'sanitize_title' ) );
52 if ( empty( $page ) || $page === 'formidable' ) {
53 $action = FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
54 if ( in_array( $action, array( 'settings', 'edit', 'list' ) ) ) {
55 $page .= $action;
56 } else {
57 $page = $action;
58 }
59 }
60 if ( ! empty( $page ) ) {
61 $classes .= ' frm-admin-page-' . $page;
62 }
63 }
64
65 if ( self::is_grey_page() ) {
66 $classes .= ' frm-grey-body ';
67 }
68
69 if ( FrmAppHelper::is_full_screen() ) {
70 $full_screen_on = self::get_full_screen_setting();
71 $add_class = '';
72 if ( $full_screen_on ) {
73 $add_class = ' frm-full-screen is-fullscreen-mode';
74
75 // Load the CSS for .is-fullscreen-mode.
76 wp_enqueue_style( 'wp-edit-post' );
77 }
78 $classes .= apply_filters( 'frm_admin_full_screen_class', $add_class );
79 }
80
81 if ( ! FrmAppHelper::pro_is_installed() ) {
82 $classes .= ' frm-lite ';
83 }
84
85 if ( get_user_setting( 'unfold' ) && 'f' !== get_user_setting( 'mfold' ) ) {
86 $classes .= ' frm-unfold ';
87 }
88
89 return $classes;
90 }
91
92 /**
93 * Get the full screen mode setting from the block editor.
94 *
95 * @since 6.1
96 *
97 * @return bool
98 */
99 private static function get_full_screen_setting() {
100 global $wpdb;
101 $meta_key = $wpdb->get_blog_prefix() . 'persisted_preferences';
102
103 $prefs = get_user_meta( get_current_user_id(), $meta_key, true );
104 if ( $prefs && isset( $prefs['core/edit-post']['fullscreenMode'] ) ) {
105 return $prefs['core/edit-post']['fullscreenMode'];
106 }
107
108 return true;
109 }
110
111 /**
112 * @since 4.0
113 *
114 * @return string
115 */
116 private static function get_os() {
117 $agent = strtolower( FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' ) );
118 $os = '';
119 if ( strpos( $agent, 'mac' ) !== false ) {
120 $os = ' osx';
121 } elseif ( strpos( $agent, 'linux' ) !== false ) {
122 $os = ' linux';
123 } elseif ( strpos( $agent, 'windows' ) !== false ) {
124 $os = ' windows';
125 }
126 return $os;
127 }
128
129 /**
130 * @since 3.0
131 */
132 private static function is_white_page() {
133 $white_pages = array(
134 'formidable',
135 'formidable-entries',
136 'formidable-views',
137 'formidable-views-editor',
138 'formidable-pro-upgrade',
139 'formidable-addons',
140 'formidable-import',
141 'formidable-settings',
142 'formidable-styles',
143 'formidable-styles2',
144 'formidable-inbox',
145 FrmFormTemplatesController::PAGE_SLUG,
146 );
147
148 if ( ! class_exists( 'FrmTransHooksController', false ) && ! FrmTransLiteAppHelper::should_fallback_to_paypal() ) {
149 // Only consider the payments page as a "white page" when the Payments submodule is off.
150 // Otherwise this causes a lot of styling issues when the Stripe add-on (or Authorize.Net) is active.
151
152 // Add an extra check to avoid white page styling on the PayPal "edit" action.
153 // We fallback to the PayPal add on for the "edit" action since Stripe Lite does not have an edit view.
154 if ( ! in_array( FrmAppHelper::simple_get( 'action' ), array( 'edit', 'new' ), true ) || ! is_callable( 'FrmPaymentsController::route' ) ) {
155 $white_pages[] = 'formidable-payments';
156 }
157 }
158
159 $is_white_page = self::is_page_in_list( $white_pages ) || self::is_grey_page() || FrmAppHelper::is_view_builder_page();
160
161 /**
162 * Allow another add on to style a page as a Formidable "white page", which adds a white background color.
163 *
164 * @since 5.3
165 *
166 * @param bool $is_white_page
167 */
168 $is_white_page = apply_filters( 'frm_is_white_page', $is_white_page );
169
170 return $is_white_page;
171 }
172
173 /**
174 * Add a grey bg instead of white.
175 *
176 * @since 6.8
177 *
178 * @return bool
179 */
180 private static function is_grey_page() {
181 $grey_pages = array(
182 'formidable-applications',
183 'formidable-dashboard',
184 );
185
186 $is_grey_page = self::is_page_in_list( $grey_pages );
187
188 /**
189 * Filter to change FF wrapper background to grey.
190 *
191 * @since 6.8
192 *
193 * @param bool $is_grey_page
194 * @return bool
195 */
196 return apply_filters( 'frm_is_grey_page', $is_grey_page );
197 }
198
199 /**
200 * @since 6.8
201 *
202 * @param array $pages A list of page names to check.
203 * @return bool
204 */
205 private static function is_page_in_list( $pages ) {
206 $get_page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
207 return in_array( $get_page, $pages, true );
208 }
209
210 /**
211 * @return void
212 */
213 public static function load_wp_admin_style() {
214 FrmAppHelper::load_font_style();
215 }
216
217 /**
218 * @param int|object $form
219 * @param bool $show_nav
220 * @param string $title
221 *
222 * @psalm-param 'hide'|'show' $title
223 *
224 * @return void
225 */
226 public static function get_form_nav( $form, $show_nav = false, $title = 'show' ) {
227 $show_nav = FrmAppHelper::get_param( 'show_nav', $show_nav, 'get', 'absint' );
228 if ( empty( $show_nav ) || ! $form ) {
229 return;
230 }
231
232 FrmForm::maybe_get_form( $form );
233 if ( ! is_object( $form ) ) {
234 return;
235 }
236
237 $id = $form->id;
238 $current_page = self::get_current_page();
239 $nav_items = self::get_form_nav_items( $form );
240
241 include( FrmAppHelper::plugin_path() . '/classes/views/shared/form-nav.php' );
242 }
243
244 /**
245 * @return string
246 */
247 private static function get_current_page() {
248 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
249 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title', 'None' );
250 $current_page = isset( $_GET['page'] ) ? $page : $post_type;
251
252 if ( FrmAppHelper::is_view_builder_page() ) {
253 $current_page = 'frm_display';
254 }
255
256 return $current_page;
257 }
258
259 /**
260 * @param object $form
261 * @return array
262 */
263 private static function get_form_nav_items( $form ) {
264 $id = $form->parent_form_id ? $form->parent_form_id : $form->id;
265
266 $nav_items = array(
267 array(
268 'link' => FrmForm::get_edit_link( $id ),
269 'label' => __( 'Build', 'formidable' ),
270 'current' => array( 'edit', 'new', 'duplicate' ),
271 'page' => 'formidable',
272 'permission' => 'frm_edit_forms',
273 ),
274 array(
275 'link' => FrmStylesHelper::get_list_url( $id ),
276 'label' => __( 'Style', 'formidable' ),
277 'current' => array(),
278 'page' => 'formidable-styles',
279 'permission' => 'frm_edit_forms',
280 ),
281 array(
282 'link' => admin_url( 'admin.php?page=formidable&frm_action=settings&id=' . absint( $id ) ),
283 'label' => __( 'Settings', 'formidable' ),
284 'current' => array( 'settings' ),
285 'page' => 'formidable',
286 'permission' => 'frm_edit_forms',
287 ),
288 array(
289 'link' => admin_url( 'admin.php?page=formidable-entries&frm_action=list&form=' . absint( $id ) ),
290 'label' => __( 'Entries', 'formidable' ),
291 'current' => array(),
292 'page' => 'formidable-entries',
293 'permission' => 'frm_view_entries',
294 ),
295 );
296
297 $views_installed = is_callable( 'FrmProAppHelper::views_is_installed' ) ? FrmProAppHelper::views_is_installed() : FrmAppHelper::pro_is_installed();
298
299 if ( ! $views_installed ) {
300 $nav_items[] = array(
301 'link' => admin_url( 'admin.php?page=formidable-views&form=' . absint( $id ) ),
302 'label' => __( 'Views', 'formidable' ),
303 'current' => array(),
304 'page' => 'formidable-views',
305 'permission' => 'frm_view_entries',
306 'atts' => array(
307 'class' => 'frm_noallow',
308 ),
309 );
310 }
311
312 // Let people know reports and views exist.
313 if ( ! FrmAppHelper::pro_is_installed() ) {
314 $nav_items[] = array(
315 'link' => admin_url( 'admin.php?page=formidable&frm_action=lite-reports&form=' . absint( $id ) ),
316 'label' => __( 'Reports', 'formidable' ),
317 'current' => array( 'reports' ),
318 'page' => 'formidable',
319 'permission' => 'frm_view_entries',
320 'atts' => array(
321 'class' => 'frm_noallow',
322 ),
323 );
324 }
325
326 $nav_args = array(
327 'form_id' => $id,
328 'form' => $form,
329 );
330
331 return (array) apply_filters( 'frm_form_nav_list', $nav_items, $nav_args );
332 }
333
334 // Adds a settings link to the plugins page
335 /**
336 * @return array
337 */
338 public static function settings_link( $links ) {
339 $settings = array();
340
341 if ( ! FrmAppHelper::pro_is_installed() ) {
342 $label = FrmAddonsController::is_license_expired() ? __( 'Renew', 'formidable' ) : __( 'Upgrade to Pro', 'formidable' );
343 $settings[] = '<a href="' . esc_url( FrmAppHelper::admin_upgrade_link( 'plugin-row' ) ) . '" target="_blank" rel="noopener"><b style="color:#1da867;font-weight:700;">' . esc_html( $label ) . '</b></a>';
344 }
345
346 $settings[] = '<a href="' . esc_url( admin_url( 'admin.php?page=formidable' ) ) . '">' . __( 'Build a Form', 'formidable' ) . '</a>';
347
348 return array_merge( $settings, $links );
349 }
350
351 /**
352 * @return void
353 */
354 public static function pro_get_started_headline() {
355 self::review_request();
356 FrmAppHelper::min_pro_version_notice( '4.0' );
357 }
358
359 /**
360 * Add admin notices as needed for reviews
361 *
362 * @since 3.04.03
363 *
364 * @return void
365 */
366 private static function review_request() {
367 $reviews = new FrmReviews();
368 $reviews->review_request();
369 }
370
371 /**
372 * Save the request to hide the review
373 *
374 * @since 3.04.03
375 *
376 * @return void
377 */
378 public static function dismiss_review() {
379 FrmAppHelper::permission_check( 'frm_change_settings' );
380 check_ajax_referer( 'frm_ajax', 'nonce' );
381
382 $reviews = new FrmReviews();
383 $reviews->dismiss_review();
384 }
385
386 /**
387 * @since 3.04.02
388 *
389 * @return void
390 */
391 public static function include_upgrade_overlay() {
392 self::enqueue_dialog_assets();
393 add_action( 'admin_footer', 'FrmAppController::upgrade_overlay_html' );
394 }
395
396 /**
397 * Enqueue scripts and styles required for modals.
398 *
399 * @since 5.3
400 *
401 * @return void
402 */
403 public static function enqueue_dialog_assets() {
404 wp_enqueue_script( 'jquery-ui-dialog' );
405 wp_enqueue_style( 'jquery-ui-dialog' );
406 }
407
408 /**
409 * @since 3.06.03
410 *
411 * @return void
412 */
413 public static function upgrade_overlay_html() {
414 $is_pro = FrmAppHelper::pro_is_installed();
415 $upgrade_link = array(
416 'medium' => 'builder',
417 'content' => 'upgrade',
418 );
419 $default_link = FrmAppHelper::admin_upgrade_link( $upgrade_link );
420 $plugin_path = FrmAppHelper::plugin_path();
421 $shared_path = $plugin_path . '/classes/views/shared/';
422
423 include $shared_path . 'upgrade_overlay.php';
424 include $shared_path . 'confirm-overlay.php';
425 }
426
427 /**
428 * Create a basic form with an email field.
429 *
430 * @param string $form_key
431 * @param string $title
432 * @param string $description
433 * @return void
434 */
435 public static function api_email_form( $form_key, $title, $description ) {
436 $user = wp_get_current_user();
437 $args = array(
438 'api_url' => 'https://sandbox.formidableforms.com/api/wp-json/frm/v2/forms/' . $form_key . '?return=html&exclude_script=jquery&exclude_style=formidable-css',
439 'title' => $title,
440 'description' => $description,
441 );
442 require FrmAppHelper::plugin_path() . '/classes/views/form-templates/modals/leave-email-modal.php';
443 }
444
445 /**
446 * @return void
447 */
448 public static function include_info_overlay() {
449 self::enqueue_dialog_assets();
450 add_action( 'admin_footer', 'FrmAppController::info_overlay_html' );
451 }
452
453 /**
454 * @return void
455 */
456 public static function info_overlay_html() {
457 include FrmAppHelper::plugin_path() . '/classes/views/shared/info-overlay.php';
458 }
459
460 /**
461 * @since 3.04.02
462 *
463 * @return void
464 */
465 public static function remove_upsells() {
466 remove_action( 'frm_before_settings', 'FrmSettingsController::license_box' );
467 remove_action( 'frm_after_settings', 'FrmSettingsController::settings_cta' );
468 remove_action( 'frm_add_form_style_tab_options', 'FrmFormsController::add_form_style_tab_options' );
469 remove_action( 'frm_after_field_options', 'FrmFormsController::logic_tip' );
470 }
471
472 /**
473 * If there are CURL problems on this server, wp_remote_post won't work for installing
474 * Use a javascript fallback instead.
475 *
476 * @since 2.0.3
477 *
478 * @return void
479 */
480 public static function install_js_fallback() {
481 FrmAppHelper::load_admin_wide_js();
482 ?>
483 <div id="frm_install_message"></div>
484 <script>jQuery(document).ready( frm_install_now );</script>
485 <?php
486 }
487
488 /**
489 * Check if the database is outdated
490 *
491 * @since 2.0.1
492 * @return boolean
493 */
494 public static function needs_update() {
495 $needs_upgrade = self::compare_for_update(
496 array(
497 'option' => 'frm_db_version',
498 'new_db_version' => FrmAppHelper::$db_version,
499 'new_plugin_version' => FrmAppHelper::plugin_version(),
500 )
501 );
502
503 if ( ! $needs_upgrade ) {
504 $needs_upgrade = apply_filters( 'frm_db_needs_upgrade', $needs_upgrade );
505 }
506
507 return $needs_upgrade;
508 }
509
510 /**
511 * Check both version number and DB number for changes
512 *
513 * @since 3.0.04
514 *
515 * @param array $atts
516 * @return bool
517 */
518 public static function compare_for_update( $atts ) {
519 $db_version = get_option( $atts['option'] );
520
521 if ( strpos( $db_version, '-' ) === false ) {
522 $needs_upgrade = true;
523 } else {
524 $last_upgrade = explode( '-', $db_version );
525 $needs_db_upgrade = (int) $last_upgrade[1] < (int) $atts['new_db_version'];
526 $new_version = version_compare( $last_upgrade[0], $atts['new_plugin_version'], '<' );
527 $needs_upgrade = $needs_db_upgrade || $new_version;
528 }
529
530 return $needs_upgrade;
531 }
532
533 /**
534 * Check for database update and trigger js loading
535 *
536 * @since 2.0.1
537 *
538 * @return void
539 */
540 public static function admin_init() {
541 if ( FrmAppHelper::get_param( 'delete_all' ) && FrmAppHelper::is_admin_page( 'formidable' ) && 'trash' === FrmAppHelper::get_param( 'form_type' ) ) {
542 FrmFormsController::delete_all();
543 }
544
545 if ( FrmAppHelper::is_admin_page( 'formidable' ) && 'duplicate' === FrmAppHelper::get_param( 'frm_action' ) ) {
546 FrmFormsController::duplicate();
547 }
548
549 if ( FrmAppHelper::is_style_editor_page() && 'save' === FrmAppHelper::get_param( 'frm_action' ) ) {
550 // Hook in earlier than FrmStylesController::route so we can redirect before the headers have been sent.
551 FrmStylesController::save_style();
552 }
553
554 // Register personal data hooks.
555 new FrmPersonalData();
556
557 if ( ! FrmAppHelper::doing_ajax() && self::needs_update() ) {
558 self::network_upgrade_site();
559 }
560
561 if ( ! FrmAppHelper::doing_ajax() ) {
562 // don't continue during ajax calls
563 self::admin_js();
564 }
565
566 self::trigger_page_load_hooks();
567
568 if ( FrmAppHelper::is_admin_page( 'formidable' ) ) {
569 // Redirect to the "Form Templates" page if the 'frm_action' parameter matches specific actions.
570 // This provides backward compatibility for old addons that use legacy modal templates.
571 $action = FrmAppHelper::get_param( 'frm_action' );
572 $trigger_name_modal = FrmAppHelper::get_param( 'triggerNewFormModal' );
573 if ( $trigger_name_modal || in_array( $action, array( 'add_new', 'list_templates' ), true ) ) {
574 $application_id = FrmAppHelper::simple_get( 'applicationId', 'absint' );
575 $url_param = $application_id ? '&applicationId=' . $application_id : '';
576
577 wp_safe_redirect( admin_url( 'admin.php?page=' . FrmFormTemplatesController::PAGE_SLUG . $url_param ) );
578 exit;
579 }
580
581 FrmInbox::maybe_disable_screen_options();
582 }
583
584 self::maybe_add_ip_warning();
585 }
586
587 /**
588 * Get the current page and check for a possible function to trigger.
589 * If a class name matches the page name, and the class has a load_page() method, trigger it.
590 *
591 * @since 6.8
592 *
593 * @return void
594 */
595 private static function trigger_page_load_hooks() {
596 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
597 if ( strpos( $page, 'formidable-' ) !== 0 ) {
598 // Only trigger hooks on Formidable pages.
599 return;
600 }
601
602 $page = str_replace( array( 'formidable-', '-' ), array( '', ' ' ), $page );
603 $page = str_replace( ' ', '', ucwords( $page ) );
604 $class = 'Frm' . $page . 'Controller';
605 if ( class_exists( $class ) && method_exists( $class, 'load_page' ) ) {
606 call_user_func( array( $class, 'load_page' ) );
607 }
608 }
609
610 /**
611 * Show a warning for the IP address setting if it hasn't been set.
612 *
613 * @since 6.1
614 *
615 * @return void
616 */
617 private static function maybe_add_ip_warning() {
618 $settings = FrmAppHelper::get_settings();
619 if ( false !== $settings->custom_header_ip ) {
620 // The setting has been changed from the false default (to either 1 or 0), so stop showing the message.
621 return;
622 }
623
624 if ( ! self::is_behind_proxy() ) {
625 // This message is only applicable when using a reverse proxy.
626 return;
627 }
628
629 if ( FrmAppHelper::get_post_param( 'frm_action', '', 'sanitize_text_field' ) ) {
630 // Avoid the message on a POST action. We don't want to show the message if we're saving global settings.
631 return;
632 }
633
634 $global_settings_link = admin_url( 'admin.php?page=formidable-settings' ) . '#frm_custom_header_ip';
635 $message = sprintf(
636 // Translators: 1: Global Settings Link
637 __( 'IP addresses in form submissions may no longer be accurate! If you are experiencing issues, we recommend going to %1$s and enabling the "Use custom headers when retrieving IPs with form submissions." setting.', 'formidable' ),
638 '<a href="' . esc_url( $global_settings_link ) . '">Global Settings</a>'
639 );
640 $option_name = 'frm_dismiss_ip_address_notice';
641 FrmAppHelper::add_dismissable_warning_message( $message, $option_name );
642 }
643
644 /**
645 * Check if any reverse proxy headers are set.
646 *
647 * @since 6.1
648 *
649 * @return bool
650 */
651 private static function is_behind_proxy() {
652 $custom_headers = FrmAppHelper::get_custom_header_keys_for_ip();
653 foreach ( $custom_headers as $header ) {
654 if ( 'REMOTE_ADDR' === $header ) {
655 // We want to check every key but REMOTE_ADDR. REMOTE_ATTR is not unique to reverse proxy servers.
656 continue;
657 }
658
659 $ip = trim( FrmAppHelper::get_server_value( $header ) );
660 // Return true for anything that isn't empty but ignoring values like ::1.
661 if ( $ip && 0 !== strpos( $ip, '::' ) ) {
662 return true;
663 }
664 }
665
666 return false;
667 }
668
669 /**
670 * @return void
671 */
672 public static function admin_js() {
673 $plugin_url = FrmAppHelper::plugin_url();
674 $version = FrmAppHelper::plugin_version();
675
676 FrmAppHelper::load_admin_wide_js();
677
678 // Register component assets early to ensure they can be enqueued later in controllers.
679 wp_register_style( 'formidable-animations', $plugin_url . '/css/admin/animations.css', array(), $version );
680
681 if ( class_exists( 'FrmOverlayController' ) ) {
682 // This should always exist.
683 // But it may not have loaded properly when updating the plugin.
684 FrmOverlayController::register_assets();
685 }
686
687 wp_register_style( 'formidable_admin_global', $plugin_url . '/css/admin/frm_admin_global.css', array(), $version );
688 wp_enqueue_style( 'formidable_admin_global' );
689
690 wp_register_style( 'formidable-admin', $plugin_url . '/css/frm_admin.css', array(), $version );
691 wp_register_style( 'formidable-grids', $plugin_url . '/css/frm_grids.css', array(), $version );
692
693 wp_register_script( 'formidable_dom', $plugin_url . '/js/admin/dom.js', array( 'jquery', 'jquery-ui-dialog', 'wp-i18n' ), $version, true );
694 wp_register_script( 'formidable_embed', $plugin_url . '/js/admin/embed.js', array( 'formidable_dom', 'jquery-ui-autocomplete' ), $version, true );
695 self::register_popper1();
696 wp_register_script( 'bootstrap_tooltip', $plugin_url . '/js/bootstrap.min.js', array( 'jquery', 'popper' ), '4.6.1', true );
697 wp_register_script( 'formidable_settings', $plugin_url . '/js/admin/settings.js', array(), $version, true );
698
699 if ( self::should_show_floating_links() ) {
700 self::enqueue_floating_links( $plugin_url, $version );
701 }
702
703 $dependencies = array(
704 'formidable_admin_global',
705 'jquery',
706 'jquery-ui-core',
707 'jquery-ui-draggable',
708 'jquery-ui-sortable',
709 'bootstrap_tooltip',
710 'bootstrap-multiselect',
711 'wp-i18n',
712 // Required in WP versions older than 5.7
713 'wp-hooks',
714 'formidable_dom',
715 'formidable_embed',
716 );
717
718 if ( FrmAppHelper::is_style_editor_page( 'edit' ) ) {
719 // We only need to load the color picker when editing styles.
720 $dependencies[] = 'wp-color-picker';
721 }
722
723 wp_register_script( 'formidable_admin', $plugin_url . '/js/formidable_admin.js', $dependencies, $version, true );
724
725 if ( FrmAppHelper::on_form_listing_page() ) {
726 // For the existing page dropdown in the Form embed modal.
727 wp_enqueue_script( 'jquery-ui-autocomplete' );
728 }
729
730 wp_register_script( 'bootstrap-multiselect', $plugin_url . '/js/bootstrap-multiselect.js', array( 'jquery', 'bootstrap_tooltip', 'popper' ), '1.1.1', true );
731
732 if ( ! class_exists( 'FrmTransHooksController', false ) ) {
733 /**
734 * Gateway fields are included for add-on compatibility but we do not want it to be visible.
735 * They do however need to be visible when the payments submodule is active.
736 */
737 wp_add_inline_style(
738 'formidable-admin',
739 '#frm_builder_page li[data-ftype="gateway"] { display: none; }'
740 );
741 }
742
743 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
744 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
745
746 global $pagenow;
747 if ( strpos( $page, 'formidable' ) === 0 || ( $pagenow === 'edit.php' && $post_type === 'frm_display' ) ) {
748
749 wp_enqueue_script( 'admin-widgets' );
750 wp_enqueue_style( 'widgets' );
751 self::maybe_deregister_popper2();
752 wp_enqueue_script( 'formidable_admin' );
753 wp_enqueue_script( 'formidable_embed' );
754 FrmAppHelper::localize_script( 'admin' );
755
756 wp_enqueue_style( 'formidable-animations' );
757 wp_enqueue_style( 'formidable-admin' );
758 if ( 'formidable-styles' !== $page && 'formidable-styles2' !== $page ) {
759 wp_enqueue_style( 'formidable-grids' );
760 wp_enqueue_style( 'formidable-dropzone' );
761 } else {
762 wp_enqueue_style( 'formidable-grids' );
763 }
764
765 if ( 'formidable-entries' === $page ) {
766 // Load front end js for entries.
767 wp_enqueue_script( 'formidable' );
768
769 // Registers and enqueues the entries page scripts.
770 wp_register_script( 'formidable_entries', $plugin_url . '/js/admin/entries.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
771 wp_enqueue_script( 'formidable_entries' );
772 }
773
774 do_action( 'frm_enqueue_builder_scripts' );
775 self::include_upgrade_overlay();
776 self::include_info_overlay();
777 } elseif ( FrmAppHelper::is_view_builder_page() ) {
778 if ( isset( $_REQUEST['post_type'] ) ) {
779 $post_type = sanitize_title( wp_unslash( $_REQUEST['post_type'] ) );
780 } elseif ( isset( $_REQUEST['post'] ) && absint( $_REQUEST['post'] ) ) {
781 $post = get_post( absint( wp_unslash( $_REQUEST['post'] ) ) );
782 if ( ! $post ) {
783 return;
784 }
785 $post_type = $post->post_type;
786 } else {
787 return;
788 }
789
790 if ( $post_type === 'frm_display' ) {
791 self::enqueue_legacy_views_assets();
792 }
793 }//end if
794
795 if ( 'formidable-addons' === $page ) {
796 wp_register_script( 'formidable_addons', $plugin_url . '/js/admin/addons.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
797 wp_enqueue_script( 'formidable_addons' );
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
830 /**
831 * Enqueue required assets for the Legacy Views editor (Views v4.x).
832 *
833 * @since 6.1.2
834 *
835 * @return void
836 */
837 private static function enqueue_legacy_views_assets() {
838 wp_enqueue_style( 'formidable-grids' );
839 wp_enqueue_script( 'jquery-ui-draggable' );
840 self::maybe_deregister_popper2();
841 wp_enqueue_script( 'formidable_admin' );
842 wp_add_inline_style(
843 'formidable-admin',
844 '
845 .frm-white-body.post-type-frm_display .columns-2 {
846 display: block;
847 overflow: visible;
848 }
849
850 .frm-white-body.post-type-frm_display .columns-2 > div {
851 overflow-y: hidden;
852 }
853
854 .frm-white-body.post-type-frm_display #titlediv #title-prompt-text {
855 padding: 3px 0 0 10px;
856 }
857
858 .post-type-frm_display #field-search-input,
859 .post-type-frm_display #advanced-search-input {
860 flex: 1;
861 }
862 '
863 );
864 wp_enqueue_style( 'formidable-admin' );
865 FrmAppHelper::localize_script( 'admin' );
866 self::include_info_overlay();
867 }
868
869 /**
870 * Fix a Duplicator Pro conflict because it uses Popper 2. See issue #3459.
871 *
872 * @since 5.2.02.01
873 *
874 * @return void
875 */
876 private static function maybe_deregister_popper2() {
877 global $wp_scripts;
878
879 if ( ! array_key_exists( 'popper', $wp_scripts->registered ) ) {
880 return;
881 }
882
883 $popper = $wp_scripts->registered['popper'];
884 if ( version_compare( $popper->ver, '2.0', '>=' ) ) {
885 wp_deregister_script( 'popper' );
886 self::register_popper1();
887 }
888 }
889
890 /**
891 * Register Popper required for Bootstrap 4.
892 *
893 * @since 5.2.02.01
894 *
895 * @return void
896 */
897 private static function register_popper1() {
898 wp_register_script( 'popper', FrmAppHelper::plugin_url() . '/js/popper.min.js', array( 'jquery' ), '1.16.0', true );
899 }
900
901 /**
902 * Automatically insert a Formidable block when loading Gutenberg when $_GET['frmForm' is set.
903 *
904 * @since 5.2
905 *
906 * @return void
907 */
908 private static function maybe_force_formidable_block_on_gutenberg_page() {
909 global $pagenow;
910 if ( 'post.php' !== $pagenow ) {
911 return;
912 }
913
914 $form_id = FrmAppHelper::simple_get( 'frmForm', 'absint' );
915 if ( ! $form_id ) {
916 return;
917 }
918
919 self::add_js_to_inject_gutenberg_block( 'formidable/simple-form', 'formId', $form_id );
920 }
921
922 /**
923 * @since 5.3
924 *
925 * @param string $block_name
926 * @param string $object_key
927 * @param array|string $object_id
928 *
929 * @return void
930 */
931 public static function add_js_to_inject_gutenberg_block( $block_name, $object_key, $object_id ) {
932 require FrmAppHelper::plugin_path() . '/classes/views/shared/edit-page-js.php';
933 }
934
935 /**
936 * @return void
937 */
938 public static function load_lang() {
939 load_plugin_textdomain( 'formidable', false, FrmAppHelper::plugin_folder() . '/languages/' );
940 }
941
942 /**
943 * Check if the styles are updated when a form is loaded on the front-end
944 *
945 * @since 3.0.1
946 *
947 * @return void
948 */
949 public static function maybe_update_styles() {
950 if ( self::needs_update() ) {
951 self::network_upgrade_site();
952 }
953 }
954
955 /**
956 * @since 3.0
957 *
958 * @return void
959 */
960 public static function create_rest_routes() {
961 $args = array(
962 'methods' => 'GET',
963 'callback' => 'FrmAppController::api_install',
964 'permission_callback' => __CLASS__ . '::can_update_db',
965 );
966
967 register_rest_route( 'frm-admin/v1', '/install', $args );
968
969 $args = array(
970 'methods' => 'GET',
971 'callback' => 'FrmAddonsController::install_addon_api',
972 'permission_callback' => 'FrmAddonsController::can_install_addon_api',
973 );
974
975 register_rest_route( 'frm-admin/v1', '/install-addon', $args );
976 }
977
978 /**
979 * Make sure the install is only being run when we tell it to.
980 * We don't want to run manually by people calling the API.
981 *
982 * @since 4.06.02
983 */
984 public static function can_update_db() {
985 return get_transient( 'frm_updating_api' );
986 }
987
988 /**
989 * Run silent upgrade on each site in the network during a network upgrade.
990 * Update database settings for all sites in a network during network upgrade process.
991 *
992 * @since 2.0.1
993 *
994 * @param int $blog_id Blog ID.
995 *
996 * @return void
997 */
998 public static function network_upgrade_site( $blog_id = 0 ) {
999 // Flag to check if install is happening as intended.
1000 set_transient( 'frm_updating_api', true, MINUTE_IN_SECONDS );
1001 $request = new WP_REST_Request( 'GET', '/frm-admin/v1/install' );
1002
1003 self::maybe_add_wp_site_health();
1004
1005 if ( $blog_id ) {
1006 switch_to_blog( $blog_id );
1007 $response = rest_do_request( $request );
1008 restore_current_blog();
1009 } else {
1010 $response = rest_do_request( $request );
1011 }
1012
1013 if ( $response->is_error() ) {
1014 // if the remove post fails, use javascript instead
1015 add_action( 'admin_notices', 'FrmAppController::install_js_fallback' );
1016 }
1017 }
1018
1019 /**
1020 * Make sure WP_Site_Health has been included because it is required when calling rest_do_request.
1021 * Check first that the file exists because WP_Site_Health was only introduced in WordPress 5.2.
1022 *
1023 * @return void
1024 */
1025 private static function maybe_add_wp_site_health() {
1026 if ( ! class_exists( 'WP_Site_Health' ) ) {
1027 $wp_site_health_path = ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
1028 if ( file_exists( $wp_site_health_path ) ) {
1029 require_once $wp_site_health_path;
1030 }
1031 }
1032 }
1033
1034 /**
1035 * @since 3.0
1036 *
1037 * @return true
1038 */
1039 public static function api_install() {
1040 delete_transient( 'frm_updating_api' );
1041 if ( self::needs_update() ) {
1042 $running = get_option( 'frm_install_running' );
1043 if ( false === $running || $running < strtotime( '-5 minutes' ) ) {
1044 update_option( 'frm_install_running', time(), 'no' );
1045 self::install();
1046 delete_option( 'frm_install_running' );
1047 }
1048 }
1049
1050 return true;
1051 }
1052
1053 /**
1054 * Silent database upgrade (no redirect).
1055 * Called via ajax request during network upgrade process.
1056 *
1057 * @since 2.0.1
1058 *
1059 * @return void
1060 */
1061 public static function ajax_install() {
1062 FrmAppHelper::permission_check( 'frm_change_settings' );
1063 check_ajax_referer( 'frm_ajax', 'nonce' );
1064 self::api_install();
1065 wp_die();
1066 }
1067
1068 /**
1069 * @return void
1070 */
1071 public static function install() {
1072 $frmdb = new FrmMigrate();
1073 $frmdb->upgrade();
1074 }
1075
1076 /**
1077 * @return void
1078 */
1079 public static function uninstall() {
1080 FrmAppHelper::permission_check( 'administrator' );
1081 check_ajax_referer( 'frm_ajax', 'nonce' );
1082
1083 $frmdb = new FrmMigrate();
1084 $frmdb->uninstall();
1085
1086 // Disable the plugin and redirect after uninstall so the tables don't get added right back.
1087 $plugins = array( FrmAppHelper::plugin_folder() . '/formidable.php', 'formidable-pro/formidable-pro.php' );
1088 deactivate_plugins( $plugins, false, false );
1089 echo esc_url_raw( admin_url( 'plugins.php?deactivate=true' ) );
1090
1091 wp_die();
1092 }
1093
1094 public static function drop_tables( $tables ) {
1095 global $wpdb;
1096 $tables[] = $wpdb->prefix . 'frm_fields';
1097 $tables[] = $wpdb->prefix . 'frm_forms';
1098 $tables[] = $wpdb->prefix . 'frm_items';
1099 $tables[] = $wpdb->prefix . 'frm_item_metas';
1100
1101 return $tables;
1102 }
1103
1104 /**
1105 * @return void
1106 */
1107 public static function deauthorize() {
1108 FrmAppHelper::permission_check( 'frm_change_settings' );
1109 check_ajax_referer( 'frm_ajax', 'nonce' );
1110
1111 delete_option( 'frmpro-credentials' );
1112 delete_option( 'frmpro-authorized' );
1113 delete_site_option( 'frmpro-credentials' );
1114 delete_site_option( 'frmpro-authorized' );
1115 wp_die();
1116 }
1117
1118 /**
1119 * This is triggered when Formidable is activated.
1120 *
1121 * @return void
1122 */
1123 public static function handle_activation() {
1124 self::maybe_activate_payment_cron();
1125 }
1126
1127 /**
1128 * The payment cron is unscheduled when Formidable is deactivated.
1129 * We need to add it back again on activation if Stripe is configured.
1130 *
1131 * @since 6.5
1132 *
1133 * @return void
1134 */
1135 private static function maybe_activate_payment_cron() {
1136 if ( ! FrmStrpLiteConnectHelper::stripe_connect_is_setup() ) {
1137 return;
1138 }
1139
1140 FrmTransLiteAppController::maybe_schedule_cron();
1141 }
1142
1143 public static function set_footer_text( $text ) {
1144 if ( FrmAppHelper::is_formidable_admin() ) {
1145 $text = '';
1146 }
1147
1148 return $text;
1149 }
1150
1151 /**
1152 * Add admin footer links.
1153 *
1154 * @since 6.4.1
1155 *
1156 * @return void
1157 */
1158 public static function add_admin_footer_links() {
1159 if ( self::should_show_footer_links() ) {
1160 include FrmAppHelper::plugin_path() . '/classes/views/shared/admin-footer-links.php';
1161 }
1162 }
1163
1164 /**
1165 * Check if the footer links should be shown.
1166 *
1167 * @since 6.7
1168 *
1169 * @return bool
1170 */
1171 private static function should_show_footer_links() {
1172 $post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
1173 $is_formidable_page = FrmAppHelper::is_formidable_admin() || 'frm_logs' === $post_type;
1174 $show_footer_links = $is_formidable_page;
1175 if ( FrmAppHelper::is_full_screen() || ! FrmAppHelper::is_formidable_branding() ) {
1176 $show_footer_links = false;
1177 }
1178
1179 /**
1180 * Filter whether to show the Formidable footer links.
1181 *
1182 * @since 6.7
1183 *
1184 * @param bool $show_footer_links
1185 * @return bool
1186 */
1187 return apply_filters( 'frm_show_footer_links', $show_footer_links );
1188 }
1189
1190 /**
1191 * Show an error modal and terminate the script execution.
1192 *
1193 * @since 6.7
1194 *
1195 * @param array $error_args Arguments that control the behavior of the error modal.
1196 *
1197 * @return void
1198 */
1199 public static function show_error_modal( $error_args ) {
1200 $defaults = array(
1201 'title' => '',
1202 'body' => '',
1203 'cancel_url' => '',
1204 'cancel_classes' => '',
1205 'continue_url' => '',
1206 'continue_classes' => '',
1207 'icon' => 'frm_lock_simple',
1208 );
1209
1210 $error_args = wp_parse_args( $error_args, $defaults );
1211 if ( ! isset( $error_args['cancel_text'] ) && ! empty( $error_args['cancel_url'] ) ) {
1212 $error_args['cancel_text'] = __( 'Cancel', 'formidable' );
1213 }
1214
1215 if ( ! isset( $error_args['continue_text'] ) && ! empty( $error_args['continue_url'] ) ) {
1216 $error_args['continue_text'] = __( 'Continue', 'formidable' );
1217 }
1218
1219 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/error-modal.php';
1220 }
1221
1222 /**
1223 * @deprecated 3.0.04
1224 *
1225 * @codeCoverageIgnore
1226 *
1227 * @return void
1228 */
1229 public static function activation_install() {
1230 FrmDeprecated::activation_install();
1231 }
1232
1233 /**
1234 * @deprecated 3.0
1235 * @codeCoverageIgnore
1236 */
1237 public static function page_route( $content ) {
1238 return FrmDeprecated::page_route( $content );
1239 }
1240
1241 /**
1242 * Include icons on page for Embed Form modal.
1243 *
1244 * @since 5.2
1245 *
1246 * @return void
1247 */
1248 public static function include_embed_form_icons() {
1249 _deprecated_function( __METHOD__, '5.3' );
1250 }
1251
1252 /**
1253 * @deprecated 1.07.05 This is still referenced in the API add on as of v1.13.
1254 * @codeCoverageIgnore
1255 *
1256 * @param array $atts
1257 * @return string
1258 */
1259 public static function get_form_shortcode( $atts ) {
1260 _deprecated_function( __FUNCTION__, '1.07.05', 'FrmFormsController::get_form_shortcode' );
1261 return FrmFormsController::get_form_shortcode( $atts );
1262 }
1263
1264 /**
1265 * Handles Floating Links' scripts and styles enqueueing.
1266 *
1267 * @since 6.4
1268 *
1269 * @param string $plugin_url URL of the plugin.
1270 * @param string $version Current version of the plugin.
1271 * @return void
1272 */
1273 private static function enqueue_floating_links( $plugin_url, $version ) {
1274 if ( ! $plugin_url || ! $version ) {
1275 // If any required parameters are missing, exit early.
1276 return;
1277 }
1278
1279 // Enqueue the Floating Links styles.
1280 wp_enqueue_style( 's11-floating-links', $plugin_url . '/css/packages/s11-floating-links.css', array(), $version );
1281
1282 // Enqueue the Floating Links script.
1283 wp_enqueue_script( 's11-floating-links', $plugin_url . '/js/packages/floating-links/s11-floating-links.js', array(), $version, true );
1284
1285 // Enqueue the config script.
1286 wp_enqueue_script( 's11-floating-links-config', $plugin_url . '/js/packages/floating-links/config.js', array( 'wp-i18n' ), $version, true );
1287
1288 if ( function_exists( 'wp_set_script_translations' ) ) {
1289 wp_set_script_translations( 's11-floating-links-config', 's11-' );
1290 }
1291
1292 $floating_links_data = array(
1293 'proIsInstalled' => FrmAppHelper::pro_is_installed(),
1294 );
1295 wp_localize_script( 's11-floating-links-config', 's11FloatingLinksData', $floating_links_data );
1296
1297 /**
1298 * Prompt Pro to load additional floating links scripts.
1299 * This is used to include images in the Inbox SlideIn when Pro is active.
1300 *
1301 * @since 6.8.4
1302 */
1303 do_action( 'frm_enqueue_floating_links' );
1304 }
1305 }
1306