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

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