TP Basic authentication * userinfo format, so passwords may contain colons. * * @since 7.1.0 * @access private * * @param string $value The raw credentials string. * @return array{username: string, password: string} Parsed credentials. Both values * are empty when the string is malformed. */ function wp_connectors_parse_application_password_credentials( string $value ): array { $separator = strpos( $value, ':' ); // Trim so surrounding whitespace or a trailing newline (common when the // value comes from a file or `.env`) does not become part of the credentials. $username = false === $separator ? '' : trim( substr( $value, 0, $separator ) ); $password = false === $separator ? '' : trim( substr( $value, $separator + 1 ) ); if ( '' === $username || '' === $password ) { return array( 'username' => '', 'password' => '', ); } return array( 'username' => $username, 'password' => $password, ); } /** * Resolves application-password credentials for a connector. * * Checks in order: environment variable, PHP constant, database. The * environment variable and constant are only checked when their respective * names are provided, and must contain the credentials as a single * `username:password` string. A non-empty environment variable or constant * that cannot be parsed as `username:password` is reported with * `_doing_it_wrong()` and ignored, so resolution falls through to the next * source. * * @since 7.1.0 * @access private * * @param array $auth The connector's authentication configuration. * @return array{username: string, password: string, source: string} Resolved credentials and * their source: 'env', 'constant', * 'database', or 'none'. */ function wp_connectors_get_application_password_credentials( array $auth ): array { // Check environment variable first. $env_var_name = $auth['env_var_name'] ?? ''; if ( '' !== $env_var_name ) { $env_value = getenv( $env_var_name ); if ( false !== $env_value && '' !== $env_value ) { $credentials = wp_connectors_parse_application_password_credentials( $env_value ); if ( '' !== $credentials['username'] && '' !== $credentials['password'] ) { $credentials['source'] = 'env'; return $credentials; } _doing_it_wrong( __FUNCTION__, sprintf( /* translators: %s: Environment variable name. */ __( 'The %s environment variable must contain application password credentials in "username:password" format.' ), esc_html( $env_var_name ) ), '7.1.0' ); } } // Check PHP constant. $constant_name = $auth['constant_name'] ?? ''; if ( '' !== $constant_name && defined( $constant_name ) ) { $const_value = constant( $constant_name ); if ( is_string( $const_value ) && '' !== $const_value ) { $credentials = wp_connectors_parse_application_password_credentials( $const_value ); if ( '' !== $credentials['username'] && '' !== $credentials['password'] ) { $credentials['source'] = 'constant'; return $credentials; } _doing_it_wrong( __FUNCTION__, sprintf( /* translators: %s: PHP constant name. */ __( 'The %s constant must contain application password credentials in "username:password" format.' ), esc_html( $constant_name ) ), '7.1.0' ); } } // Check database. $stored = get_option( $auth['setting_name'] ?? '', array() ); $username = is_array( $stored ) && isset( $stored['username'] ) && is_string( $stored['username'] ) ? $stored['username'] : ''; $password = is_array( $stored ) && isset( $stored['password'] ) && is_string( $stored['password'] ) ? $stored['password'] : ''; return array( 'username' => $username, 'password' => $password, 'source' => '' !== $username && '' !== $password ? 'database' : 'none', ); } /** * Checks whether an API key is valid for a given provider. * * @since 7.0.0 * @access private * * @param string $key The API key to check. * @param string $provider_id The WP AI client provider ID. * @return bool|null True if valid, false if invalid, null if unable to determine. */ function _wp_connectors_is_ai_api_key_valid( string $key, string $provider_id ): ?bool { try { $registry = AiClient::defaultRegistry(); if ( ! $registry->hasProvider( $provider_id ) ) { _doing_it_wrong( __FUNCTION__, sprintf( /* translators: %s: AI provider ID. */ __( 'The provider "%s" is not registered in the AI client registry.' ), $provider_id ), '7.0.0' ); return null; } $registry->setProviderRequestAuthentication( $provider_id, new ApiKeyRequestAuthentication( $key ) ); return $registry->isProviderConfigured( $provider_id ); } catch ( Exception $e ) { wp_trigger_error( __FUNCTION__, $e->getMessage() ); return null; } } /** * Sanitizes stored application-password credentials for a connector. * * Credential fields that are missing or not strings keep their currently * stored values, so partial updates cannot silently clear a stored secret. * A password matching the mask that `_wp_connectors_rest_settings_dispatch()` * places in REST responses also keeps the stored password, so a masked * settings response can be submitted back to the endpoint unchanged. * Pass an empty string to clear a field. * If the sanitized username is empty, both fields are discarded so partial * credentials cannot leave an orphaned secret. * * @since 7.1.0 * @access private * * @param mixed $value The submitted setting value. * @param string $option The option name being sanitized. Passed explicitly by the * registered sanitize callback; falls back to the current * `sanitize_option_{$option}` filter name when omitted. * @return array{username: string, password: string} Sanitized credentials. */ function wp_connectors_sanitize_application_password_credentials( $value, string $option = '' ): array { if ( ! is_array( $value ) ) { $value = array(); } if ( '' === $option ) { $option = str_replace( 'sanitize_option_', '', (string) current_filter() ); } $stored = get_option( $option ); if ( ! is_array( $stored ) ) { $stored = array(); } $credentials = array(); foreach ( array( 'username', 'password' ) as $field ) { if ( isset( $value[ $field ] ) && is_string( $value[ $field ] ) ) { $credentials[ $field ] = sanitize_text_field( $value[ $field ] ); } else { $credentials[ $field ] = isset( $stored[ $field ] ) && is_string( $stored[ $field ] ) ? $stored[ $field ] : ''; } } // A masked password means a client resubmitted a masked REST response. if ( str_repeat( "\u{2022}", 16 ) === $credentials['password'] ) { $credentials['password'] = isset( $stored['password'] ) && is_string( $stored['password'] ) ? $stored['password'] : ''; } if ( '' === $credentials['username'] ) { return array( 'username' => '', 'password' => '', ); } return $credentials; } /** * Masks and validates connector credentials in REST responses. * * On every `/wp/v2/settings` response, masks connector API key values and the * password field of default application-password credential objects. * * On POST or PUT requests, validates each updated AI provider API key before * masking. If validation fails, the key is reverted to an empty string. * Application password values are masked but not validated. * * @since 7.0.0 * @access private * * @param WP_REST_Response $response The response object. * @param WP_REST_Server $server The server instance. * @param WP_REST_Request $request The request object. * @return WP_REST_Response The modified response with masked/validated keys. */ function _wp_connectors_rest_settings_dispatch( WP_REST_Response $response, WP_REST_Server $server, WP_REST_Request $request ): WP_REST_Response { if ( '/wp/v2/settings' !== $request->get_route() ) { return $response; } $data = $response->get_data(); if ( ! is_array( $data ) ) { return $response; } $is_update = 'POST' === $request->get_method() || 'PUT' === $request->get_method(); foreach ( wp_get_connectors() as $connector_id => $connector_data ) { $auth = $connector_data['authentication']; if ( 'application_password' === $auth['method'] && ! empty( $auth['setting_name'] ) ) { $setting_name = $auth['setting_name']; if ( array_key_exists( $setting_name, $data ) && is_array( $data[ $setting_name ] ) ) { $password = $data[ $setting_name ]['password'] ?? ''; if ( is_string( $password ) && '' !== $password ) { $data[ $setting_name ]['password'] = str_repeat( "\u{2022}", 16 ); } } continue; } if ( 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) { continue; } $setting_name = $auth['setting_name']; if ( ! array_key_exists( $setting_name, $data ) ) { continue; } $value = $data[ $setting_name ]; // On update, validate AI provider keys before masking. // Non-AI connectors accept keys as-is; the service plugin handles its own validation. if ( $is_update && is_string( $value ) && '' !== $value && 'ai_provider' === $connector_data['type'] ) { if ( true !== _wp_connectors_is_ai_api_key_valid( $value, $connector_id ) ) { update_option( $setting_name, '' ); $data[ $setting_name ] = ''; continue; } } // Mask the key in the response. if ( is_string( $value ) && '' !== $value ) { $data[ $setting_name ] = _wp_connectors_mask_api_key( $value ); } } $response->set_data( $data ); return $response; } add_filter( 'rest_post_dispatch', '_wp_connectors_rest_settings_dispatch', 10, 3 ); /** * Registers default connector settings. * * @since 7.0.0 * @access private */ function _wp_register_default_connector_settings(): void { $registered_settings = get_registered_settings(); foreach ( wp_get_connectors() as $connector_data ) { $auth = $connector_data['authentication']; if ( 'api_key' !== $auth['method'] && 'application_password' !== $auth['method'] ) { continue; } if ( empty( $auth['setting_name'] ) || isset( $registered_settings[ $auth['setting_name'] ] ) ) { continue; } $setting_name = $auth['setting_name']; if ( ! isset( $connector_data['plugin']['is_active'] ) || ! is_callable( $connector_data['plugin']['is_active'] ) ) { continue; } if ( ! call_user_func( $connector_data['plugin']['is_active'] ) ) { continue; } if ( 'api_key' === $auth['method'] ) { register_setting( 'connectors', $setting_name, array( 'type' => 'string', 'label' => sprintf( /* translators: %s: Connector name. */ __( '%s API Key' ), $connector_data['name'] ), 'description' => sprintf( /* translators: %s: Connector name. */ __( 'API key for the %s connector.' ), $connector_data['name'] ), 'default' => '', 'show_in_rest' => true, 'sanitize_callback' => 'sanitize_text_field', ) ); } elseif ( 'application_password' === $auth['method'] ) { register_setting( 'connectors', $setting_name, array( 'type' => 'object', 'label' => sprintf( /* translators: %s: Connector name. */ __( '%s Credentials' ), $connector_data['name'] ), 'description' => sprintf( /* translators: %s: Connector name. */ __( 'Application password credentials for the %s connector.' ), $connector_data['name'] ), 'default' => array( 'username' => '', 'password' => '', ), 'show_in_rest' => array( 'schema' => array( 'type' => 'object', 'properties' => array( 'username' => array( 'type' => 'string', ), 'password' => array( 'type' => 'string', ), ), 'additionalProperties' => false, ), ), 'sanitize_callback' => static function ( $value ) use ( $setting_name ) { return wp_connectors_sanitize_application_password_credentials( $value, $setting_name ); }, ) ); } } } add_action( 'init', '_wp_register_default_connector_settings', 20 ); /** * Passes stored connector API keys to the WP AI client. * * @since 7.0.0 * @access private */ function _wp_connectors_pass_default_keys_to_ai_client(): void { try { $ai_registry = AiClient::defaultRegistry(); foreach ( wp_get_connectors() as $connector_id => $connector_data ) { if ( 'ai_provider' !== $connector_data['type'] ) { continue; } $auth = $connector_data['authentication']; if ( 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) { continue; } if ( ! $ai_registry->hasProvider( $connector_id ) ) { continue; } // Skip if the key is already provided via env var or constant. $key_source = _wp_connectors_get_api_key_source( $auth['setting_name'], $auth['env_var_name'] ?? '', $auth['constant_name'] ?? '' ); if ( 'env' === $key_source || 'constant' === $key_source ) { continue; } $api_key = get_option( $auth['setting_name'], '' ); if ( ! is_string( $api_key ) || '' === $api_key ) { continue; } $ai_registry->setProviderRequestAuthentication( $connector_id, new ApiKeyRequestAuthentication( $api_key ) ); } } catch ( Exception $e ) { wp_trigger_error( __FUNCTION__, $e->getMessage() ); } } add_action( 'init', '_wp_connectors_pass_default_keys_to_ai_client', 20 ); /** * Exposes connector settings to the connectors-wp-admin script module. * * @since 7.0.0 * @access private * * @param array $data Existing script module data. * @return array Script module data with connectors added. */ function _wp_connectors_get_connector_script_module_data( array $data ): array { $registry = AiClient::defaultRegistry(); if ( ! function_exists( 'validate_plugin' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $connectors = array(); foreach ( wp_get_connectors() as $connector_id => $connector_data ) { $auth = $connector_data['authentication']; $auth_out = array( 'method' => $auth['method'] ); if ( 'api_key' === $auth['method'] ) { $auth_out['settingName'] = $auth['setting_name'] ?? ''; $auth_out['credentialsUrl'] = $auth['credentials_url'] ?? null; $key_source = _wp_connectors_get_api_key_source( $auth['setting_name'] ?? '', $auth['env_var_name'] ?? '', $auth['constant_name'] ?? '' ); $auth_out['keySource'] = $key_source; if ( 'ai_provider' === $connector_data['type'] ) { try { $auth_out['isConnected'] = $registry->hasProvider( $connector_id ) && $registry->isProviderConfigured( $connector_id ); } catch ( Exception $e ) { $auth_out['isConnected'] = false; } } else { $auth_out['isConnected'] = 'none' !== $key_source; } } elseif ( 'application_password' === $auth['method'] ) { $credentials = wp_connectors_get_application_password_credentials( $auth ); $auth_out['settingName'] = $auth['setting_name'] ?? ''; $auth_out['credentialsUrl'] = $auth['credentials_url'] ?? null; $auth_out['keySource'] = $credentials['source']; $auth_out['isConnected'] = '' !== $credentials['username'] && '' !== $credentials['password']; } $connector_out = array( 'name' => $connector_data['name'], 'description' => $connector_data['description'], 'logoUrl' => ! empty( $connector_data['logo_url'] ) ? $connector_data['logo_url'] : null, 'type' => $connector_data['type'], 'authentication' => $auth_out, ); if ( ! empty( $connector_data['plugin']['file'] ) ) { $file = $connector_data['plugin']['file']; $is_activated = (bool) call_user_func( $connector_data['plugin']['is_active'] ); $is_installed = $is_activated || 0 === validate_plugin( $file ); $connector_out['plugin'] = array( 'file' => $file, 'isInstalled' => $is_installed, 'isActivated' => $is_activated, ); } $connectors[ $connector_id ] = $connector_out; } ksort( $connectors ); $data['connectors'] = $connectors; $data['isFileModDisabled'] = ! wp_is_file_mod_allowed( 'install_plugins' ); return $data; } add_filter( 'script_module_data_options-connectors-wp-admin', '_wp_connectors_get_connector_script_module_data' ); ), 'get_instance' ) ); if ( isset( $_GET['page'] ) && $tgmpa_instance->menu === $_GET['page'] ) { if ( ! class_exists( 'Plugin_Upgrader', false ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; } if ( ! class_exists( 'TGMPA_Bulk_Installer' ) ) { /** * Installer class to handle bulk plugin installations. * * Extends WP_Upgrader and customizes to suit the installation of multiple * plugins. * * @since 2.2.0 * * {@internal Since 2.5.0 the class is an extension of Plugin_Upgrader rather than WP_Upgrader.}} * {@internal Since 2.5.2 the class has been renamed from TGM_Bulk_Installer to TGMPA_Bulk_Installer. * This was done to prevent backward compatibility issues with v2.3.6.}} * * @package TGM-Plugin-Activation * @author Thomas Griffin * @author Gary Jones */ class TGMPA_Bulk_Installer extends Plugin_Upgrader { /** * Holds result of bulk plugin installation. * * @since 2.2.0 * * @var string */ public $result; /** * Flag to check if bulk installation is occurring or not. * * @since 2.2.0 * * @var boolean */ public $bulk = false; /** * TGMPA instance * * @since 2.5.0 * * @var object */ protected $tgmpa; /** * Whether or not the destination directory needs to be cleared ( = on update). * * @since 2.5.0 * * @var bool */ protected $clear_destination = false; /** * References parent constructor and sets defaults for class. * * @since 2.2.0 * * @param \Bulk_Upgrader_Skin|null $skin Installer skin. */ public function __construct( $skin = null ) { // Get TGMPA class instance. $this->tgmpa = call_user_func( array( get_class( $GLOBALS['firezy'] ), 'get_instance' ) ); parent::__construct( $skin ); if ( isset( $this->skin->options['install_type'] ) && 'update' === $this->skin->options['install_type'] ) { $this->clear_destination = true; } if ( $this->tgmpa->is_automatic ) { $this->activate_strings(); } add_action( 'upgrader_process_complete', array( $this->tgmpa, 'populate_file_path' ) ); } /** * Sets the correct activation strings for the installer skin to use. * * @since 2.2.0 */ public function activate_strings() { $this->strings['activation_failed'] = __( 'Plugin activation failed.', 'firezy' ); $this->strings['activation_success'] = __( 'Plugin activated successfully.', 'firezy' ); } /** * Performs the actual installation of each plugin. * * @since 2.2.0 * * @see WP_Upgrader::run() * * @param array $options The installation config options. * @return null|array Return early if error, array of installation data on success. */ public function run( $options ) { $result = parent::run( $options ); // Reset the strings in case we changed one during automatic activation. if ( $this->tgmpa->is_automatic ) { if ( 'update' === $this->skin->options['install_type'] ) { $this->upgrade_strings(); } else { $this->install_strings(); } } return $result; } /** * Processes the bulk installation of plugins. * * @since 2.2.0 * * {@internal This is basically a near identical copy of the WP Core * Plugin_Upgrader::bulk_upgrade() method, with minor adjustments to deal with * new installs instead of upgrades. * For ease of future synchronizations, the adjustments are clearly commented, but no other * comments are added. Code style has been made to comply.}} * * @see Plugin_Upgrader::bulk_upgrade() * @see https://core.trac.wordpress.org/browser/tags/4.2.1/src/wp-admin/includes/class-wp-upgrader.php#L838 * (@internal Last synced: Dec 31st 2015 against https://core.trac.wordpress.org/browser/trunk?rev=36134}} * * @param array $plugins The plugin sources needed for installation. * @param array $args Arbitrary passed extra arguments. * @return array|false Install confirmation messages on success, false on failure. */ public function bulk_install( $plugins, $args = array() ) { // [TGMPA + ] Hook auto-activation in. add_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 ); $defaults = array( 'clear_update_cache' => true, ); $parsed_args = wp_parse_args( $args, $defaults ); $this->init(); $this->bulk = true; $this->install_strings(); // [TGMPA + ] adjusted. /* [TGMPA - ] $current = get_site_transient( 'update_plugins' ); */ /* [TGMPA - ] add_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'), 10, 4); */ $this->skin->header(); // Connect to the Filesystem first. $res = $this->fs_connect( array( WP_CONTENT_DIR, WP_PLUGIN_DIR ) ); if ( ! $res ) { $this->skin->footer(); return false; } $this->skin->bulk_header(); /* * Only start maintenance mode if: * - running Multisite and there are one or more plugins specified, OR * - a plugin with an update available is currently active. * @TODO: For multisite, maintenance mode should only kick in for individual sites if at all possible. */ $maintenance = ( is_multisite() && ! empty( $plugins ) ); /* [TGMPA - ] foreach ( $plugins as $plugin ) $maintenance = $maintenance || ( is_plugin_active( $plugin ) && isset( $current->response[ $plugin] ) ); */ if ( $maintenance ) { $this->maintenance_mode( true ); } $results = array(); $this->update_count = count( $plugins ); $this->update_current = 0; foreach ( $plugins as $plugin ) { $this->update_current++; /* [TGMPA - ] $this->skin->plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true); if ( !isset( $current->response[ $plugin ] ) ) { $this->skin->set_result('up_to_date'); $this->skin->before(); $this->skin->feedback('up_to_date'); $this->skin->after(); $results[$plugin] = true; continue; } // Get the URL to the zip file. $r = $current->response[ $plugin ]; $this->skin->plugin_active = is_plugin_active($plugin); */ $result = $this->run( array( 'package' => $plugin, // [TGMPA + ] adjusted. 'destination' => WP_PLUGIN_DIR, 'clear_destination' => false, // [TGMPA + ] adjusted. 'clear_working' => true, 'is_multi' => true, 'hook_extra' => array( 'plugin' => $plugin, ), ) ); $results[ $plugin ] = $this->result; // Prevent credentials auth screen from displaying multiple times. if ( false === $result ) { break; } } //end foreach $plugins $this->maintenance_mode( false ); /** * Fires when the bulk upgrader process is complete. * * @since WP 3.6.0 / TGMPA 2.5.0 * * @param Plugin_Upgrader $this Plugin_Upgrader instance. In other contexts, $this, might * be a Theme_Upgrader or Core_Upgrade instance. * @param array $data { * Array of bulk item update data. * * @type string $action Type of action. Default 'update'. * @type string $type Type of update process. Accepts 'plugin', 'theme', or 'core'. * @type bool $bulk Whether the update process is a bulk update. Default true. * @type array $packages Array of plugin, theme, or core packages to update. * } */ do_action( 'upgrader_process_complete', $this, array( 'action' => 'install', // [TGMPA + ] adjusted. 'type' => 'plugin', 'bulk' => true, 'plugins' => $plugins, ) ); $this->skin->bulk_footer(); $this->skin->footer(); // Cleanup our hooks, in case something else does a upgrade on this connection. /* [TGMPA - ] remove_filter('upgrader_clear_destination', array($this, 'delete_old_plugin')); */ // [TGMPA + ] Remove our auto-activation hook. remove_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 ); // Force refresh of plugin update information. wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); return $results; } /** * Handle a bulk upgrade request. * * @since 2.5.0 * * @see Plugin_Upgrader::bulk_upgrade() * * @param array $plugins The local WP file_path's of the plugins which should be upgraded. * @param array $args Arbitrary passed extra arguments. * @return string|bool Install confirmation messages on success, false on failure. */ public function bulk_upgrade( $plugins, $args = array() ) { add_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 ); $result = parent::bulk_upgrade( $plugins, $args ); remove_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 ); return $result; } /** * Abuse a filter to auto-activate plugins after installation. * * Hooked into the 'upgrader_post_install' filter hook. * * @since 2.5.0 * * @param bool $bool The value we need to give back (true). * @return bool */ public function auto_activate( $bool ) { // Only process the activation of installed plugins if the automatic flag is set to true. if ( $this->tgmpa->is_automatic ) { // Flush plugins cache so the headers of the newly installed plugins will be read correctly. wp_clean_plugins_cache(); // Get the installed plugin file. $plugin_info = $this->plugin_info(); // Don't try to activate on upgrade of active plugin as WP will do this already. if ( ! is_plugin_active( $plugin_info ) ) { $activate = activate_plugin( $plugin_info ); // Adjust the success string based on the activation result. $this->strings['process_success'] = $this->strings['process_success'] . "
\n"; if ( is_wp_error( $activate ) ) { $this->skin->error( $activate ); $this->strings['process_success'] .= $this->strings['activation_failed']; } else { $this->strings['process_success'] .= $this->strings['activation_success']; } } } return $bool; } } } if ( ! class_exists( 'TGMPA_Bulk_Installer_Skin' ) ) { /** * Installer skin to set strings for the bulk plugin installations.. * * Extends Bulk_Upgrader_Skin and customizes to suit the installation of multiple * plugins. * * @since 2.2.0 * * {@internal Since 2.5.2 the class has been renamed from TGM_Bulk_Installer_Skin to * TGMPA_Bulk_Installer_Skin. * This was done to prevent backward compatibility issues with v2.3.6.}} * * @see https://core.trac.wordpress.org/browser/trunk/src/wp-admin/includes/class-wp-upgrader-skins.php * * @package TGM-Plugin-Activation * @author Thomas Griffin * @author Gary Jones */ class TGMPA_Bulk_Installer_Skin extends Bulk_Upgrader_Skin { /** * Holds plugin info for each individual plugin installation. * * @since 2.2.0 * * @var array */ public $plugin_info = array(); /** * Holds names of plugins that are undergoing bulk installations. * * @since 2.2.0 * * @var array */ public $plugin_names = array(); /** * Integer to use for iteration through each plugin installation. * * @since 2.2.0 * * @var integer */ public $i = 0; /** * TGMPA instance * * @since 2.5.0 * * @var object */ protected $tgmpa; /** * Constructor. Parses default args with new ones and extracts them for use. * * @since 2.2.0 * * @param array $args Arguments to pass for use within the class. */ public function __construct( $args = array() ) { // Get TGMPA class instance. $this->tgmpa = call_user_func( array( get_class( $GLOBALS['firezy'] ), 'get_instance' ) ); // Parse default and new args. $defaults = array( 'url' => '', 'nonce' => '', 'names' => array(), 'install_type' => 'install', ); $args = wp_parse_args( $args, $defaults ); // Set plugin names to $this->plugin_names property. $this->plugin_names = $args['names']; // Extract the new args. parent::__construct( $args ); } /** * Sets install skin strings for each individual plugin. * * Checks to see if the automatic activation flag is set and uses the * the proper strings accordingly. * * @since 2.2.0 */ public function add_strings() { if ( 'update' === $this->options['install_type'] ) { parent::add_strings(); /* translators: 1: plugin name, 2: action number 3: total number of actions. */ $this->upgrader->strings['skin_before_update_header'] = __( 'Updating Plugin %1$s (%2$d/%3$d)', 'firezy' ); } else { /* translators: 1: plugin name, 2: error message. */ $this->upgrader->strings['skin_update_failed_error'] = __( 'An error occurred while installing %1$s: %2$s.', 'firezy' ); /* translators: 1: plugin name. */ $this->upgrader->strings['skin_update_failed'] = __( 'The installation of %1$s failed.', 'firezy' ); if ( $this->tgmpa->is_automatic ) { // Automatic activation strings. $this->upgrader->strings['skin_upgrade_start'] = __( 'The installation and activation process is starting. This process may take a while on some hosts, so please be patient.', 'firezy' ); /* translators: 1: plugin name. */ $this->upgrader->strings['skin_update_successful'] = __( '%1$s installed and activated successfully.', 'firezy' ); $this->upgrader->strings['skin_upgrade_end'] = __( 'All installations and activations have been completed.', 'firezy' ); /* translators: 1: plugin name, 2: action number 3: total number of actions. */ $this->upgrader->strings['skin_before_update_header'] = __( 'Installing and Activating Plugin %1$s (%2$d/%3$d)', 'firezy' ); } else { // Default installation strings. $this->upgrader->strings['skin_upgrade_start'] = __( 'The installation process is starting. This process may take a while on some hosts, so please be patient.', 'firezy' ); /* translators: 1: plugin name. */ $this->upgrader->strings['skin_update_successful'] = esc_html__( '%1$s installed successfully.', 'firezy' ) . ' ' . esc_html__( 'Show Details', 'firezy' ) . '.'; $this->upgrader->strings['skin_upgrade_end'] = __( 'All installations have been completed.', 'firezy' ); /* translators: 1: plugin name, 2: action number 3: total number of actions. */ $this->upgrader->strings['skin_before_update_header'] = __( 'Installing Plugin %1$s (%2$d/%3$d)', 'firezy' ); } } } /** * Outputs the header strings and necessary JS before each plugin installation. * * @since 2.2.0 * * @param string $title Unused in this implementation. */ public function before( $title = '' ) { if ( empty( $title ) ) { $title = esc_html( $this->plugin_names[ $this->i ] ); } parent::before( $title ); } /** * Outputs the footer strings and necessary JS after each plugin installation. * * Checks for any errors and outputs them if they exist, else output * success strings. * * @since 2.2.0 * * @param string $title Unused in this implementation. */ public function after( $title = '' ) { if ( empty( $title ) ) { $title = esc_html( $this->plugin_names[ $this->i ] ); } parent::after( $title ); $this->i++; } /** * Outputs links after bulk plugin installation is complete. * * @since 2.2.0 */ public function bulk_footer() { // Serve up the string to say installations (and possibly activations) are complete. parent::bulk_footer(); // Flush plugins cache so we can make sure that the installed plugins list is always up to date. wp_clean_plugins_cache(); $this->tgmpa->show_tgmpa_version(); // Display message based on if all plugins are now active or not. $update_actions = array(); if ( $this->tgmpa->is_tgmpa_complete() ) { // All plugins are active, so we display the complete string and hide the menu to protect users. echo ''; $update_actions['dashboard'] = sprintf( esc_html( $this->tgmpa->strings['complete'] ), '' . esc_html__( 'Return to the Dashboard', 'firezy' ) . '' ); } else { $update_actions['tgmpa_page'] = '' . esc_html( $this->tgmpa->strings['return'] ) . ''; } /** * Filter the list of action links available following bulk plugin installs/updates. * * @since 2.5.0 * * @param array $update_actions Array of plugin action links. * @param array $plugin_info Array of information for the last-handled plugin. */ $update_actions = apply_filters( 'tgmpa_update_bulk_plugins_complete_actions', $update_actions, $this->plugin_info ); if ( ! empty( $update_actions ) ) { $this->feedback( implode( ' | ', (array) $update_actions ) ); } } /* *********** DEPRECATED METHODS *********** */ /** * Flush header output buffer. * * @since 2.2.0 * @deprecated 2.5.0 use {@see Bulk_Upgrader_Skin::flush_output()} instead * @see Bulk_Upgrader_Skin::flush_output() */ public function before_flush_output() { _deprecated_function( __FUNCTION__, 'TGMPA 2.5.0', 'Bulk_Upgrader_Skin::flush_output()' ); $this->flush_output(); } /** * Flush footer output buffer and iterate $this->i to make sure the * installation strings reference the correct plugin. * * @since 2.2.0 * @deprecated 2.5.0 use {@see Bulk_Upgrader_Skin::flush_output()} instead * @see Bulk_Upgrader_Skin::flush_output() */ public function after_flush_output() { _deprecated_function( __FUNCTION__, 'TGMPA 2.5.0', 'Bulk_Upgrader_Skin::flush_output()' ); $this->flush_output(); $this->i++; } } } } } } if ( ! class_exists( 'TGMPA_Utils' ) ) { /** * Generic utilities for TGMPA. * * All methods are static, poor-dev name-spacing class wrapper. * * Class was called TGM_Utils in 2.5.0 but renamed TGMPA_Utils in 2.5.1 as this was conflicting with Soliloquy. * * @since 2.5.0 * * @package TGM-Plugin-Activation * @author Juliette Reinders Folmer */ class TGMPA_Utils { /** * Whether the PHP filter extension is enabled. * * @see http://php.net/book.filter * * @since 2.5.0 * * @static * * @var bool $has_filters True is the extension is enabled. */ public static $has_filters; /** * Wrap an arbitrary string in tags. Meant to be used in combination with array_map(). * * @since 2.5.0 * * @static * * @param string $string Text to be wrapped. * @return string */ public static function wrap_in_em( $string ) { return '' . wp_kses_post( $string ) . ''; } /** * Wrap an arbitrary string in tags. Meant to be used in combination with array_map(). * * @since 2.5.0 * * @static * * @param string $string Text to be wrapped. * @return string */ public static function wrap_in_strong( $string ) { return '' . wp_kses_post( $string ) . ''; } /** * Helper function: Validate a value as boolean * * @since 2.5.0 * * @static * * @param mixed $value Arbitrary value. * @return bool */ public static function validate_bool( $value ) { if ( ! isset( self::$has_filters ) ) { self::$has_filters = extension_loaded( 'filter' ); } if ( self::$has_filters ) { return filter_var( $value, FILTER_VALIDATE_BOOLEAN ); } else { return self::emulate_filter_bool( $value ); } } /** * Helper function: Cast a value to bool * * @since 2.5.0 * * @static * * @param mixed $value Value to cast. * @return bool */ protected static function emulate_filter_bool( $value ) { // @codingStandardsIgnoreStart static $true = array( '1', 'true', 'True', 'TRUE', 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', ); static $false = array( '0', 'false', 'False', 'FALSE', 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF', ); // @codingStandardsIgnoreEnd if ( is_bool( $value ) ) { return $value; } elseif ( is_int( $value ) && ( 0 === $value || 1 === $value ) ) { return (bool) $value; } elseif ( ( is_float( $value ) && ! is_nan( $value ) ) && ( (float) 0 === $value || (float) 1 === $value ) ) { return (bool) $value; } elseif ( is_string( $value ) ) { $value = trim( $value ); if ( in_array( $value, $true, true ) ) { return true; } elseif ( in_array( $value, $false, true ) ) { return false; } else { return false; } } return false; } } // End of class TGMPA_Utils } // End of class_exists wrapper