Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extract file parsing and lookup as a separate "Package" class.
- Loading branch information
1 parent
98ac494
commit 4f6afa9
Showing
9 changed files
with
413 additions
and
227 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<?php | ||
if ( !class_exists('Puc_v4p4_InstalledPackage', false) ): | ||
|
||
/** | ||
* This class represents a currently installed plugin or theme. | ||
* | ||
* Not to be confused with the "package" field in WP update API responses that contains | ||
* the download URL of a the new version. | ||
*/ | ||
abstract class Puc_v4p4_InstalledPackage { | ||
/** | ||
* @var Puc_v4p4_UpdateChecker | ||
*/ | ||
protected $updateChecker; | ||
|
||
public function __construct($updateChecker) { | ||
$this->updateChecker = $updateChecker; | ||
} | ||
|
||
/** | ||
* Get the currently installed version of the plugin or theme. | ||
* | ||
* @return string|null Version number. | ||
*/ | ||
abstract public function getInstalledVersion(); | ||
|
||
/** | ||
* Get the full path of the plugin or theme directory (without a trailing slash). | ||
* | ||
* @return string | ||
*/ | ||
abstract public function getAbsoluteDirectoryPath(); | ||
|
||
/** | ||
* Check whether a regular file exists in the package's directory. | ||
* | ||
* @param string $relativeFileName File name relative to the package directory. | ||
* @return bool | ||
*/ | ||
public function fileExists($relativeFileName) { | ||
return is_file( | ||
$this->getAbsoluteDirectoryPath() | ||
. DIRECTORY_SEPARATOR | ||
. ltrim($relativeFileName, '/\\') | ||
); | ||
} | ||
|
||
/* ------------------------------------------------------------------- | ||
* File header parsing | ||
* ------------------------------------------------------------------- | ||
*/ | ||
|
||
/** | ||
* Parse plugin or theme metadata from the header comment. | ||
* | ||
* This is basically a simplified version of the get_file_data() function from /wp-includes/functions.php. | ||
* It's intended as a utility for subclasses that detect updates by parsing files in a VCS. | ||
* | ||
* @param string|null $content File contents. | ||
* @return string[] | ||
*/ | ||
public function getFileHeader($content) { | ||
$content = (string)$content; | ||
|
||
//WordPress only looks at the first 8 KiB of the file, so we do the same. | ||
$content = substr($content, 0, 8192); | ||
//Normalize line endings. | ||
$content = str_replace("\r", "\n", $content); | ||
|
||
$headers = $this->getHeaderNames(); | ||
$results = array(); | ||
foreach ($headers as $field => $name) { | ||
$success = preg_match('/^[ \t\/*#@]*' . preg_quote($name, '/') . ':(.*)$/mi', $content, $matches); | ||
|
||
if ( ($success === 1) && $matches[1] ) { | ||
$value = $matches[1]; | ||
if ( function_exists('_cleanup_header_comment') ) { | ||
$value = _cleanup_header_comment($value); | ||
} | ||
$results[$field] = $value; | ||
} else { | ||
$results[$field] = ''; | ||
} | ||
} | ||
|
||
return $results; | ||
} | ||
|
||
/** | ||
* @return array Format: ['HeaderKey' => 'Header Name'] | ||
*/ | ||
abstract protected function getHeaderNames(); | ||
|
||
/** | ||
* Get the value of a specific plugin or theme header. | ||
* | ||
* @param string $headerName | ||
* @return string Either the value of the header, or an empty string if the header doesn't exist. | ||
*/ | ||
abstract public function getHeaderValue($headerName); | ||
|
||
} | ||
endif; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
<?php | ||
if ( !class_exists('Puc_v4p4_Plugin_Package', false) ): | ||
|
||
class Puc_v4p4_Plugin_Package extends Puc_v4p4_InstalledPackage { | ||
/** | ||
* @var Puc_v4p4_Plugin_UpdateChecker | ||
*/ | ||
protected $updateChecker; | ||
|
||
/** | ||
* @var string Full path of the main plugin file. | ||
*/ | ||
protected $pluginAbsolutePath = ''; | ||
|
||
/** | ||
* @var string Plugin basename. | ||
*/ | ||
private $pluginFile; | ||
|
||
/** | ||
* @var string|null | ||
*/ | ||
private $cachedInstalledVersion = null; | ||
|
||
public function __construct($pluginAbsolutePath, $updateChecker) { | ||
$this->pluginAbsolutePath = $pluginAbsolutePath; | ||
$this->pluginFile = plugin_basename($this->pluginAbsolutePath); | ||
|
||
parent::__construct($updateChecker); | ||
|
||
//Clear the version number cache when something - anything - is upgraded or WP clears the update cache. | ||
add_filter('upgrader_post_install', array($this, 'clearCachedVersion')); | ||
add_action('delete_site_transient_update_plugins', array($this, 'clearCachedVersion')); | ||
} | ||
|
||
public function getInstalledVersion() { | ||
if ( isset($this->cachedInstalledVersion) ) { | ||
return $this->cachedInstalledVersion; | ||
} | ||
|
||
$pluginHeader = $this->getPluginHeader(); | ||
if ( isset($pluginHeader['Version']) ) { | ||
$this->cachedInstalledVersion = $pluginHeader['Version']; | ||
return $pluginHeader['Version']; | ||
} else { | ||
//This can happen if the filename points to something that is not a plugin. | ||
$this->updateChecker->triggerError( | ||
sprintf( | ||
"Can't to read the Version header for '%s'. The filename is incorrect or is not a plugin.", | ||
$this->updateChecker->pluginFile | ||
), | ||
E_USER_WARNING | ||
); | ||
return null; | ||
} | ||
} | ||
|
||
/** | ||
* Clear the cached plugin version. This method can be set up as a filter (hook) and will | ||
* return the filter argument unmodified. | ||
* | ||
* @param mixed $filterArgument | ||
* @return mixed | ||
*/ | ||
public function clearCachedVersion($filterArgument = null) { | ||
$this->cachedInstalledVersion = null; | ||
return $filterArgument; | ||
} | ||
|
||
public function getAbsoluteDirectoryPath() { | ||
return dirname($this->pluginAbsolutePath); | ||
} | ||
|
||
/** | ||
* Get the value of a specific plugin or theme header. | ||
* | ||
* @param string $headerName | ||
* @param string $defaultValue | ||
* @return string Either the value of the header, or $defaultValue if the header doesn't exist or is empty. | ||
*/ | ||
public function getHeaderValue($headerName, $defaultValue = '') { | ||
$headers = $this->getPluginHeader(); | ||
if ( isset($headers[$headerName]) && ($headers[$headerName] !== '') ) { | ||
return $headers[$headerName]; | ||
} | ||
return $defaultValue; | ||
} | ||
|
||
protected function getHeaderNames() { | ||
return array( | ||
'Name' => 'Plugin Name', | ||
'PluginURI' => 'Plugin URI', | ||
'Version' => 'Version', | ||
'Description' => 'Description', | ||
'Author' => 'Author', | ||
'AuthorURI' => 'Author URI', | ||
'TextDomain' => 'Text Domain', | ||
'DomainPath' => 'Domain Path', | ||
'Network' => 'Network', | ||
|
||
//The newest WordPress version that this plugin requires or has been tested with. | ||
//We support several different formats for compatibility with other libraries. | ||
'Tested WP' => 'Tested WP', | ||
'Requires WP' => 'Requires WP', | ||
'Tested up to' => 'Tested up to', | ||
'Requires at least' => 'Requires at least', | ||
); | ||
} | ||
|
||
/** | ||
* Get the translated plugin title. | ||
* | ||
* @return string | ||
*/ | ||
public function getPluginTitle() { | ||
$title = ''; | ||
$header = $this->getPluginHeader(); | ||
if ( $header && !empty($header['Name']) && isset($header['TextDomain']) ) { | ||
$title = translate($header['Name'], $header['TextDomain']); | ||
} | ||
return $title; | ||
} | ||
|
||
/** | ||
* Get plugin's metadata from its file header. | ||
* | ||
* @return array | ||
*/ | ||
public function getPluginHeader() { | ||
if ( !is_file($this->pluginAbsolutePath) ) { | ||
//This can happen if the plugin filename is wrong. | ||
$this->updateChecker->triggerError( | ||
sprintf( | ||
"Can't to read the plugin header for '%s'. The file does not exist.", | ||
$this->updateChecker->pluginFile | ||
), | ||
E_USER_WARNING | ||
); | ||
return array(); | ||
} | ||
|
||
if ( !function_exists('get_plugin_data') ) { | ||
/** @noinspection PhpIncludeInspection */ | ||
require_once(ABSPATH . '/wp-admin/includes/plugin.php'); | ||
} | ||
return get_plugin_data($this->pluginAbsolutePath, false, false); | ||
} | ||
|
||
public function removeHooks() { | ||
remove_filter('upgrader_post_install', array($this, 'clearCachedVersion')); | ||
remove_action('delete_site_transient_update_plugins', array($this, 'clearCachedVersion')); | ||
} | ||
|
||
/** | ||
* Check if the plugin file is inside the mu-plugins directory. | ||
* | ||
* @return bool | ||
*/ | ||
public function isMuPlugin() { | ||
static $cachedResult = null; | ||
|
||
if ( $cachedResult === null ) { | ||
//Convert both paths to the canonical form before comparison. | ||
$muPluginDir = realpath(WPMU_PLUGIN_DIR); | ||
$pluginPath = realpath($this->pluginAbsolutePath); | ||
|
||
$cachedResult = (strpos($pluginPath, $muPluginDir) === 0); | ||
} | ||
|
||
return $cachedResult; | ||
} | ||
} | ||
|
||
endif; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.