stalling updates
* -------------------------------------------------------------------
*/
/**
* Rename the update directory to match the existing plugin/theme directory.
*
* When WordPress installs a plugin or theme update, it assumes that the ZIP file will contain
* exactly one directory, and that the directory name will be the same as the directory where
* the plugin or theme is currently installed.
*
* GitHub and other repositories provide ZIP downloads, but they often use directory names like
* "project-branch" or "project-tag-hash". We need to change the name to the actual plugin folder.
*
* This is a hook callback. Don't call it from a plugin.
*
* @access protected
*
* @param string $source The directory to copy to /wp-content/plugins or /wp-content/themes. Usually a subdirectory of $remoteSource.
* @param string $remoteSource WordPress has extracted the update to this directory.
* @param WP_Upgrader $upgrader
* @return string|WP_Error
*/
public function fixDirectoryName($source, $remoteSource, $upgrader) {
global $wp_filesystem;
/** @var WP_Filesystem_Base $wp_filesystem */
//Basic sanity checks.
if ( !isset($source, $remoteSource, $upgrader, $upgrader->skin, $wp_filesystem) ) {
return $source;
}
//If WordPress is upgrading anything other than our plugin/theme, leave the directory name unchanged.
if ( !$this->isBeingUpgraded($upgrader) ) {
return $source;
}
//Rename the source to match the existing directory.
$correctedSource = trailingslashit($remoteSource) . $this->directoryName . '/';
if ( $source !== $correctedSource ) {
//The update archive should contain a single directory that contains the rest of plugin/theme files.
//Otherwise, WordPress will try to copy the entire working directory ($source == $remoteSource).
//We can't rename $remoteSource because that would break WordPress code that cleans up temporary files
//after update.
if ( $this->isBadDirectoryStructure($remoteSource) ) {
return new WP_Error(
'puc-incorrect-directory-structure',
sprintf(
'The directory structure of the update is incorrect. All files should be inside ' .
'a directory named %s, not at the root of the ZIP archive.',
htmlentities($this->slug)
)
);
}
/** @var WP_Upgrader_Skin $upgrader ->skin */
$upgrader->skin->feedback(sprintf(
'Renaming %s to %s…',
'' . basename($source) . '',
'' . $this->directoryName . ''
));
if ( $wp_filesystem->move($source, $correctedSource, true) ) {
$upgrader->skin->feedback('Directory successfully renamed.');
return $correctedSource;
} else {
return new WP_Error(
'puc-rename-failed',
'Unable to rename the update to match the existing directory.'
);
}
}
return $source;
}
/**
* Is there an update being installed right now, for this plugin or theme?
*
* @param WP_Upgrader|null $upgrader The upgrader that's performing the current update.
* @return bool
*/
abstract public function isBeingUpgraded($upgrader = null);
/**
* Check for incorrect update directory structure. An update must contain a single directory,
* all other files should be inside that directory.
*
* @param string $remoteSource Directory path.
* @return bool
*/
protected function isBadDirectoryStructure($remoteSource) {
global $wp_filesystem;
/** @var WP_Filesystem_Base $wp_filesystem */
$sourceFiles = $wp_filesystem->dirlist($remoteSource);
if ( is_array($sourceFiles) ) {
$sourceFiles = array_keys($sourceFiles);
$firstFilePath = trailingslashit($remoteSource) . $sourceFiles[0];
return (count($sourceFiles) > 1) || (!$wp_filesystem->is_dir($firstFilePath));
}
//Assume it's fine.
return false;
}
/* -------------------------------------------------------------------
* DebugBar integration
* -------------------------------------------------------------------
*/
/**
* Initialize the update checker Debug Bar plugin/add-on thingy.
*/
public function maybeInitDebugBar() {
if ( class_exists('Debug_Bar', false) && file_exists(dirname(__FILE__) . '/DebugBar') ) {
$this->createDebugBarExtension();
}
}
protected function createDebugBarExtension() {
return new Puc_v4p9_DebugBar_Extension($this);
}
/**
* Display additional configuration details in the Debug Bar panel.
*
* @param Puc_v4p9_DebugBar_Panel $panel
*/
public function onDisplayConfiguration($panel) {
//Do nothing. Subclasses can use this to add additional info to the panel.
}
}
endif;