enabled() ) { // Allows locally defined JETPACK_DEV_DEBUG constant to override filter. if ( ! defined( 'JETPACK_DEV_DEBUG' ) ) { // Keep jetpack from attempting external requests. add_filter( 'jetpack_development_mode', '__return_true', 9999 ); } // Prevent BuddyPress from falling back to Gravatar avatars. add_filter( 'bp_core_fetch_avatar_no_grav', '__return_true' ); // Disable automatic updater updates. add_filter( 'automatic_updater_disabled', '__return_true' ); // Tell WordPress we are on a version control system to add additional blocks. add_filter( 'automatic_updates_is_vcs_checkout', '__return_true' ); // Disable translation updates. add_filter( 'auto_update_translation', '__return_false' ); // Disable minor core updates. add_filter( 'allow_minor_auto_core_updates', '__return_false' ); // Disable major core updates. add_filter( 'allow_major_auto_core_updates', '__return_false' ); // Disable dev core updates. add_filter( 'allow_dev_auto_core_updates', '__return_false' ); // Disable overall core updates. add_filter( 'auto_update_core', '__return_false' ); add_filter( 'wp_auto_update_core', '__return_false' ); // Disable automatic plugin and theme updates (used by WP to force push security fixes). add_filter( 'auto_update_plugin', '__return_false' ); add_filter( 'auto_update_theme', '__return_false' ); // Disable debug emails (used by core for rollback alerts in automatic update deployment). add_filter( 'automatic_updates_send_debug_email', '__return_false' ); // Disable update emails (for when we push the new WordPress versions manually) as well // as the notification there is a new version emails. add_filter( 'auto_core_update_send_email', '__return_false' ); add_filter( 'send_core_update_notification_email', '__return_false' ); add_filter( 'automatic_updates_send_debug_email ', '__return_false', 1 ); // Get rid of the version number in the footer. add_filter( 'update_footer', '__return_empty_string', 11 ); // Filter out the pre core option. add_filter( 'pre_option_update_core', '__return_null' ); // Remove some actions. remove_action( 'admin_init', 'wp_plugin_update_rows' ); remove_action( 'admin_init', 'wp_theme_update_rows' ); remove_action( 'admin_notices', 'maintenance_nag' ); remove_action( 'init', 'wp_schedule_update_checks' ); // Add back the upload tab. add_action( 'install_themes_upload', 'install_themes_upload', 10, 0 ); // Define core contants for more protection. if ( ! defined( 'AUTOMATIC_UPDATER_DISABLED' ) ) { define( 'AUTOMATIC_UPDATER_DISABLED', true ); } if ( ! defined( 'WP_AUTO_UPDATE_CORE' ) ) { define( 'WP_AUTO_UPDATE_CORE', false ); } } } /** * If an instance exists, this returns it. If not, it creates one and * returns it. * * @return $instance */ public static function getInstance() { if ( ! self::$instance ) { self::$instance = new self; } return self::$instance; } /** * Load our textdomain for localization. * * @return void */ public function textdomain() { load_plugin_textdomain( 'airplane-mode', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); } /** * Set our initial airplane mode setting to 'on' on activation. */ public function create_setting() { add_site_option( 'airplane-mode', 'on' ); set_transient( 'wporg_theme_feature_list', array(), 999999999999 ); } /** * Remove our setting on plugin deactivation. */ public function remove_setting() { delete_option( 'airplane-mode' ); delete_site_option( 'airplane-mode' ); delete_transient( 'wporg_theme_feature_list' ); } /** * Helper function to check the current status. * * @return bool True if status is 'on'; false if not. */ public function enabled() { // Bail if CLI. if ( defined( 'WP_CLI' ) and WP_CLI ) { return false; } // Pull our status from the options table. $option = get_site_option( 'airplane-mode' ); // Backup check for regular options table. if ( false === $option ) { $option = get_option( 'airplane-mode' ); } // Return the option flag. return 'on' === $option; } /** * Check the URL of a stylesheet and remove any that are not on the local URL. * * @param string $source The source URL of the CSS sheet. * * @return string $source The same URL, or null. */ public function block_style_load( $source ) { // Bail if disabled. if ( ! $this->enabled() ) { return $source; } // Parse the URL being passed to pull out the host. $parsed = parse_url( $source, PHP_URL_HOST ); // First run the filter to allow a source host to get through. if ( false === apply_filters( 'airplane_mode_parse_style', true, $parsed ) ) { return $source; } // If we don't share the same URL as the site itself, return null. Otherwise return the URL. return isset( $parsed ) && false === strpos( home_url(), $parsed ) ? new Airplane_Mode_WP_Error( 'airplane_mode_enabled', __( 'Airplane Mode blocked style', 'airplane-mode' ), array( 'return' => '', 'src' => $source, ) ) : $source; } /** * Check the URL of a JS file and remove any that are not on the local URL. * * @param string $source The source URL of the JS file. * * @return string $source The same URL, or null. */ public function block_script_load( $source ) { // Bail if disabled. if ( ! $this->enabled() ) { return $source; } // Parse the URL being passed to pull out the host. $parsed = parse_url( $source, PHP_URL_HOST ); // First run the filter to allow a source host to get through. if ( false === apply_filters( 'airplane_mode_parse_script', true, $parsed ) ) { return $source; } // If we don't share the same URL as the site itself, return null. Otherwise return the URL. return isset( $parsed ) && false === strpos( home_url(), $parsed ) ? new Airplane_Mode_WP_Error( 'airplane_mode_enabled', __( 'Airplane Mode blocked script', 'airplane-mode' ), array( 'return' => '', 'src' => $source, ) ) : $source; } /** * Use our existing filter to check for local assets. * * @param boolean $block Whether to block the specific asset. Defaults to 'true'. * @param array $parsed The URL of the asset, parsed. * * @return boolean */ public function bypass_asset_block( $block, $parsed ) { // Create an array of the approved local domains. $local = apply_filters( 'airplane_mode_local_hosts', array( 'localhost', '127.0.0.1' ) ); // If our parsed URL host is in that array, return false. Otherwise, return our blocking choice. return ! empty( $local ) && in_array( $parsed, $local ) ? false : $block; } /** * Block oEmbeds from displaying. * * @param string $html The embed HTML. * @param string $url The attempted embed URL. * @param array $attr An array of shortcode attributes. * @param int $post_ID Post ID. * * @return string */ public function block_oembed_html( $html, $url, $attr, $post_ID ) { return $this->enabled() ? sprintf( '

%s

', sprintf( __( 'Airplane Mode is enabled. oEmbed blocked for %1$s.', 'airplane-mode' ), esc_url( $url ) ) ) : $html; } /** * Add body class to front-end pages and login based on plugin status. * * @param array $classes The existing array of body classes. * * @return array $classes The updated array of body classes. */ public function body_class( $classes ) { // Add the class based on the current status. $classes[] = $this->enabled() ? 'airplane-mode-enabled' : 'airplane-mode-disabled'; // Also add in the margin setup for Query Monitor because I'm a perfectionist. if ( ! class_exists( 'QueryMonitor' ) || defined( 'QM_DISABLED' ) && QM_DISABLED ) { $classes[] = 'airplane-mode-no-qm'; } // Return our array of classes. return $classes; } /** * Add body class to admin pages based on plugin status. * * @param string $classes The existing space-separated list of CSS classes. * * @return string $classes The updated space-separated list of CSS classes. */ public function admin_body_class( $classes ) { // First add the standard set of classes based on status. $classes .= $this->enabled() ? ' airplane-mode-enabled' : ' airplane-mode-disabled'; // Also add in the margin setup for Query Monitor because I'm a perfectionist. if ( ! class_exists( 'QueryMonitor' ) || defined( 'QM_DISABLED' ) && QM_DISABLED ) { $classes .= ' airplane-mode-no-qm'; } // Return our string of classes. return $classes; } /** * Remove menu items for updates from a standard WP install. * * @return null */ public function admin_menu_items() { // Bail if disabled, or on a multisite. if ( ! $this->enabled() || is_multisite() ) { return; } // Remove our items. remove_submenu_page( 'index.php', 'update-core.php' ); } /** * Remove menu items for updates from a multisite instance. * * @return null */ public function ms_admin_menu_items() { // Bail if disabled or not on our network admin. if ( ! $this->enabled() || ! is_network_admin() ) { return; } // Remove the items. remove_submenu_page( 'index.php', 'upgrade.php' ); } /** * Replace all instances of gravatar with a local image file * to remove the call to remote service. * * @param string $avatar Image tag for the user's avatar. * @param int|object|string $id_or_email A user ID, email address, or comment object. * @param int $size Square avatar width and height in pixels to retrieve. * @param string $default URL to a default image to use if no avatar is available. * @param string $alt Alternative text to use in the avatar image tag. * * @return string `` tag for the user's avatar. */ public function replace_gravatar( $avatar, $id_or_email, $size, $default, $alt ) { // Bail if disabled. if ( ! $this->enabled() ) { return $avatar; } // Swap out the file for a base64 encoded image. $image = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; $avatar = "{$alt}"; // Return the avatar. return $avatar; } /** * Remove avatar images from the default avatar list. * * @param string $avatar_list List of default avatars. * * @return string Updated list with images removed. */ public function default_avatar( $avatar_list ) { // Bail if disabled. if ( ! $this->enabled() ) { return $avatar_list; } // Remove images. $avatar_list = preg_replace( '|]+)> |i', '', $avatar_list ); // Send back the list. return $avatar_list; } /** * Disable all the HTTP requests being made with the action * happening before the status check so others can allow certain * items as desired. * * @param bool|array|WP_Error $status Whether to preempt an HTTP request return. Default false. * @param array $args HTTP request arguments. * @param string $url The request URL. * * @return bool|array|WP_Error A WP_Error object if Airplane Mode is enabled. Original $status if not. */ public function disable_http_reqs( $status = false, $args = array(), $url = '' ) { // Pass our data to the action to allow a bypass. do_action( 'airplane_mode_http_args', $status, $args, $url ); if ( ! $this->enabled() ) { return $status; } $url_host = parse_url( $url, PHP_URL_HOST ); // Allow the request to pass through if the URL host matches the site's host. if ( $url_host && parse_url( home_url(), PHP_URL_HOST ) === $url_host ) { // But allow this to be disabled via a filter. if ( apply_filters( 'airplane_mode_allow_local_bypass', true, $url, $args ) ) { return $status; } } // Allow certain HTTP API requests to pass through via a filter. if ( apply_filters( 'airplane_mode_allow_http_api_request', false, $url, $args, $url_host ) ) { return $status; } // Disable the http requests if enabled. return new WP_Error( 'airplane_mode_enabled', __( 'Airplane Mode is enabled', 'airplane-mode' ) ); } /** * Load our small CSS file for the toggle switch. */ public function toggle_css() { // Don't display CSS on the front-end if the admin bar is not loading. if ( ! is_admin() && ! is_admin_bar_showing() ) { return; } // Set a suffix for loading the minified or normal. $file = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? 'airplane-mode.css' : 'airplane-mode.min.css'; // Set a version for browser caching. $vers = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? time() : AIRMDE_VER; // Load the CSS file itself. wp_enqueue_style( 'airplane-mode', plugins_url( '/lib/css/' . $file, __FILE__ ), array(), $vers, 'all' ); } /** * Sets the mode. * * @param string $mode Desired mode ('on' or 'off'). * * @return bool Whether the setting changed. */ public function set_mode( $mode = 'on' ) { // Check what mode we're currently in, with "on" as a fallback. if ( ! in_array( $mode, array( 'on', 'off' ) ) ) { $mode = 'on'; } // Update the setting. $return = update_site_option( 'airplane-mode', $mode ); // Fire action to allow for functions to run on status change. do_action( 'airplane_mode_status_change', $mode ); // And return the status we just set. return $return; } /** * Enables airplane mode. * * @return bool Whether the setting changed. */ public function enable() { return self::set_mode( 'on' ); } /** * Disables airplane mode. * * @return bool Whether the setting changed. */ public function disable() { return self::set_mode( 'off' ); } /** * Check the user action from the toggle switch to set the option * to 'on' or 'off'. * * @return void If any of the sanity checks fail and we bail early. */ public function toggle_check() { // Bail if current user doesn't have cap. if ( ! current_user_can( 'manage_options' ) ) { return; } // Set a sanitized variable of our potential nonce and request. $nonce = isset( $_GET['airmde_nonce'] ) ? sanitize_key( $_GET['airmde_nonce'] ) : ''; $switch = isset( $_REQUEST['airplane-mode'] ) ? sanitize_key( $_REQUEST['airplane-mode'] ) : ''; // Check for our nonce. if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'airmde_nonce' ) ) { return; } // Now check for our query string. if ( empty( $switch ) || ! in_array( $switch, array( 'on', 'off' ) ) ) { return; } // Delete old per-site option. delete_option( 'airplane-mode' ); // Set our mode based on the toggle action. self::set_mode( $switch ); // And go about our business. wp_redirect( self::get_redirect() ); exit; } /** * Fetch the URL to redirect to after toggling Airplane Mode. * * @return string The URL to redirect to. */ protected static function get_redirect() { // Return the args for the actual redirect. $redirect = remove_query_arg( array( 'airplane-mode', 'airmde_nonce', 'user_switched', 'switched_off', 'switched_back', 'message', 'update', 'updated', 'settings-updated', 'saved', 'activated', 'activate', 'deactivate', 'enabled', 'disabled', 'locked', 'skipped', 'deleted', 'trashed', 'untrashed', 'force-check', ) ); // Redirect away from the update core page. $redirect = str_replace( 'update-core.php', '', $redirect ); // And return the redirect. return apply_filters( 'airplane_mode_redirect_url', $redirect ); } /** * Add our quick toggle to the admin bar to enable / disable. * * @param WP_Admin_Bar $wp_admin_bar The admin bar object. * * @return void if current user can't manage options and we bail early. */ public function admin_bar_toggle( WP_Admin_Bar $wp_admin_bar ) { // Bail if current user doesn't have cap. if ( ! current_user_can( 'manage_options' ) ) { return; } // Get the current status. $status = $this->enabled(); // Set a title message (translatable). $title = $status ? __( 'Airplane Mode is enabled.', 'airplane-mode' ) : __( 'Airplane Mode is disabled.', 'airplane-mode' ); // Set our toggle variable parameter (in reverse since we want the opposite action). $toggle = $status ? 'off' : 'on'; // Set my HTTP request count label to a blank string for now. $label = ''; // Get and display the HTTP count when Query Monitor isn't active. if ( ! class_exists( 'QueryMonitor' ) || defined( 'QM_DISABLED' ) && QM_DISABLED ) { // Pull my HTTP count. $count = ! empty( $this->http_count ) ? number_format_i18n( $this->http_count ) : 0; $count_label = sprintf( _n( 'There was %s HTTP request.', 'There were %s HTTP requests.', $count, 'airplane-mode' ), $count ); // Build the markup for my label. $label = ''; $label .= '' . esc_html( $count_label ) . ''; // Amend the tooltip title with the count. $title .= ' ' . $count_label; } // Get our link with the status parameter. $link = wp_nonce_url( add_query_arg( 'airplane-mode', $toggle ), 'airmde_nonce', 'airmde_nonce' ); // Now add the admin bar link. $wp_admin_bar->add_node( array( 'id' => 'airplane-mode-toggle', 'title' => '' . $label, 'href' => esc_url( $link ), 'position' => 0, 'meta' => array( 'title' => $title, ), ) ); } /** * Filter a user's meta capabilities to prevent auto-updates from being attempted. * * @param array $caps Returns the user's actual capabilities. * @param string $cap Capability name. * * @return array The user's filtered capabilities. */ public function prevent_auto_updates( $caps, $cap ) { // Check for being enabled and look for specific cap requirements. if ( $this->enabled() && in_array( $cap, array( 'update_plugins', 'update_themes', 'update_core' ) ) ) { $caps[] = 'do_not_allow'; } // Send back the data array. return $caps; } /** * Check the new status after airplane mode has been enabled or * disabled and purge related transients. * * @param boolean $force Whether to force the purge. * * @return void */ public function purge_transients( $force = false ) { // First check for the filter to avoid this action overall. if ( empty( $force ) && false === $clear = apply_filters( 'airplane_mode_purge_transients', true ) ) { return; } // Purge the transients related to updates when disabled or the force is called. if ( ! $this->enabled() || ! empty( $force ) ) { delete_site_transient( 'update_core' ); delete_site_transient( 'update_plugins' ); delete_site_transient( 'update_themes' ); delete_site_transient( 'wporg_theme_feature_list' ); } } /** * Remove all the various places WP does the update checks. As you can see there are a lot of them. * * @return null */ public function remove_update_crons() { // Bail if disabled. if ( ! $this->enabled() ) { return; } // Do a quick check to make sure we can remove things. if ( ! function_exists( 'remove_action' ) ) { return; } // Disable Theme Updates. remove_action( 'load-update-core.php', 'wp_update_themes' ); remove_action( 'load-themes.php', 'wp_update_themes' ); remove_action( 'load-update.php', 'wp_update_themes' ); remove_action( 'wp_update_themes', 'wp_update_themes' ); remove_action( 'admin_init', '_maybe_update_themes' ); // Disable Plugin Updates. remove_action( 'load-update-core.php', 'wp_update_plugins' ); remove_action( 'load-plugins.php', 'wp_update_plugins' ); remove_action( 'load-update.php', 'wp_update_plugins' ); remove_action( 'wp_update_plugins', 'wp_update_plugins' ); remove_action( 'admin_init', '_maybe_update_plugins' ); // Disable Core updates // Don't look for WordPress updates. Seriously! remove_action( 'wp_version_check', 'wp_version_check' ); remove_action( 'admin_init', '_maybe_update_core' ); // Not even maybe. remove_action( 'wp_maybe_auto_update', 'wp_maybe_auto_update' ); remove_action( 'admin_init', 'wp_maybe_auto_update' ); remove_action( 'admin_init', 'wp_auto_update_core' ); // Don't forget when the language packs do it. remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); remove_action( 'upgrader_process_complete', 'wp_version_check' ); remove_action( 'upgrader_process_complete', 'wp_update_plugins' ); remove_action( 'upgrader_process_complete', 'wp_update_themes' ); } /** * Remove all the various schedule hooks for themes, plugins, etc. * * @return null */ public function remove_schedule_hook() { // Bail if disabled. if ( ! $this->enabled() ) { return; } // Clear all my hooks. wp_clear_scheduled_hook( 'wp_update_themes' ); wp_clear_scheduled_hook( 'wp_update_plugins' ); wp_clear_scheduled_hook( 'wp_version_check' ); wp_clear_scheduled_hook( 'wp_maybe_auto_update' ); } /** * Override the API call made for pulling themes from the .org repo. * * @param false|object|array $override Whether to override the WordPress.org Themes API. Default false. * @param string $action Requested action. Likely values are 'theme_information', * 'feature_list', or 'query_themes'. * @param object $args Arguments used to query for installer pages from the Themes API. * * @return bool True if enabled, otherwise the existng value. */ public function bypass_theme_api_call( $override, $action, $args ) { // Bail if disabled. if ( ! $this->enabled() ) { return $override; } // Return false on feature list to avoid the API call. return ! empty( $action ) && 'feature_list' === $action ? true : $override; } /** * Hijack the expected themes API result. * * @param array|object|WP_Error $res WordPress.org Themes API response. * @param string $action Requested action. Likely values are 'theme_information', * 'feature_list', or 'query_themes'. * @param object $args Arguments used to query for installer pages from the WordPress.org Themes API. * * @return bool An empty array if enabled, otherwise the existng result. */ public function bypass_theme_api_result( $res, $action, $args ) { // Bail if disabled. if ( ! $this->enabled() ) { return $res; } // Return false on feature list to avoid the API call. return ! empty( $action ) && in_array( $action, array( 'feature_list', 'query_themes' ) ) ? array() : $res; } /** * Always send back that the latest version of WordPress is the one we're running * * @return object the modified output with our information */ public function last_checked_core() { // Bail if disabled. if ( ! $this->enabled() ) { return false; } // Call the global WP version. global $wp_version; // Return our object. return (object) array( 'last_checked' => time(), 'updates' => array(), 'version_checked' => $wp_version, ); } /** * Always send back that the latest version of our theme is the one we're running * * @return object the modified output with our information */ public function last_checked_themes() { // Bail if disabled. if ( ! $this->enabled() ) { return false; } // Call the global WP version. global $wp_version; // Set a blank data array. $data = array(); // Build my theme data array. foreach ( wp_get_themes() as $theme ) { $data[ $theme->get_stylesheet() ] = $theme->get( 'Version' ); } // Return our object. return (object) array( 'last_checked' => time(), 'updates' => array(), 'version_checked' => $wp_version, 'checked' => $data, ); } /** * Always send back that the latest version of our plugins are the one we're running * * @return object the modified output with our information */ public function last_checked_plugins() { // Bail if disabled. if ( ! $this->enabled() ) { return false; } // Call the global WP version. global $wp_version; // Set a blank data array. $data = array(); // Add our plugin file if we don't have it. if ( ! function_exists( 'get_plugins' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } // Build my plugin data array. foreach ( get_plugins() as $file => $pl ) { $data[ $file ] = $pl['Version']; } // Return our object. return (object) array( 'last_checked' => time(), 'updates' => array(), 'version_checked' => $wp_version, 'checked' => $data, ); } /** * Filter for languages list transient. Returns locally available translations * to avoid request into wp.org translation API. * * @param mixed $translations Translation data returned from transient API. * * @return array List of available languages. */ public function available_translations( $translations ) { // Bail if disabled. if ( ! $this->enabled() ) { return $translations; } /** * If transient still contains list of languages just use those. * Otherwise fallback to mimicked data which we create here. */ if ( $translations && ! empty( $translations ) ) { return $translations; } else { $installed_languages = get_available_languages(); return $this->get_offline_languages( $installed_languages ); } } /** * Returns list of languages installed locally with full mimicked meta data. * * @param array $installed_languages List of locally available languages. * * @return array List of available languages in offline mode. */ private function get_offline_languages( $installed_languages ) { // This is list of languages which are available from translations API. $offline_languages = $this->get_offline_translation_information(); // Call the global WP version. global $wp_version; // Tell WordPress that all translations are recent even though they can be old. $date = date_i18n( 'Y-m-d H:is' , time() ); // Set an empty array of the available languages. $available_languages = array(); // Loop through our installed languages. foreach ( $installed_languages as $lang ) { // Try to mimick the data that WordPress puts into 'available_translations' transient. $settings = array( 'language' => $lang, 'iso' => array( $lang ), 'version' => $wp_version, 'updated' => $date, 'strings' => array( 'continue' => __( 'Continue' ), ), 'package' => "https://downloads.wordpress.org/translation/core/{$wp_version}/{$lang}.zip", ); // Combine the mimicked data with data we have stored in $offline_languages to give realistic output. if ( isset( $offline_languages[ $lang ] ) ) { $available_languages[ $lang ] = array_merge( $settings, $offline_languages[ $lang ] ); } } // And return our language sets. return $available_languages; } /** * We can't use wp_get_available_translations() offine. * This function tries to return something similiar. * * @return array List of wordpress language meta data. */ private function get_offline_translation_information() { // Build out the list of languages to use. $languages = array( 'af' => array( 'english_name' => 'Afrikaans', 'native_name' => 'Afrikaans' ), 'ar' => array( 'english_name' => 'Arabic', 'native_name' => 'العربية' ), 'ary' => array( 'english_name' => 'Moroccan Arabic', 'native_name' => 'العربية المغربية' ), 'as' => array( 'english_name' => 'Assamese', 'native_name' => 'অসমীয়া' ), 'az' => array( 'english_name' => 'Azerbaijani', 'native_name' => 'Azərbaycan dili' ), 'azb' => array( 'english_name' => 'South Azerbaijani', 'native_name' => 'گؤنئی آذربایجان' ), 'bel' => array( 'english_name' => 'Belarusian', 'native_name' => 'Беларуская мова' ), 'bg_BG' => array( 'english_name' => 'Bulgarian', 'native_name' => 'Български' ), 'bn_BD' => array( 'english_name' => 'Bengali', 'native_name' => 'বাংলা' ), 'bo' => array( 'english_name' => 'Tibetan', 'native_name' => 'བོད་ཡིག' ), 'bs_BA' => array( 'english_name' => 'Bosnian', 'native_name' => 'Bosanski' ), 'ca' => array( 'english_name' => 'Catalan', 'native_name' => 'Català' ), 'ceb' => array( 'english_name' => 'Cebuano', 'native_name' => 'Cebuano' ), 'ckb' => array( 'english_name' => 'Kurdish (Sorani)', 'native_name' => 'كوردی‎' ), 'cs_CZ' => array( 'english_name' => 'Czech', 'native_name' => 'Čeština‎' ), 'cy' => array( 'english_name' => 'Welsh', 'native_name' => 'Cymraeg' ), 'da_DK' => array( 'english_name' => 'Danish', 'native_name' => 'Dansk' ), 'de_DE_formal' => array( 'english_name' => 'German (Formal)', 'native_name' => 'Deutsch (Sie)' ), 'de_DE' => array( 'english_name' => 'German', 'native_name' => 'Deutsch' ), 'de_CH_informal' => array( 'english_name' => 'German (Switzerland, Informal)', 'native_name' => 'Deutsch (Schweiz, Du)' ), 'de_CH' => array( 'english_name' => 'German (Switzerland)', 'native_name' => 'Deutsch (Schweiz)' ), 'dzo' => array( 'english_name' => 'Dzongkha', 'native_name' => 'རྫོང་ཁ' ), 'el' => array( 'english_name' => 'Greek', 'native_name' => 'Ελληνικά' ), 'en_CA' => array( 'english_name' => 'English (Canada)', 'native_name' => 'English (Canada)' ), 'en_ZA' => array( 'english_name' => 'English (South Africa)', 'native_name' => 'English (South Africa)' ), 'en_AU' => array( 'english_name' => 'English (Australia)', 'native_name' => 'English (Australia)' ), 'en_NZ' => array( 'english_name' => 'English (New Zealand)', 'native_name' => 'English (New Zealand)' ), 'en_GB' => array( 'english_name' => 'English (UK)', 'native_name' => 'English (UK)' ), 'eo' => array( 'english_name' => 'Esperanto', 'native_name' => 'Esperanto' ), 'es_CL' => array( 'english_name' => 'Spanish (Chile)', 'native_name' => 'Español de Chile' ), 'es_AR' => array( 'english_name' => 'Spanish (Argentina)', 'native_name' => 'Español de Argentina' ), 'es_PE' => array( 'english_name' => 'Spanish (Peru)', 'native_name' => 'Español de Perú' ), 'es_MX' => array( 'english_name' => 'Spanish (Mexico)', 'native_name' => 'Español de México' ), 'es_CO' => array( 'english_name' => 'Spanish (Colombia)', 'native_name' => 'Español de Colombia' ), 'es_ES' => array( 'english_name' => 'Spanish (Spain)', 'native_name' => 'Español' ), 'es_VE' => array( 'english_name' => 'Spanish (Venezuela)', 'native_name' => 'Español de Venezuela' ), 'es_GT' => array( 'english_name' => 'Spanish (Guatemala)', 'native_name' => 'Español de Guatemala' ), 'et' => array( 'english_name' => 'Estonian', 'native_name' => 'Eesti' ), 'eu' => array( 'english_name' => 'Basque', 'native_name' => 'Euskara' ), 'fa_IR' => array( 'english_name' => 'Persian', 'native_name' => 'فارسی' ), 'fi' => array( 'english_name' => 'Finnish', 'native_name' => 'Suomi' ), 'fr_BE' => array( 'english_name' => 'French (Belgium)', 'native_name' => 'Français de Belgique' ), 'fr_FR' => array( 'english_name' => 'French (France)', 'native_name' => 'Français' ), 'fr_CA' => array( 'english_name' => 'French (Canada)', 'native_name' => 'Français du Canada' ), 'gd' => array( 'english_name' => 'Scottish Gaelic', 'native_name' => 'Gàidhlig' ), 'gl_ES' => array( 'english_name' => 'Galician', 'native_name' => 'Galego' ), 'gu' => array( 'english_name' => 'Gujarati', 'native_name' => 'ગુજરાતી' ), 'haz' => array( 'english_name' => 'Hazaragi', 'native_name' => 'هزاره گی' ), 'he_IL' => array( 'english_name' => 'Hebrew', 'native_name' => 'עִבְרִית' ), 'hi_IN' => array( 'english_name' => 'Hindi', 'native_name' => 'हिन्दी' ), 'hr' => array( 'english_name' => 'Croatian', 'native_name' => 'Hrvatski' ), 'hu_HU' => array( 'english_name' => 'Hungarian', 'native_name' => 'Magyar' ), 'hy' => array( 'english_name' => 'Armenian', 'native_name' => 'Հայերեն' ), 'id_ID' => array( 'english_name' => 'Indonesian', 'native_name' => 'Bahasa Indonesia' ), 'is_IS' => array( 'english_name' => 'Icelandic', 'native_name' => 'Íslenska' ), 'it_IT' => array( 'english_name' => 'Italian', 'native_name' => 'Italiano' ), 'ja' => array( 'english_name' => 'Japanese', 'native_name' => '日本語' ), 'ka_GE' => array( 'english_name' => 'Georgian', 'native_name' => 'ქართული' ), 'kab' => array( 'english_name' => 'Kabyle', 'native_name' => 'Taqbaylit' ), 'km' => array( 'english_name' => 'Khmer', 'native_name' => 'ភាសាខ្មែរ' ), 'ko_KR' => array( 'english_name' => 'Korean', 'native_name' => '한국어' ), 'lo' => array( 'english_name' => 'Lao', 'native_name' => 'ພາສາລາວ' ), 'lt_LT' => array( 'english_name' => 'Lithuanian', 'native_name' => 'Lietuvių kalba' ), 'lv' => array( 'english_name' => 'Latvian', 'native_name' => 'Latviešu valoda' ), 'mk_MK' => array( 'english_name' => 'Macedonian', 'native_name' => 'Македонски јазик' ), 'ml_IN' => array( 'english_name' => 'Malayalam', 'native_name' => 'മലയാളം' ), 'mn' => array( 'english_name' => 'Mongolian', 'native_name' => 'Монгол' ), 'mr' => array( 'english_name' => 'Marathi', 'native_name' => 'मराठी' ), 'ms_MY' => array( 'english_name' => 'Malay', 'native_name' => 'Bahasa Melayu' ), 'my_MM' => array( 'english_name' => 'Myanmar (Burmese)', 'native_name' => 'ဗမာစာ' ), 'nb_NO' => array( 'english_name' => 'Norwegian (Bokmål)', 'native_name' => 'Norsk bokmål' ), 'ne_NP' => array( 'english_name' => 'Nepali', 'native_name' => 'नेपाली' ), 'nl_BE' => array( 'english_name' => 'Dutch (Belgium)', 'native_name' => 'Nederlands (België)' ), 'nl_NL' => array( 'english_name' => 'Dutch', 'native_name' => 'Nederlands' ), 'nl_NL_formal' => array( 'english_name' => 'Dutch (Formal)', 'native_name' => 'Nederlands (Formeel)' ), 'nn_NO' => array( 'english_name' => 'Norwegian (Nynorsk)', 'native_name' => 'Norsk nynorsk' ), 'oci' => array( 'english_name' => 'Occitan', 'native_name' => 'Occitan' ), 'pa_IN' => array( 'english_name' => 'Punjabi', 'native_name' => 'ਪੰਜਾਬੀ' ), 'pl_PL' => array( 'english_name' => 'Polish', 'native_name' => 'Polski' ), 'ps' => array( 'english_name' => 'Pashto', 'native_name' => 'پښتو' ), 'pt_BR' => array( 'english_name' => 'Portuguese (Brazil)', 'native_name' => 'Português do Brasil' ), 'pt_PT' => array( 'english_name' => 'Portuguese (Portugal)', 'native_name' => 'Português' ), 'rhg' => array( 'english_name' => 'Rohingya', 'native_name' => 'Ruáinga' ), 'ro_RO' => array( 'english_name' => 'Romanian', 'native_name' => 'Română' ), 'ru_RU' => array( 'english_name' => 'Russian', 'native_name' => 'Русский' ), 'sah' => array( 'english_name' => 'Sakha', 'native_name' => 'Сахалыы' ), 'si_LK' => array( 'english_name' => 'Sinhala', 'native_name' => 'සිංහල' ), 'sk_SK' => array( 'english_name' => 'Slovak', 'native_name' => 'Slovenčina' ), 'sl_SI' => array( 'english_name' => 'Slovenian', 'native_name' => 'Slovenščina' ), 'sq' => array( 'english_name' => 'Albanian', 'native_name' => 'Shqip' ), 'sr_RS' => array( 'english_name' => 'Serbian', 'native_name' => 'Српски језик' ), 'sv_SE' => array( 'english_name' => 'Swedish', 'native_name' => 'Svenska' ), 'szl' => array( 'english_name' => 'Silesian', 'native_name' => 'Ślōnskŏ gŏdka' ), 'ta_IN' => array( 'english_name' => 'Tamil', 'native_name' => 'தமிழ்' ), 'tah' => array( 'english_name' => 'Tahitian', 'native_name' => 'Reo Tahiti' ), 'te' => array( 'english_name' => 'Telugu', 'native_name' => 'తెలుగు' ), 'th' => array( 'english_name' => 'Thai', 'native_name' => 'ไทย' ), 'tl' => array( 'english_name' => 'Tagalog', 'native_name' => 'Tagalog' ), 'tr_TR' => array( 'english_name' => 'Turkish', 'native_name' => 'Türkçe' ), 'tt_RU' => array( 'english_name' => 'Tatar', 'native_name' => 'Татар теле' ), 'ug_CN' => array( 'english_name' => 'Uighur', 'native_name' => 'Uyƣurqə' ), 'uk' => array( 'english_name' => 'Ukrainian', 'native_name' => 'Українська' ), 'ur' => array( 'english_name' => 'Urdu', 'native_name' => 'اردو' ), 'uz_UZ' => array( 'english_name' => 'Uzbek', 'native_name' => 'O‘zbekcha' ), 'vi' => array( 'english_name' => 'Vietnamese', 'native_name' => 'Tiếng Việt' ), 'zh_CN' => array( 'english_name' => 'Chinese (China)', 'native_name' => '简体中文' ), 'zh_HK' => array( 'english_name' => 'Chinese (Hong Kong)', 'native_name' => '香港中文版' ), 'zh_TW' => array( 'english_name' => 'Chinese (Taiwan)', 'native_name' => '繁體中文' ), ); // Allow adding or removing languages. return apply_filters( 'airplane_mode_offline_languages', $languages ); } /** * Return an empty array of items requiring update for both themes and plugins * * @param array $items All the items being passed for update. * * @return array An empty array, or the original items if not enabled. */ public function remove_update_array( $items ) { return ! $this->enabled() ? $items : array(); } /** * Remove the ability to update plugins/themes from single * site and multisite bulk actions * * @param array $actions All the bulk actions. * * @return array $actions The remaining actions */ public function remove_bulk_actions( $actions ) { // Bail if disabled. if ( ! $this->enabled() ) { return $actions; } // Set an array of items to be removed with optional filter. if ( false === $remove = apply_filters( 'airplane_mode_bulk_items', array( 'update-selected', 'update', 'upgrade' ) ) ) { return $actions; } // Loop the item array and unset each. foreach ( $remove as $key ) { unset( $actions[ $key ] ); } // Return the remaining. return $actions; } /** * Remove the tabs on the plugin page to add new items * since they require the WP connection and will fail. * * @param array $nonmenu_tabs All the tabs displayed. * @return array $nonmenu_tabs The remaining tabs. */ public function plugin_add_tabs( $nonmenu_tabs ) { // Bail if disabled. if ( ! $this->enabled() ) { return $nonmenu_tabs; } // Set an array of tabs to be removed with optional filter. if ( false === $remove = apply_filters( 'airplane_mode_bulk_items', array( 'featured', 'popular', 'recommended', 'favorites', 'beta' ) ) ) { return $nonmenu_tabs; } // Loop the item array and unset each. foreach ( $remove as $key ) { unset( $nonmenu_tabs[ $key ] ); } // Return the tabs. return $nonmenu_tabs; } /** * Increase HTTP request counter by one. * * @return void */ public function count_http_requests() { $this->http_count++; } // End class. } } // End class_exists. if ( ! class_exists( 'Airplane_Mode_WP_Error' ) ) { /** * Extend the WP_Error class to include our own. */ class Airplane_Mode_WP_Error extends WP_Error { /** * Get our error data and return it. * * @return string */ public function __tostring() { $data = $this->get_error_data(); return $data['return']; } // End class. } } // Instantiate our class. $Airplane_Mode_Core = Airplane_Mode_Core::getInstance();