metadataUrl = $metadataUrl; $this->enableAutomaticChecking = $enableAutomaticChecking; $this->theme = $theme; $this->optionName = 'external_theme_updates-' . $this->theme; $this->installHooks(); } public function installHooks() { if ($this->enableAutomaticChecking) { add_filter('pre_set_site_transient_update_themes', array($this, 'onTransientUpdate')); } //Insert our update info into the update list maintained by WP. add_filter('site_transient_update_themes', array($this, 'injectUpdate')); //Delete our update info when WP deletes its own. //This usually happens when a theme is installed, removed or upgraded. add_action('delete_site_transient_update_themes', array($this, 'deleteStoredData')); } public function requestUpdate($queryArgs = array()) { //Query args to append to the URL. Themes can add their own by using a filter callback (see addQueryArgFilter()). $queryArgs['installed_version'] = $this->getInstalledVersion(); $queryArgs = apply_filters(self::$filterPrefix . 'query_args-' . $this->theme, $queryArgs); //Various options for the wp_remote_get() call. Themes can filter these, too. $options = array( 'timeout' => 20, //seconds ); $options = apply_filters(self::$filterPrefix . 'options-' . $this->theme, $options); $url = $this->metadataUrl; if (!empty($queryArgs)) { $url = add_query_arg($queryArgs, $url); } //Send the request. $result = wp_remote_get($url, $options); //Try to parse the response $themeUpdate = null; $code = wp_remote_retrieve_response_code($result); $body = wp_remote_retrieve_body($result); if (($code == 200) && !empty($body)) { $themeUpdate = ThemeUpdate::fromJson($body); //The update should be newer than the currently installed version. if (($themeUpdate != null) && version_compare($themeUpdate->version, $this->getInstalledVersion(), '<=')) { $themeUpdate = null; } } $themeUpdate = apply_filters(self::$filterPrefix . 'result-' . $this->theme, $themeUpdate, $result); return $themeUpdate; } public function getInstalledVersion() { if (function_exists('wp_get_theme')) { $theme = wp_get_theme($this->theme); return $theme->get('Version'); } foreach (get_themes() as $theme) { if ($theme['Stylesheet'] === $this->theme) { return $theme['Version']; } } return ''; } public function checkForUpdates() { $state = get_option($this->optionName); if (empty($state)) { $state = new StdClass; $state->lastCheck = 0; $state->checkedVersion = ''; $state->update = null; } $state->lastCheck = time(); $state->checkedVersion = $this->getInstalledVersion(); update_option($this->optionName, $state); //Save before checking in case something goes wrong $state->update = $this->requestUpdate(); update_option($this->optionName, $state); } public function onTransientUpdate($value) { if (!$this->automaticCheckDone) { $this->checkForUpdates(); $this->automaticCheckDone = true; } return $value; } public function injectUpdate($updates) { $state = get_option($this->optionName); //Is there an update to insert? if (!empty($state) && isset($state->update) && !empty($state->update)) { $updates->response[$this->theme] = $state->update->toWpFormat(); } return $updates; } public function deleteStoredData() { delete_option($this->optionName); } public function addQueryArgFilter($callback) { add_filter(self::$filterPrefix . 'query_args-' . $this->theme, $callback); } public function addHttpRequestArgFilter($callback) { add_filter(self::$filterPrefix . 'options-' . $this->theme, $callback); } public function addResultFilter($callback) { add_filter(self::$filterPrefix . 'result-' . $this->theme, $callback, 10, 2); } } endif; if (!class_exists('ThemeUpdate')): class ThemeUpdate { public $version; //Version number. public $details_url; //The URL where the user can learn more about this version. public $download_url; //The download URL for this version of the theme. Optional. public static function fromJson($json) { $apiResponse = json_decode($json); if (empty($apiResponse) || !is_object($apiResponse)) { return null; } //Very, very basic validation. $valid = isset($apiResponse->version) && !empty($apiResponse->version) && isset($apiResponse->details_url) && !empty($apiResponse->details_url); if (!$valid) { return null; } $update = new self(); foreach (get_object_vars($apiResponse) as $key => $value) { $update->$key = $value; } return $update; } public function toWpFormat() { $update = array( 'new_version' => $this->version, 'url' => $this->details_url, ); if (!empty($this->download_url)) { $update['package'] = $this->download_url; } return $update; } } endif;