extensions = $extensions; $this->license = $license; $this->api = $api; } /** * Add hooks */ public function init() { add_filter('pre_set_site_transient_update_plugins', [ $this, 'add_updates' ]); add_filter('plugins_api', [ $this, 'get_plugin_info' ], 20, 3); add_filter('http_request_args', [ $this, 'add_auth_headers' ], 10, 2); } /** * This adds the license key header to download package requests. * * @param array $args * @param string $url * * @return mixed */ public function add_auth_headers($args, $url) { // only act on download request's to the Boxzilla update API if (strpos($url, $this->api->url) !== 0 || strpos($url, '/download') === false) { return $args; } // only add if activation key not empty if (empty($this->license->activation_key)) { return $args; } if (! isset($args['headers'])) { $args['headers'] = []; } $args['headers']['Authorization'] = "Bearer {$this->license->activation_key}"; return $args; } /** * @param $result * @param string $action * @param object $args * * @return object|null */ public function get_plugin_info($result, $action, $args) { // do nothing for unrelated requests if ($action !== 'plugin_information' || ! isset($args->slug)) { return $result; } // only act on our plugins if (strpos($args->slug, 'boxzilla-') !== 0) { return $result; } return $this->get_update_info($args->slug); } /** * @param null|object $updates * @return object */ public function add_updates($updates) { // do nothing if no plugins registered if (empty($this->extensions)) { return $updates; } // failsafe WP bug if (empty($updates) || ! isset($updates->response) || ! is_array($updates->response)) { return $updates; } // fetch available updates $available_updates = $this->fetch_updates(); // merge with other updates $updates->response = array_merge($updates->response, $available_updates); return $updates; } /** * Fetch array of available updates from remote server * * @return array */ protected function fetch_updates() { if (is_array($this->available_updates)) { return $this->available_updates; } // don't try if we failed a request recently. $failed_at = get_transient('boxzilla_request_failed'); if (! empty($failed_at) && ( ( time() - 300 ) < $failed_at )) { return []; } // fetch remote info try { $remote_plugins = $this->api->get_plugins(); } catch (API_Exception $e) { // set flag for 5 minutes set_transient('boxzilla_request_failed', time(), 300); return []; } // filter remote plugins, we only want the ones with an update available $this->available_updates = $this->filter_remote_plugins($remote_plugins); return $this->available_updates; } /** * @param $remote_plugins * @return array */ protected function filter_remote_plugins($remote_plugins) { $available_updates = []; // find new versions foreach ($remote_plugins as $remote_plugin) { // sanity check if (! isset($remote_plugin->new_version)) { continue; } // if plugin is activated, we can access it here if (isset($this->extensions[ $remote_plugin->sid ])) { /** @var Plugin $local_plugin */ $local_plugin = $this->extensions[ $remote_plugin->sid ]; // plugin found and local plugin version not same as remote version? if (! $local_plugin || version_compare($local_plugin->version(), $remote_plugin->new_version, '>=')) { continue; } // add some dynamic data $available_updates[ $local_plugin->slug() ] = $this->format_response($local_plugin->slug(), $remote_plugin); } else { // if plugin is not active, use get_plugin_data for fetching version $plugin_file = WP_PLUGIN_DIR . "/{$remote_plugin->slug}/{$remote_plugin->slug}.php"; if (! file_exists($plugin_file)) { continue; } $plugin_data = get_plugin_data($plugin_file); if (! $plugin_data || version_compare($plugin_data['Version'], $remote_plugin->new_version, '>=')) { continue; } // add some dynamic data $slug = plugin_basename($plugin_file); $available_updates[ $slug ] = $this->format_response($slug, $remote_plugin); } } return $available_updates; } /** * @param string $slug * * @return object|null */ public function get_update_info($slug) { $available_updates = $this->fetch_updates(); foreach ($available_updates as $plugin_file => $update_info) { if ($slug === $update_info->slug) { return $update_info; } } return null; } /** * @param $slug * @param $response * * @return mixed */ protected function format_response($slug, $response) { $response->slug = dirname($slug); $response->plugin = $slug; // add some notices if license is inactive if (! $this->license->activated) { $response->upgrade_notice = sprintf('You will need to activate your license to install this plugin update.', admin_url('edit.php?post_type=boxzilla-box&page=boxzilla-settings')); $response->sections->changelog = '

' . sprintf('You will need to activate your license to install this plugin update.', admin_url('edit.php?post_type=boxzilla-box&page=boxzilla-settings')) . '

' . $response->sections->changelog; $response->package = null; } // cast subkey objects to array as that is what WP expects $response->sections = get_object_vars($response->sections); $response->banners = get_object_vars($response->banners); $response->contributors = get_object_vars($response->contributors); $response->contributors = array_map( function ($v) { return get_object_vars($v); }, $response->contributors ); return $response; } }