<?php
if ( ! defined( 'ABSPATH' ) ) {
	die( 'You are not allowed to call this page directly.' );
}

class FrmAppController {

	/**
	 * @return void
	 */
	public static function menu() {
		FrmAppHelper::maybe_add_permissions();

		if ( ! current_user_can( 'frm_view_forms' ) ) {
			return;
		}

		$menu_name = FrmAppHelper::get_menu_name();

		if ( in_array( $menu_name, array( 'Formidable', 'Forms' ), true ) ) {
			$menu_name .= wp_kses_post( FrmInboxController::get_notice_count() );
		}

		add_menu_page( 'Formidable', $menu_name, 'frm_view_forms', 'formidable', 'FrmFormsController::route', self::menu_icon(), self::get_menu_position() );
	}

	/**
	 * @return int
	 */
	private static function get_menu_position() {
		return (int) apply_filters( 'frm_menu_position', 29 );
	}

	/**
	 * @since 3.05
	 *
	 * @return string
	 */
	private static function menu_icon() {
		$icon = FrmAppHelper::svg_logo(
			array(
				'fill'   => '#a0a5aa',
				'orange' => '#a0a5aa',
			)
		);
		$icon = 'data:image/svg+xml;base64,' . base64_encode( $icon );

		return apply_filters( 'frm_icon', $icon );
	}

	/**
	 * @since 3.0
	 *
	 * @param string $classes
	 *
	 * @return string
	 */
	public static function add_admin_class( $classes ) {
		if ( self::is_white_page() ) {
			$classes .= ' frm-white-body ';
			$classes .= self::get_os();

			$page = str_replace( 'formidable-', '', FrmAppHelper::simple_get( 'page', 'sanitize_title' ) );

			if ( ! $page || $page === 'formidable' ) {
				$action = FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );

				if ( in_array( $action, array( 'settings', 'edit', 'list' ), true ) ) {
					$page .= $action;
				} else {
					$page = $action;
				}
			}

			if ( $page ) {
				$classes .= ' frm-admin-page-' . $page;
			}
		}

		if ( self::is_grey_page() ) {
			$classes .= ' frm-grey-body ';
		}

		if ( FrmAppHelper::is_full_screen() ) {
			$full_screen_on = self::get_full_screen_setting();
			$add_class      = '';

			if ( $full_screen_on ) {
				$add_class = ' frm-full-screen is-fullscreen-mode';

				// Load the CSS for .is-fullscreen-mode.
				wp_enqueue_style( 'wp-edit-post' );
			}

			$classes .= apply_filters( 'frm_admin_full_screen_class', $add_class );
		}

		if ( ! FrmAppHelper::pro_is_installed() ) {
			$classes .= ' frm-lite ';
		}

		if ( get_user_setting( 'unfold' ) && 'f' !== get_user_setting( 'mfold' ) ) {
			$classes .= ' frm-unfold ';
		}

		return $classes;
	}

	/**
	 * Get the full screen mode setting from the block editor.
	 *
	 * @since 6.1
	 *
	 * @return bool
	 */
	private static function get_full_screen_setting() {
		global $wpdb;
		$meta_key = $wpdb->get_blog_prefix() . 'persisted_preferences';
		$prefs    = get_user_meta( get_current_user_id(), $meta_key, true );

		if ( $prefs && isset( $prefs['core/edit-post']['fullscreenMode'] ) ) {
			return $prefs['core/edit-post']['fullscreenMode'];
		}

		return true;
	}

	/**
	 * @since 4.0
	 *
	 * @return string
	 */
	private static function get_os() {
		$agent = strtolower( FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' ) );
		$os    = '';

		if ( str_contains( $agent, 'mac' ) ) {
			$os = ' osx';
		} elseif ( str_contains( $agent, 'linux' ) ) {
			$os = ' linux';
		} elseif ( str_contains( $agent, 'windows' ) ) {
			$os = ' windows';
		}

		return $os;
	}

	/**
	 * @since 3.0
	 *
	 * @return bool
	 */
	private static function is_white_page() {
		$white_pages = array(
			'formidable',
			'formidable-entries',
			'formidable-views',
			'formidable-views-editor',
			'formidable-addons',
			'formidable-import',
			'formidable-settings',
			'formidable-styles',
			'formidable-styles2',
			'formidable-inbox',
			FrmFormTemplatesController::PAGE_SLUG,
			FrmOnboardingWizardController::PAGE_SLUG,
		);

		if ( self::is_white_payments_page() ) {
			$white_pages[] = 'formidable-payments';
		}

		$is_white_page = self::is_page_in_list( $white_pages ) || self::is_grey_page() || FrmAppHelper::is_view_builder_page();

		/**
		 * Allow another add on to style a page as a Formidable "white page", which adds a white background color.
		 *
		 * @since 5.3
		 *
		 * @param bool $is_white_page
		 */
		return apply_filters( 'frm_is_white_page', $is_white_page );
	}

	/**
	 * Check if the payments page should be styled as a white page.
	 * Fallback to the Stripe, Authorize.Net, or PayPal add on for the "edit" action since
	 * Stripe Lite does not have an edit view. Also fallback for bulk deleting, since that
	 * isn't built into Lite. The pages we fall back to should not be styled as white pages.
	 *
	 * @since 6.27
	 *
	 * @return bool
	 */
	private static function is_white_payments_page() {
		$action       = FrmAppHelper::simple_get( 'action', 'sanitize_title' );
		$on_edit_page = in_array( $action, array( 'edit', 'new' ), true );
		return ! $on_edit_page && 'bulk_delete' !== $action;
	}

	/**
	 * Add a grey bg instead of white.
	 *
	 * @since 6.8
	 *
	 * @return bool
	 */
	private static function is_grey_page() {
		$grey_pages = array(
			'formidable-applications',
			'formidable-dashboard',
			'formidable-views',
		);

		$is_grey_page = self::is_page_in_list( $grey_pages );

		/**
		 * Filter to change FF wrapper background to grey.
		 *
		 * @since 6.8
		 *
		 * @param bool $is_grey_page
		 *
		 * @return bool
		 */
		return apply_filters( 'frm_is_grey_page', $is_grey_page );
	}

	/**
	 * @since 6.8
	 *
	 * @param array $pages A list of page names to check.
	 *
	 * @return bool
	 */
	private static function is_page_in_list( $pages ) {
		$get_page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
		return in_array( $get_page, $pages, true );
	}

	/**
	 * @return void
	 */
	public static function load_wp_admin_style() {
		FrmAppHelper::load_font_style();
	}

	/**
	 * @param int|object $form
	 * @param bool       $show_nav
	 * @param string     $title
	 *
	 * @psalm-param 'hide'|'show' $title
	 *
	 * @return void
	 */
	public static function get_form_nav( $form, $show_nav = false, $title = 'show' ) {
		$show_nav = FrmAppHelper::get_param( 'show_nav', $show_nav, 'get', 'absint' );

		if ( ! $show_nav || ! $form ) {
			return;
		}

		FrmForm::maybe_get_form( $form );

		if ( ! is_object( $form ) ) {
			return;
		}

		$id           = $form->id;
		$current_page = self::get_current_page();
		$nav_items    = self::get_form_nav_items( $form );

		include FrmAppHelper::plugin_path() . '/classes/views/shared/form-nav.php';
	}

	/**
	 * @return string
	 */
	private static function get_current_page() {
		$page      = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
		$post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title', 'None' );

		if ( FrmAppHelper::is_view_builder_page() ) {
			return 'frm_display';
		}

		return isset( $_GET['page'] ) ? $page : $post_type;
	}

	/**
	 * @param object $form
	 *
	 * @return array
	 */
	private static function get_form_nav_items( $form ) {
		$id = $form->parent_form_id ? $form->parent_form_id : $form->id;

		$nav_items = array(
			array(
				'link'       => FrmForm::get_edit_link( $id ),
				'label'      => __( 'Build', 'formidable' ),
				'current'    => array( 'edit', 'new', 'duplicate' ),
				'page'       => 'formidable',
				'permission' => 'frm_edit_forms',
			),
			array(
				'link'       => FrmStylesHelper::get_list_url( $id ),
				'label'      => __( 'Style', 'formidable' ),
				'current'    => array(),
				'page'       => 'formidable-styles',
				'permission' => 'frm_edit_forms',
			),
			array(
				'link'       => admin_url( 'admin.php?page=formidable&frm_action=settings&id=' . absint( $id ) ),
				'label'      => __( 'Settings', 'formidable' ),
				'current'    => array( 'settings' ),
				'page'       => 'formidable',
				'permission' => 'frm_edit_forms',
			),
			array(
				'link'       => admin_url( 'admin.php?page=formidable-entries&frm_action=list&form=' . absint( $id ) ),
				'label'      => __( 'Entries', 'formidable' ),
				'current'    => array(),
				'page'       => 'formidable-entries',
				'permission' => 'frm_view_entries',
			),
		);

		$views_installed = is_callable( 'FrmProAppHelper::views_is_installed' ) && FrmProAppHelper::views_is_installed();

		if ( ! $views_installed ) {
			$nav_items[] = array(
				'link'       => admin_url( 'admin.php?page=formidable-views&form=' . absint( $id ) ),
				'label'      => __( 'Views', 'formidable' ),
				'current'    => array(),
				'page'       => 'formidable-views',
				'permission' => 'frm_view_entries',
				'atts'       => array(
					'class' => 'frm_noallow',
				),
			);
		}

		// Let people know reports and views exist.
		if ( ! FrmAppHelper::pro_is_installed() ) {
			$nav_items[] = array(
				'link'       => admin_url( 'admin.php?page=formidable&frm_action=lite-reports&form=' . absint( $id ) ),
				'label'      => __( 'Reports', 'formidable' ),
				'current'    => array( 'reports' ),
				'page'       => 'formidable',
				'permission' => 'frm_view_entries',
				'atts'       => array(
					'class' => 'frm_noallow',
				),
			);
		}

		$nav_args = array(
			'form_id' => $id,
			'form'    => $form,
		);

		return (array) apply_filters( 'frm_form_nav_list', $nav_items, $nav_args );
	}

	/**
	 * Adds a settings link to the plugins page
	 *
	 * @param array $links
	 *
	 * @return array
	 */
	public static function settings_link( $links ) {
		$settings = array();

		if ( ! FrmAppHelper::pro_is_installed() ) {
			if ( FrmAddonsController::is_license_expired() ) {
				$label = __( 'Renew', 'formidable' );
			} else {
				$label = FrmSalesApi::get_best_sale_value( 'plugin_page_cta_text' );

				if ( ! $label ) {
					$label = __( 'Upgrade to Pro', 'formidable' );
				}
			}

			$upgrade_link = FrmSalesApi::get_best_sale_value( 'plugin_page_cta_link' );

			if ( $upgrade_link ) {
				$upgrade_link = FrmAppHelper::maybe_add_missing_utm( $upgrade_link, array( 'medium' => 'plugin-row' ) );
			} else {
				$upgrade_link = FrmAppHelper::admin_upgrade_link( 'plugin-row' );
			}

			$settings[] = '<a href="' . esc_url( $upgrade_link ) . '" target="_blank" rel="noopener"><b style="color:#1da867;font-weight:700;">' . esc_html( $label ) . '</b></a>';
		}//end if

		$settings[] = '<a href="' . esc_url( admin_url( 'admin.php?page=formidable' ) ) . '">' . __( 'Build a Form', 'formidable' ) . '</a>';

		return array_merge( $settings, $links );
	}

	/**
	 * @return void
	 */
	public static function pro_get_started_headline() {
		self::review_request();
		FrmAppHelper::min_pro_version_notice( '6.20' );
	}

	/**
	 * Add admin notices as needed for reviews
	 *
	 * @since 3.04.03
	 *
	 * @return void
	 */
	private static function review_request() {
		$reviews = new FrmReviews();
		$reviews->review_request();
	}

	/**
	 * Save the request to hide the review
	 *
	 * @since 3.04.03
	 *
	 * @return void
	 */
	public static function dismiss_review() {
		FrmAppHelper::permission_check( 'frm_change_settings' );
		check_ajax_referer( 'frm_ajax', 'nonce' );

		$reviews = new FrmReviews();
		$reviews->dismiss_review();
	}

	/**
	 * @since 3.04.02
	 *
	 * @return void
	 */
	public static function include_upgrade_overlay() {
		self::enqueue_dialog_assets();
		add_action( 'admin_footer', 'FrmAppController::upgrade_overlay_html' );
	}

	/**
	 * Enqueue scripts and styles required for modals.
	 *
	 * @since 5.3
	 *
	 * @return void
	 */
	public static function enqueue_dialog_assets() {
		wp_enqueue_script( 'jquery-ui-dialog' );
		wp_enqueue_style( 'jquery-ui-dialog' );
	}

	/**
	 * @since 3.06.03
	 *
	 * @return void
	 */
	public static function upgrade_overlay_html() {
		$is_pro       = FrmAppHelper::pro_is_installed();
		$upgrade_link = array(
			'medium'  => 'builder',
			'content' => 'upgrade',
		);
		$default_link = FrmAppHelper::admin_upgrade_link( $upgrade_link );
		$plugin_path  = FrmAppHelper::plugin_path();
		$shared_path  = $plugin_path . '/classes/views/shared/';

		include $shared_path . 'upgrade_overlay.php';
		include $shared_path . 'confirm-overlay.php';
	}

	/**
	 * Create a basic form with an email field.
	 *
	 * @param string $form_key
	 * @param string $title
	 * @param string $description
	 *
	 * @return void
	 */
	public static function api_email_form( $form_key, $title = '', $description = '' ) {
		$user = wp_get_current_user();
		$args = array(
			'api_url'     => 'https://sandbox.formidableforms.com/api/wp-json/frm/v2/forms/' . $form_key . '?return=html&exclude_script=jquery&exclude_style=formidable-css',
			'title'       => $title,
			'description' => $description,
		);
		require FrmAppHelper::plugin_path() . '/classes/views/form-templates/modals/leave-email-modal.php';
	}

	/**
	 * @return void
	 */
	public static function include_info_overlay() {
		self::enqueue_dialog_assets();
		add_action( 'admin_footer', 'FrmAppController::info_overlay_html' );
	}

	/**
	 * @return void
	 */
	public static function info_overlay_html() {
		include FrmAppHelper::plugin_path() . '/classes/views/shared/info-overlay.php';
	}

	/**
	 * @since 3.04.02
	 *
	 * @return void
	 */
	public static function remove_upsells() {
		remove_action( 'frm_before_settings', 'FrmSettingsController::license_box' );
		remove_action( 'frm_after_settings_tabs', 'FrmSettingsController::settings_cta' );
		remove_action( 'frm_after_field_options', 'FrmFormsController::logic_tip' );
	}

	/**
	 * If there are CURL problems on this server, wp_remote_post won't work for installing
	 * Use a javascript fallback instead.
	 *
	 * @since 2.0.3
	 *
	 * @return void
	 */
	public static function install_js_fallback() {
		FrmAppHelper::load_admin_wide_js();
		?>
			<div id="frm_install_message"></div>
			<script>jQuery(document).ready( frm_install_now );</script>
		<?php
	}

	/**
	 * Check if the database is outdated
	 *
	 * @since 2.0.1
	 *
	 * @return bool
	 */
	public static function needs_update() {
		$needs_upgrade = self::compare_for_update(
			array(
				'option'             => 'frm_db_version',
				'new_db_version'     => FrmAppHelper::$db_version,
				'new_plugin_version' => FrmAppHelper::plugin_version(),
			)
		);

		if ( ! $needs_upgrade ) {
			$needs_upgrade = apply_filters( 'frm_db_needs_upgrade', $needs_upgrade );
		}

		return $needs_upgrade;
	}

	/**
	 * Check both version number and DB number for changes
	 *
	 * @since 3.0.04
	 *
	 * @param array $atts
	 *
	 * @return bool
	 */
	public static function compare_for_update( $atts ) {
		$db_version = get_option( $atts['option'] );

		if ( ! str_contains( $db_version, '-' ) ) {
			return true;
		}

		$last_upgrade     = explode( '-', $db_version );
		$needs_db_upgrade = (int) $last_upgrade[1] < (int) $atts['new_db_version'];
		$new_version      = version_compare( $last_upgrade[0], $atts['new_plugin_version'], '<' );

		return $needs_db_upgrade || $new_version;
	}

	/**
	 * Check for database update and trigger js loading
	 *
	 * @since 2.0.1
	 *
	 * @return void
	 */
	public static function admin_init() {
		if ( FrmAppHelper::get_param( 'delete_all' ) && FrmAppHelper::is_admin_page( 'formidable' ) && 'trash' === FrmAppHelper::get_param( 'form_type' ) ) {
			FrmFormsController::delete_all();
		}

		if ( FrmAppHelper::is_admin_page( 'formidable' ) && 'duplicate' === FrmAppHelper::get_param( 'frm_action' ) ) {
			FrmFormsController::duplicate();
		}

		if ( FrmAppHelper::is_admin_page( 'formidable' ) && FrmAppHelper::simple_get( 'frm_add_tables' ) ) {
			self::add_missing_tables();
		}

		if ( FrmAppHelper::is_style_editor_page() && 'save' === FrmAppHelper::get_param( 'frm_action' ) ) {
			// Hook in earlier than FrmStylesController::route so we can redirect before the headers have been sent.
			FrmStylesController::save_style();
		}

		if ( 'formidable-pro-upgrade' === FrmAppHelper::get_param( 'page' ) && ! FrmAppHelper::pro_is_installed() && current_user_can( 'frm_view_forms' ) ) {
			$redirect = FrmSalesApi::get_best_sale_value( 'menu_cta_link' );
			$utm      = array(
				'campaign' => 'upgrade',
				'content'  => 'submenu-upgrade',
			);

			$redirect = $redirect ? FrmAppHelper::maybe_add_missing_utm( $redirect, $utm ) : FrmAppHelper::admin_upgrade_link( $utm );

			wp_redirect( $redirect );
			die();
		}

		// Register personal data hooks.
		new FrmPersonalData();

		if ( ! FrmAppHelper::doing_ajax() && self::needs_update() ) {
			self::network_upgrade_site();
		}

		if ( ! FrmAppHelper::doing_ajax() ) {
			// don't continue during ajax calls
			self::admin_js();
		}

		self::trigger_page_load_hooks();

		if ( FrmAppHelper::is_admin_page( 'formidable' ) ) {
			// Redirect to the "Form Templates" page if the 'frm_action' parameter matches specific actions.
			// This provides backward compatibility for old addons that use legacy modal templates.
			$action             = FrmAppHelper::get_param( 'frm_action' );
			$trigger_name_modal = FrmAppHelper::get_param( 'triggerNewFormModal' );

			if ( $trigger_name_modal || in_array( $action, array( 'add_new', 'list_templates' ), true ) ) {
				$application_id = FrmAppHelper::simple_get( 'applicationId', 'absint' );
				$url_param      = $application_id ? '&applicationId=' . $application_id : '';

				wp_safe_redirect( admin_url( 'admin.php?page=' . FrmFormTemplatesController::PAGE_SLUG . $url_param ) );
				exit;
			}

			FrmInbox::maybe_disable_screen_options();
		}
	}

	/**
	 * Get the current page and check for a possible function to trigger.
	 * If a class name matches the page name, and the class has a load_page() method, trigger it.
	 *
	 * @since 6.8
	 *
	 * @return void
	 */
	private static function trigger_page_load_hooks() {
		$page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );

		if ( ! str_starts_with( $page, 'formidable-' ) ) {
			// Only trigger hooks on Formidable pages.
			return;
		}

		$page  = str_replace( array( 'formidable-', '-' ), array( '', ' ' ), $page );
		$page  = str_replace( ' ', '', ucwords( $page ) );
		$class = 'Frm' . $page . 'Controller';

		if ( class_exists( $class ) && method_exists( $class, 'load_page' ) ) {
			call_user_func( array( $class, 'load_page' ) );
		}
	}

	/**
	 * @return void
	 */
	public static function admin_js() {
		$plugin_url = FrmAppHelper::plugin_url();
		$version    = FrmAppHelper::plugin_version();

		FrmAppHelper::load_admin_wide_js();

		// Register component assets early to ensure they can be enqueued later in controllers.
		wp_register_style( 'formidable-animations', $plugin_url . '/css/admin/animations.css', array(), $version );

		if ( class_exists( 'FrmOverlayController' ) ) {
			// This should always exist.
			// But it may not have loaded properly when updating the plugin.
			FrmOverlayController::register_assets();
		}

		wp_register_style( 'formidable_admin_global', $plugin_url . '/css/admin/frm_admin_global.css', array(), $version );
		wp_enqueue_style( 'formidable_admin_global' );

		wp_register_style( 'formidable-admin', $plugin_url . '/css/frm_admin.css', array(), $version );
		wp_register_style( 'formidable-grids', $plugin_url . '/css/frm_grids.css', array(), $version );

		wp_register_script( 'formidable_dom', $plugin_url . '/js/admin/dom.js', array( 'jquery', 'jquery-ui-dialog', 'wp-i18n' ), $version, true );
		wp_register_script( 'formidable_embed', $plugin_url . '/js/admin/embed.js', array( 'formidable_dom', 'jquery-ui-autocomplete' ), $version, true );
		self::register_popper2();
		wp_register_script( 'bootstrap_tooltip', $plugin_url . '/js/bootstrap.min.js', array( 'jquery', 'popper' ), '5.0.2', true );

		$settings_js_vars = array(
			'currencies' => FrmCurrencyHelper::get_currencies(),
		);
		wp_register_script( 'formidable_settings', $plugin_url . '/js/admin/settings.js', array(), $version, true );
		wp_localize_script( 'formidable_settings', 'frmSettings', $settings_js_vars );

		wp_register_script( 'formidable-web-components', $plugin_url . '/js/formidable-web-components.js', array( 'formidable_admin' ), $version, true );

		if ( self::should_show_floating_links() ) {
			self::enqueue_floating_links( $plugin_url, $version );
		}

		wp_register_script( 'formidable_admin', $plugin_url . '/js/formidable_admin.js', self::get_admin_js_dependencies(), $version, true );

		if ( FrmAppHelper::on_form_listing_page() ) {
			// For the existing page dropdown in the Form embed modal.
			wp_enqueue_script( 'jquery-ui-autocomplete' );
		}

		wp_register_script( 'bootstrap-multiselect', $plugin_url . '/js/bootstrap-multiselect.js', array( 'jquery', 'bootstrap_tooltip', 'popper' ), '2.0', true );

		if ( ! class_exists( 'FrmTransHooksController', false ) ) {
			/**
			 * Gateway fields are included for add-on compatibility but we do not want it to be visible.
			 * They do however need to be visible when the payments submodule is active.
			 */
			wp_add_inline_style(
				'formidable-admin',
				'#frm_builder_page li[data-ftype="gateway"] { display: none; }'
			);
		}

		$page      = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
		$post_type = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );

		global $pagenow;

		if ( str_starts_with( $page, 'formidable' ) || ( $pagenow === 'edit.php' && $post_type === 'frm_display' ) ) {
			self::enqueue_global_settings_scripts( $page );

			wp_enqueue_script( 'admin-widgets' );
			wp_enqueue_style( 'widgets' );
			self::maybe_deregister_popper1();
			wp_enqueue_script( 'formidable_admin' );
			wp_set_script_translations( 'formidable_admin', 'formidable' );
			wp_enqueue_script( 'formidable_embed' );
			wp_set_script_translations( 'formidable_embed', 'formidable' );
			FrmAppHelper::localize_script( 'admin' );

			wp_enqueue_style( 'formidable-animations' );
			wp_enqueue_style( 'formidable-admin' );

			if ( 'formidable-styles' !== $page && 'formidable-styles2' !== $page ) {
				wp_enqueue_style( 'formidable-grids' );
				self::maybe_enqueue_dropzone_css( $page );
			} else {
				wp_enqueue_style( 'formidable-grids' );
			}

			if ( 'formidable-entries' === $page ) {
				// Load front end js for entries.
				wp_enqueue_script( 'formidable' );

				// Registers and enqueues the entries page scripts.
				wp_register_script( 'formidable_entries', $plugin_url . '/js/admin/entries.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
				wp_enqueue_script( 'formidable_entries' );
			}

			do_action( 'frm_enqueue_builder_scripts' );
			self::include_upgrade_overlay();
			self::include_info_overlay();
		} elseif ( FrmAppHelper::is_view_builder_page() ) {
			if ( isset( $_REQUEST['post_type'] ) ) {
				$post_type = sanitize_title( wp_unslash( $_REQUEST['post_type'] ) );
			} elseif ( isset( $_REQUEST['post'] ) && absint( $_REQUEST['post'] ) ) {
				$post = get_post( absint( wp_unslash( $_REQUEST['post'] ) ) );

				if ( ! $post ) {
					return;
				}

				$post_type = $post->post_type;
			} else {
				return;
			}

			if ( $post_type === 'frm_display' ) {
				self::enqueue_legacy_views_assets();
			}
		}//end if

		if ( 'formidable-addons' === $page ) {
			wp_register_script( 'formidable_addons', $plugin_url . '/js/admin/addons.js', array( 'formidable_admin', 'wp-dom-ready' ), $version, true );
			wp_enqueue_script( 'formidable_addons' );
		}

		self::enqueue_builder_assets( $plugin_url, $version );
	}

	/**
	 * @since 6.27
	 *
	 * @return array
	 */
	private static function get_admin_js_dependencies() {
		$dependencies = array(
			'formidable_admin_global',
			'jquery',
			'jquery-ui-core',
			'jquery-ui-draggable',
			'jquery-ui-sortable',
			'bootstrap_tooltip',
			'bootstrap-multiselect',
			'wp-i18n',
			// Required in WP versions older than 5.7
			'wp-hooks',
			'formidable_dom',
			'formidable_embed',
		);

		if ( FrmAppHelper::is_style_editor_page( 'edit' ) ) {
			// We only need to load the color picker when editing styles.
			$dependencies[] = 'wp-color-picker';
		}

		return $dependencies;
	}

	/**
	 * Enqueue the Form Builder assets.
	 *
	 * @since 6.24
	 *
	 * @param string $plugin_url The plugin URL.
	 * @param string $version    The plugin version.
	 *
	 * @return void
	 */
	private static function enqueue_builder_assets( $plugin_url, $version ) {
		wp_register_style( 'formidable-settings-components', $plugin_url . '/css/admin/frm-settings-components.css', array( 'formidable-admin', 'formidable-grids' ), $version );
		wp_register_script( 'formidable-settings-components', $plugin_url . '/js/formidable-settings-components.js', array( 'formidable_admin' ), $version, true );

		if ( ! FrmAppHelper::is_form_builder_page() ) {
			return;
		}

		wp_enqueue_style( 'formidable-settings-components' );
		wp_enqueue_script( 'formidable-settings-components' );
	}

	/**
	 * Enqueues global settings scripts.
	 *
	 * @param string $page The `page` param in URL.
	 *
	 * @return void
	 */
	private static function enqueue_global_settings_scripts( $page ) {
		if ( 'formidable-settings' === $page ) {
			wp_enqueue_style( 'wp-color-picker' );
			wp_enqueue_script( 'formidable_settings' );
		}
	}

	/**
	 * Avoid loading dropzone CSS on the form list page. It isn't required there.
	 *
	 * @since 6.11
	 *
	 * @param string $page
	 *
	 * @return void
	 */
	private static function maybe_enqueue_dropzone_css( $page ) {
		if ( ! FrmAppHelper::pro_is_installed() ) {
			return;
		}

		$should_avoid_loading_dropzone = 'formidable' === $page && ! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );

		if ( ! $should_avoid_loading_dropzone ) {
			wp_enqueue_style( 'formidable-dropzone' );
		}
	}

	/**
	 * The floating links are not shown on every page.
	 * They are also not shown if white labeling is being used.
	 *
	 * @since 6.8.4
	 *
	 * @return bool
	 */
	private static function should_show_floating_links() {
		if ( ! FrmAppHelper::is_formidable_branding() ) {
			return false;
		}

		$should_show = FrmAppHelper::is_formidable_admin() &&
			! FrmAppHelper::is_style_editor_page() &&
			! FrmAppHelper::is_admin_page( 'formidable-views-editor' ) &&
			! FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );

		/**
		 * Filters whether the floating links should be displayed.
		 *
		 * @since 6.25.1
		 *
		 * @param bool $should_show Whether the floating links should be shown.
		 */
		return apply_filters( 'frm_should_show_floating_links', $should_show );
	}

	/**
	 * @since 6.3.2
	 *
	 * @return void
	 */
	public static function admin_enqueue_scripts() {
		self::load_wp_admin_style();
		self::maybe_force_formidable_block_on_gutenberg_page();

		if ( FrmAppHelper::is_admin_page( 'formidable-settings' ) ) {
			wp_enqueue_style( FrmDashboardController::PAGE_SLUG, FrmAppHelper::plugin_url() . '/css/admin/dashboard.css', array(), FrmAppHelper::plugin_version() );
		}

		FrmUsageController::load_scripts();
	}

	/**
	 * Enqueue required assets for the Legacy Views editor (Views v4.x).
	 *
	 * @since 6.1.2
	 *
	 * @return void
	 */
	private static function enqueue_legacy_views_assets() {
		wp_enqueue_style( 'formidable-grids' );
		wp_enqueue_script( 'jquery-ui-draggable' );
		self::maybe_deregister_popper1();
		wp_enqueue_script( 'formidable_admin' );
		wp_add_inline_style(
			'formidable-admin',
			'
			.frm-white-body.post-type-frm_display .columns-2 {
				display: block;
				overflow: visible;
			}

			.frm-white-body.post-type-frm_display .columns-2 > div {
				overflow-y: hidden;
			}

			.frm-white-body.post-type-frm_display #titlediv #title-prompt-text {
				padding: 3px 0 0 10px;
			}

			.post-type-frm_display #field-search-input,
			.post-type-frm_display #advanced-search-input {
				flex: 1;
			}
			'
		);
		wp_enqueue_style( 'formidable-admin' );
		wp_enqueue_script( 'formidable_legacy_views', FrmAppHelper::plugin_url() . '/js/admin/legacy-views.js', array( 'jquery', 'formidable_admin' ), FrmAppHelper::plugin_version() ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
		FrmAppHelper::localize_script( 'admin' );
		self::include_info_overlay();
	}

	/**
	 * Unregister Popper if the registered version is outdated.
	 *
	 * @since 6.26
	 *
	 * @return void
	 */
	private static function maybe_deregister_popper1() {
		global $wp_scripts;

		if ( ! array_key_exists( 'popper', $wp_scripts->registered ) ) {
			return;
		}

		$popper = $wp_scripts->registered['popper'];

		if ( version_compare( $popper->ver, '2.0', '<' ) ) {
			wp_deregister_script( 'popper' );
			self::register_popper2();
		}
	}

	/**
	 * Register Popper required for Bootstrap 5.
	 *
	 * @since 6.26
	 *
	 * @return void
	 */
	private static function register_popper2() {
		if ( ! self::should_register_popper() ) {
			return;
		}
		wp_register_script( 'popper', FrmAppHelper::plugin_url() . '/js/popper.min.js', array(), '2.11.8', true );
	}

	/**
	 * Only register popper on Formidable pages.
	 * This helps to avoid popper conflicts on other plugin pages, including the WP Bakery page editor.
	 *
	 * @since 6.11.1
	 *
	 * @return bool
	 */
	private static function should_register_popper() {
		global $pagenow;

		$post_id = FrmAppHelper::simple_get( 'post', 'absint' );

		if ( 'post.php' === $pagenow && $post_id && 'frm_display' === get_post_type( $post_id ) ) {
			return true;
		}

		$post_type          = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
		$is_views_post_type = 'frm_display' === $post_type;

		if ( in_array( $pagenow, array( 'post-new.php', 'edit.php' ), true ) && $is_views_post_type ) {
			return true;
		}

		$page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );

		if ( str_starts_with( $page, 'formidable' ) ) {
			return true;
		}

		return in_array( $pagenow, array( 'term.php', 'edit-tags.php' ), true ) && FrmAppHelper::simple_get( 'taxonomy' ) === 'frm_application';
	}

	/**
	 * Automatically insert a Formidable block when loading Gutenberg when $_GET['frmForm' is set.
	 *
	 * @since 5.2
	 *
	 * @return void
	 */
	private static function maybe_force_formidable_block_on_gutenberg_page() {
		global $pagenow;

		if ( 'post.php' !== $pagenow ) {
			return;
		}

		$form_id = FrmAppHelper::simple_get( 'frmForm', 'absint' );

		if ( ! $form_id ) {
			return;
		}

		self::add_js_to_inject_gutenberg_block( 'formidable/simple-form', 'formId', $form_id );
	}

	/**
	 * @since 5.3
	 *
	 * @param string       $block_name
	 * @param string       $object_key
	 * @param array|string $object_id
	 *
	 * @return void
	 */
	public static function add_js_to_inject_gutenberg_block( $block_name, $object_key, $object_id ) {
		require FrmAppHelper::plugin_path() . '/classes/views/shared/edit-page-js.php';
	}

	/**
	 * @return void
	 */
	public static function load_lang() {
		load_plugin_textdomain( 'formidable', false, FrmAppHelper::plugin_folder() . '/languages/' );
	}

	/**
	 * Check if the styles are updated when a form is loaded on the front-end
	 *
	 * @since 3.0.1
	 *
	 * @return void
	 */
	public static function maybe_update_styles() {
		if ( self::needs_update() ) {
			self::network_upgrade_site();
		}
	}

	/**
	 * @since 3.0
	 *
	 * @return void
	 */
	public static function create_rest_routes() {
		$args = array(
			'methods'             => 'GET',
			'callback'            => 'FrmAppController::api_install',
			'permission_callback' => self::class . '::can_update_db',
		);

		register_rest_route( 'frm-admin/v1', '/install', $args );

		$args = array(
			'methods'             => 'GET',
			'callback'            => 'FrmAddonsController::install_addon_api',
			'permission_callback' => 'FrmAddonsController::can_install_addon_api',
		);

		register_rest_route( 'frm-admin/v1', '/install-addon', $args );
	}

	/**
	 * Make sure the install is only being run when we tell it to.
	 * We don't want to run manually by people calling the API.
	 *
	 * @since 4.06.02
	 *
	 * @return bool
	 */
	public static function can_update_db() {
		return get_transient( 'frm_updating_api' );
	}

	/**
	 * Run silent upgrade on each site in the network during a network upgrade.
	 * Update database settings for all sites in a network during network upgrade process.
	 *
	 * @since 2.0.1
	 *
	 * @param int $blog_id Blog ID.
	 *
	 * @return void
	 */
	public static function network_upgrade_site( $blog_id = 0 ) {
		// Flag to check if install is happening as intended.
		set_transient( 'frm_updating_api', true, MINUTE_IN_SECONDS );
		$request = new WP_REST_Request( 'GET', '/frm-admin/v1/install' );

		self::maybe_add_wp_site_health();

		if ( $blog_id ) {
			switch_to_blog( $blog_id );
			$response = rest_do_request( $request );
			restore_current_blog();
		} else {
			$response = rest_do_request( $request );
		}

		if ( $response->is_error() ) {
			// if the remove post fails, use javascript instead
			add_action( 'admin_notices', 'FrmAppController::install_js_fallback' );
		}
	}

	/**
	 * Make sure WP_Site_Health has been included because it is required when calling rest_do_request.
	 * Check first that the file exists because WP_Site_Health was only introduced in WordPress 5.2.
	 *
	 * @return void
	 */
	private static function maybe_add_wp_site_health() {
		if ( ! class_exists( 'WP_Site_Health' ) ) {
			$wp_site_health_path = ABSPATH . 'wp-admin/includes/class-wp-site-health.php';

			if ( file_exists( $wp_site_health_path ) ) {
				require_once $wp_site_health_path;
			}
		}
	}

	/**
	 * @since 3.0
	 *
	 * @return true
	 */
	public static function api_install() {
		delete_transient( 'frm_updating_api' );

		if ( self::needs_update() ) {
			$running = get_option( 'frm_install_running' );

			if ( false === $running || $running < strtotime( '-5 minutes' ) ) {
				update_option( 'frm_install_running', time(), 'no' );
				self::install();
				delete_option( 'frm_install_running' );
			}
		}

		return true;
	}

	/**
	 * Silent database upgrade (no redirect).
	 * Called via ajax request during network upgrade process.
	 *
	 * @since 2.0.1
	 *
	 * @return void
	 */
	public static function ajax_install() {
		FrmAppHelper::permission_check( 'frm_change_settings' );
		check_ajax_referer( 'frm_ajax', 'nonce' );
		self::api_install();
		wp_die();
	}

	/**
	 * @return void
	 */
	public static function install() {
		$frmdb = new FrmMigrate();
		$frmdb->upgrade();
	}

	/**
	 * @return void
	 */
	public static function uninstall() {
		FrmAppHelper::permission_check( 'administrator' );
		check_ajax_referer( 'frm_ajax', 'nonce' );

		$frmdb = new FrmMigrate();
		$frmdb->uninstall();

		// Disable the plugin and redirect after uninstall so the tables don't get added right back.
		$plugins = array( FrmAppHelper::plugin_folder() . '/formidable.php', 'formidable-pro/formidable-pro.php' );
		deactivate_plugins( $plugins, false, false );
		echo esc_url_raw( admin_url( 'plugins.php?deactivate=true' ) );

		wp_die();
	}

	/**
	 * @param array $tables
	 *
	 * @return array
	 */
	public static function drop_tables( $tables ) {
		global $wpdb;
		$tables[] = $wpdb->prefix . 'frm_fields';
		$tables[] = $wpdb->prefix . 'frm_forms';
		$tables[] = $wpdb->prefix . 'frm_items';
		$tables[] = $wpdb->prefix . 'frm_item_metas';

		return $tables;
	}

	/**
	 * @return void
	 */
	public static function deauthorize() {
		FrmAppHelper::permission_check( 'frm_change_settings' );
		check_ajax_referer( 'frm_ajax', 'nonce' );

		delete_option( 'frmpro-credentials' );
		delete_option( 'frmpro-authorized' );
		delete_site_option( 'frmpro-credentials' );
		delete_site_option( 'frmpro-authorized' );
		wp_die();
	}

	/**
	 * This is triggered when Formidable is activated.
	 *
	 * @return void
	 */
	public static function handle_activation() {
		self::maybe_activate_payment_cron();
	}

	/**
	 * The payment cron is unscheduled when Formidable is deactivated.
	 * We need to add it back again on activation if Stripe is configured.
	 *
	 * @since 6.5
	 *
	 * @return void
	 */
	private static function maybe_activate_payment_cron() {
		if ( ! FrmStrpLiteConnectHelper::stripe_connect_is_setup() ) {
			return;
		}

		FrmTransLiteAppController::maybe_schedule_cron();
	}

	/**
	 * @param string $text
	 *
	 * @return string
	 */
	public static function set_footer_text( $text ) {
		if ( FrmAppHelper::is_formidable_admin() ) {
			$text = '';
		}

		return $text;
	}

	/**
	 * Add admin footer links.
	 *
	 * @since 6.4.1
	 *
	 * @return void
	 */
	public static function add_admin_footer_links() {
		FrmFormsController::include_device_too_small_message();

		if ( self::should_show_footer_links() ) {
			include FrmAppHelper::plugin_path() . '/classes/views/shared/admin-footer-links.php';
		}
	}

	/**
	 * Check if the footer links should be shown.
	 *
	 * @since 6.7
	 *
	 * @return bool
	 */
	private static function should_show_footer_links() {
		$post_type          = FrmAppHelper::simple_get( 'post_type', 'sanitize_title' );
		$is_formidable_page = FrmAppHelper::is_formidable_admin() || 'frm_logs' === $post_type;
		$show_footer_links  = $is_formidable_page;

		if ( FrmAppHelper::is_full_screen() || ! FrmAppHelper::is_formidable_branding() ) {
			$show_footer_links = false;
		}

		/**
		 * Filter whether to show the Formidable footer links.
		 *
		 * @since 6.7
		 *
		 * @param bool $show_footer_links
		 *
		 * @return bool
		 */
		return apply_filters( 'frm_show_footer_links', $show_footer_links );
	}

	/**
	 * Show an error modal and terminate the script execution.
	 *
	 * @since 6.7
	 *
	 * @param array $error_args Arguments that control the behavior of the error modal.
	 *
	 * @return void
	 */
	public static function show_error_modal( $error_args ) {
		add_filter( 'frm_show_footer_links', '__return_false' );

		$defaults = array(
			'title'            => '',
			'body'             => '',
			'cancel_url'       => '',
			'cancel_classes'   => '',
			'continue_url'     => '',
			'continue_classes' => '',
			'icon'             => 'frm_lock_simple',
		);

		$error_args = wp_parse_args( $error_args, $defaults );

		if ( ! isset( $error_args['cancel_text'] ) && ! empty( $error_args['cancel_url'] ) ) {
			$error_args['cancel_text'] = __( 'Cancel', 'formidable' );
		}

		if ( ! isset( $error_args['continue_text'] ) && ! empty( $error_args['continue_url'] ) ) {
			$error_args['continue_text'] = __( 'Continue', 'formidable' );
		}

		include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/error-modal.php';
	}

	/**
	 * Handles Floating Links' scripts and styles enqueueing.
	 *
	 * @since 6.4
	 *
	 * @param string $plugin_url URL of the plugin.
	 * @param string $version Current version of the plugin.
	 *
	 * @return void
	 */
	private static function enqueue_floating_links( $plugin_url, $version ) {
		if ( ! $plugin_url || ! $version ) {
			// If any required parameters are missing, exit early.
			return;
		}

		// Enqueue the Floating Links styles.
		wp_enqueue_style( 's11-floating-links', $plugin_url . '/css/packages/s11-floating-links.css', array(), $version );

		// Enqueue the Floating Links script.
		wp_enqueue_script( 's11-floating-links', $plugin_url . '/js/packages/floating-links/s11-floating-links.js', array( 'formidable_admin' ), $version, true );

		// Enqueue the config script.
		wp_enqueue_script( 's11-floating-links-config', $plugin_url . '/js/packages/floating-links/config.js', array( 'wp-i18n' ), $version, true );

		if ( function_exists( 'wp_set_script_translations' ) ) {
			wp_set_script_translations( 's11-floating-links-config', 's11-' );
		}

		$upgrade_utm         = array(
			'campaign' => 'floating-links',
			'content'  => 'floating-links-upgrade',
		);
		$docs_utm            = array(
			'campaign' => 'floating-links',
			'content'  => 'floating-links-docs',
		);
		$floating_links_data = array(
			'proIsInstalled'   => FrmAppHelper::pro_is_installed(),
			'upgradeUrl'       => FrmAppHelper::admin_upgrade_link( $upgrade_utm ),
			'documentationUrl' => FrmAppHelper::admin_upgrade_link( $docs_utm, 'knowledgebase/' ),
		);
		wp_localize_script( 's11-floating-links-config', 's11FloatingLinksData', $floating_links_data );

		/**
		 * Prompt Pro to load additional floating links scripts.
		 * This is used to include images in the Inbox SlideIn when Pro is active.
		 *
		 * @since 6.8.4
		 */
		do_action( 'frm_enqueue_floating_links' );
	}

	/**
	 * Check if we are in our admin pages.
	 *
	 * @return bool
	 */
	private static function in_our_pages() {
		global $current_screen, $pagenow;

		if ( FrmAppHelper::is_formidable_admin() ) {
			return true;
		}

		if ( ! empty( $current_screen->post_type ) && 'frm_logs' === $current_screen->post_type ) {
			return true;
		}

		return in_array( $pagenow, array( 'term.php', 'edit-tags.php' ), true ) && 'frm_application' === FrmAppHelper::simple_get( 'taxonomy' );
	}

	/**
	 * Handles actions related to the current screen.
	 *
	 * @since 6.19
	 *
	 * @return void
	 */
	public static function handle_current_screen() {
		if ( ! self::in_our_pages() ) {
			return;
		}

		self::filter_admin_notices();
		self::remember_custom_sort();
	}

	/**
	 * Hide all third-parties admin notices only in our admin pages.
	 *
	 * @return void
	 */
	public static function filter_admin_notices() {
		$actions = array(
			'admin_notices',
			'network_admin_notices',
			'user_admin_notices',
			'all_admin_notices',
		);

		global $wp_filter;

		foreach ( $actions as $action ) {
			if ( empty( $wp_filter[ $action ]->callbacks ) ) {
				continue;
			}

			foreach ( $wp_filter[ $action ]->callbacks as $priority => $callbacks ) {
				foreach ( $callbacks as $callback_name => $callback ) {
					if ( self::is_our_callback_string( $callback_name ) || self::is_our_callback_array( $callback ) ) {
						continue;
					}
					unset( $wp_filter[ $action ]->callbacks[ $priority ][ $callback_name ] );
				}
			}
		}
	}

	/**
	 * Remembers and applies user-specific sorting preferences.
	 *
	 * @return void
	 */
	private static function remember_custom_sort() {
		$meta_key = self::get_sort_pref_user_meta_key();

		if ( false === $meta_key ) {
			return;
		}

		$is_form_list  = FrmAppHelper::is_admin_list_page();
		$is_entry_list = FrmAppHelper::is_admin_list_page( 'formidable-entries' );

		if ( ! $is_form_list && ! $is_entry_list ) {
			return;
		}

		$orderby = FrmAppHelper::get_param( 'orderby' );

		if ( ! $orderby ) {
			return;
		}

		$user_id       = get_current_user_id();
		$order         = FrmAppHelper::get_param( 'order' );
		$new_sort      = array(
			'orderby' => $orderby,
			'order'   => $order,
		);
		$previous_meta = get_user_meta( $user_id, $meta_key, true );
		$current_sort  = $previous_meta;
		$form_id       = $is_entry_list ? FrmAppHelper::simple_get( 'form', 'absint' ) : 0;

		if ( is_array( $current_sort ) && $form_id && is_int( $form_id ) && isset( $current_sort[ $form_id ] ) ) {
			$current_sort = $current_sort[ $form_id ];
		}

		if ( $new_sort !== $current_sort ) {
			$new_meta = $new_sort;

			if ( $is_entry_list && $form_id && is_int( $form_id ) ) {
				// Index meta by form ID.
				$temp_meta             = is_array( $previous_meta ) ? $previous_meta : array();
				$temp_meta[ $form_id ] = $new_meta;
				$new_meta              = $temp_meta;
				unset( $temp_meta );
			}

			update_user_meta( $user_id, $meta_key, $new_meta );
		}
	}

	/**
	 * Retrieve and apply any saved sorting preferences for the current screen.
	 *
	 * @since 6.19
	 *
	 * @param string &$orderby Reference to the current 'orderby' parameter.
	 * @param string &$order   Reference to the current 'order' parameter.
	 *
	 * @return void
	 */
	public static function apply_saved_sort_preference( &$orderby, &$order ) {
		$meta_key = self::get_sort_pref_user_meta_key();

		if ( false === $meta_key ) {
			return;
		}

		$user_id             = get_current_user_id();
		$preferred_list_sort = get_user_meta( $user_id, $meta_key, true );
		$form_id             = FrmAppHelper::simple_get( 'form', 'absint' );

		if ( is_array( $preferred_list_sort ) && $form_id && is_int( $form_id ) && isset( $preferred_list_sort[ $form_id ] ) ) {
			$preferred_list_sort = $preferred_list_sort[ $form_id ];
		}

		if ( is_array( $preferred_list_sort ) && ! empty( $preferred_list_sort['orderby'] ) ) {
			$orderby = $preferred_list_sort['orderby'];

			if ( ! empty( $preferred_list_sort['order'] ) ) {
				$order = $preferred_list_sort['order'];
			}
		}
	}

	/**
	 * Get a simple user meta key that only includes the screen ID.
	 *
	 * @since 6.25.1
	 *
	 * @return false|string
	 */
	private static function get_sort_pref_user_meta_key() {
		if ( ! function_exists( 'get_current_screen' ) ) {
			return false;
		}

		$screen = get_current_screen();
		return $screen ? 'frm_preferred_list_sort_' . $screen->id : false;
	}

	/**
	 * Validate that the callback name is ours not from third-party.
	 *
	 * @param string $callback_name WordPress callback name.
	 *
	 * @return bool
	 */
	private static function is_our_callback_string( $callback_name ) {
		return 0 === stripos( $callback_name, 'frm' );
	}

	/**
	 * Validate that the callback array is ours not from third-party.
	 *
	 * @param array $callback WordPress callback array.
	 *
	 * @return bool
	 */
	private static function is_our_callback_array( $callback ) {
		return ! empty( $callback['function'] ) &&
			is_array( $callback['function'] ) &&
			! empty( $callback['function'][0] ) &&
			self::is_our_callback_string( is_object( $callback['function'][0] ) ? get_class( $callback['function'][0] ) : $callback['function'][0] );
	}

	/**
	 * In some cases, the DB tables may fail to install.
	 * This function tries to add them again when the user clicks the link to try again
	 * from the given inbox notice.
	 *
	 * @since 6.19
	 */
	private static function add_missing_tables() {
		FrmAppHelper::permission_check( 'frm_view_forms' );

		$error = FrmInbox::check_for_error();

		if ( ! $error || 'failed-to-create-tables' !== $error['key'] ) {
			// Confirm the inbox item with this CTA exists.
			wp_safe_redirect( admin_url( 'admin.php?page=formidable' ) );
			exit;
		}

		global $wpdb;
		$exists = $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->prefix . 'frm_forms' ) );

		if ( $exists ) {
			// Exit early if the table already exists.
			wp_safe_redirect( admin_url( 'admin.php?page=formidable' ) );
			exit;
		}

		delete_option( 'frm_db_version' );
		wp_safe_redirect( admin_url( 'admin.php?page=formidable' ) );
		exit;
	}

	/**
	 * Handles the small screen proceed action.
	 *
	 * @since 6.21
	 *
	 * @return void
	 */
	public static function small_screen_proceed() {
		FrmAppHelper::permission_check( 'frm_view_forms' );
		check_ajax_referer( 'frm_ajax', 'nonce' );
		update_user_option( get_current_user_id(), 'frm_ignore_small_screen_warning', true );
		wp_send_json_success();
	}
}
