plugin_basename( __FILE__ ), 'proper_folder_name' => dirname( plugin_basename( __FILE__ ) ), 'sslverify' => true, ]; $this->config = wp_parse_args( $config, $defaults ); if ( ! $this->has_minimum_config() ) { $message = 'The Updater was initialized without the minimum required configuration, please check the config in your plugin. The following params are missing: '; $message .= implode( ',', $this->missing_config ); _doing_it_wrong( __CLASS__, $message , self::VERSION ); return; } $this->set_defaults(); add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'api_check' ] ); // Hook into the plugin details screen add_filter( 'plugins_api', [ $this, 'get_plugin_info' ], 10, 3 ); add_filter( 'upgrader_post_install', [ $this, 'upgrader_post_install' ], 10, 3 ); // set timeout add_filter( 'http_request_timeout', [ $this, 'http_request_timeout' ] ); // set sslverify for zip download add_filter( 'http_request_args', [ $this, 'http_request_sslverify' ], 10, 2 ); } public function has_minimum_config() { $this->missing_config = []; $required_config_params = [ 'updates_url', 'zip_url', 'requires', 'tested', 'release_info', 'auth_username', 'auth_password', ]; foreach ( $required_config_params as $required_param ) { if ( empty( $this->config[$required_param] ) ) $this->missing_config[] = $required_param; } return ( empty( $this->missing_config ) ); } public function set_defaults() { if ( ! isset( $this->config['new_version'] ) ) { $this->config['new_version'] = $this->get_new_version(); } if ( ! isset( $this->config['last_updated'] ) ) { $this->config['last_updated'] = $this->get_date(); } if ( ! isset( $this->config['description'] ) ) { $this->config['description'] = $this->get_description(); } $plugin_data = $this->get_plugin_data(); if ( ! isset( $this->config['plugin_name'] ) ) { $this->config['plugin_name'] = $plugin_data['Name']; } if ( ! isset( $this->config['version'] ) ) { $this->config['version'] = $plugin_data['Version']; } if ( ! isset( $this->config['author'] ) ) { $this->config['author'] = $plugin_data['Author']; } if ( ! isset( $this->config['homepage'] ) ) { $this->config['homepage'] = $plugin_data['PluginURI']; } if ( ! isset( $this->config['release_info'] ) ) { $this->config['release_info'] = 'release_info.json'; } } /** * Get Plugin data * @return array */ public function get_plugin_data() { include_once ABSPATH . '/wp-admin/includes/plugin.php'; $data = get_plugin_data( WP_PLUGIN_DIR . '/' . $this->config['slug'] ); return $data; } /** * Get Data from the update server * @return array|false */ public function get_update_server_data() { if ( null === $this->update_server_data ) { $transient = md5( $this->config['slug'] ) . '_update_server_data'; if ( array_key_exists( 'remove_updater_transient', $_REQUEST ) ) { delete_site_transient( $transient ); } $data = get_site_transient( $transient ); if ( ! isset( $data ) || ! $data || '' == $data ) { $data = $this->remote_get( trailingslashit( $this->config['updates_url'] ) . $this->config['release_info'] ); if ( ! $data || is_wp_error( $data ) ) { return false; } $data = json_decode( $data, true ); set_site_transient( $transient, $data, 60 * 60 * 6 ); // refresh every 6 hours } $this->update_server_data = $data; } return $this->update_server_data; } /** * Get New Version from Update Server * @return string|false $version the version number */ public function get_new_version() { if ( ( $data = $this->get_update_server_data() ) ) { return $data['current_version']; } return false; } /** * Get update date * @return string|false */ public function get_date() { if ( ( $data = $this->get_update_server_data() ) ) { return $data['updated_at']; } return false; } /** * Get plugin description * @return string $description the description */ public function get_description() { if ( ( $data = $this->get_update_server_data() ) ) { return $data['description']; } return false; } /** * Hook into the plugin update check and connect to GitHub * @param object $transient the plugin data transient * @return object $transient updated plugin data transient */ public function api_check( $transient ) { // Check if the transient contains the 'checked' information // If not, just return its value without hacking it if ( empty( $transient->checked ) ) { return $transient; } // check the version and decide if it's new $update = version_compare( $this->config['new_version'], $this->config['version'] ); if ( 1 === $update ) { $response = new stdClass; $response->new_version = $this->config['new_version']; $response->slug = $this->config['proper_folder_name']; $response->url = add_query_arg( [], $this->config['updates_url'] ); $response->package = $this->config['zip_url']; // If response is false, don't alter the transient if ( false !== $response ) $transient->response[ $this->config['slug'] ] = $response; } return $transient; } /** * Get Plugin info * @param bool $false always false * @param string $action the API function being performed * @param object $args plugin arguments * @return object|false $response the plugin info */ public function get_plugin_info( $false, $action, $args ) { // Check if this call API is for the right plugin if ( ! isset( $args->slug ) || $args->slug != $this->config['proper_folder_name'] ) { return false; } $args->slug = $this->config['slug']; $args->plugin_name = $this->config['plugin_name']; $args->version = $this->config['new_version']; $args->author = $this->config['author']; $args->homepage = $this->config['homepage']; $args->requires = $this->config['requires']; $args->tested = $this->config['tested']; $args->downloaded = 0; $args->last_updated = $this->config['last_updated']; $args->sections = [ 'description' => $this->config['description'] ]; $args->download_link = $this->config['zip_url']; return $args; } /** * Move & activate the plugin, echo the update message * @param boolean $true always true * @param mixed $hook_extra not used * @param array $result the result of the move * @return array $result the result of the move */ public function upgrader_post_install( $true, $hook_extra, $result ) { /** @var WP_Filesystem_Base $wp_filesystem */ global $wp_filesystem; // Move & Activate $proper_destination = WP_PLUGIN_DIR . '/' . $this->config['proper_folder_name']; $wp_filesystem->move( $result['destination'], $proper_destination ); $result['destination'] = $proper_destination; $activate = activate_plugin( WP_PLUGIN_DIR . '/' . $this->config['slug'] ); // Output the update message $fail = __( 'The plugin has been updated, but could not be reactivated. Please reactivate it manually.' ); $success = __( 'Plugin reactivated successfully.' ); echo is_wp_error( $activate ) ? $fail : $success; return $result; } /** * Callback fn for the http_request_timeout filter * @return int timeout value */ public function http_request_timeout() { return 2; } /** * Callback fn for the http_request_args filter * @param array $args * @param string $url * @return mixed */ public function http_request_sslverify( $args, $url ) { if ( $this->config[ 'zip_url' ] == $url ) $args[ 'sslverify' ] = $this->config[ 'sslverify' ]; return $args; } /** * Interact with Update Server * @param string $url * @return mixed */ public function remote_get( $url ) { $raw_response = wp_remote_get( $url, [ 'headers' => [ 'Authorization' => 'Basic ' . base64_encode( $this->config['auth_username'] . ':' . $this->config['auth_password'] ) ], 'sslverify' => $this->config['sslverify'] ] ); if ( 200 !== wp_remote_retrieve_response_code( $raw_response ) ) { return false; } return wp_remote_retrieve_body( $raw_response ); } }