I've built my own plugin, hooking into a combination of
site_transient_update_plugins
transient_update_plugins
plugins_api
to automatically query, along with passing the current plugin version to a specified endpoint, which in return, grabs a temporary URL zip file from an S3 bucket based on the version provided.
This basically allows me to manage a lot of plugin versions per specific WordPress environments without pushing my private code WordPress. This all works fantastic. My endpoint after being fed ?v=1.0.0
will return a URL to a .zip file from our S3 bucket with the next 2.0.0
release, like so:
Unzipping plugin-name.zip
produces a single directory of plugin-name
, which contains the 100% correct version files. No problem there.
WordPress correctly tells me that my plugin has an update. I can see the custom details I provided from my endpoint such as description, screenshots, changelog, version, tested, required, banners, etc.
However, when I go to upgrade the version in WordPress, all works good, downloads and installs a new version (even refreshes the version from 1.0.0
to 2.0.0
), but once I reload/navigate to/from the page, it errors with:
The plugin plugin-name/plugin-name.php has been deactivated due to an error: Plugin file does not exist.
I look in the wp-content/plugins
and find my plugin has been renamed from plugin-name
to plugin-name-<random-slug>
. <random-slug>
is always different, but it ALWAYS contains the new versions code (2.0.0 in my case).
I can re-activate the plugin, but now if I run wp plugin list
from the CLI, I get plugin-name-<random-slug>
, and in my code, I explicitly rely on the correct plugin-name/plugin-name.zip
This is my first real time doing anything like this in WordPress, so a little unsure how to fix. How can I hook into the upgrade, so after it's downloaded the zip, and unpacked it, I can rename the folder back to plugin-name
?
Any ideas would be much appreciated!
add_filter('site_transient_update_plugins', array($this, 'register_update_check'));
add_filter('transient_update_plugins', array($this, 'register_update_check'));
add_filter('plugins_api', array($this, 'register_plugin_details_overrides'), 20, 3);
//
public function register_update_check($updates)
{
if (! is_object($updates)){
return $updates;
}
if (! isset($updates->response ) || ! is_array($updates->response)) {
$updates->response = array();
}
// Query WordPress plugins available
$this->response = $this->queryPluginVersions();
// Compare the version
// If returned version is greater than installed version,
// mock & return WordPress response, feeding it a .zip
// file which WordPress downloads, unzips the zip,
// completely replacing the plugin and its files
if ($this->response->version > $this->version) {
// Only mock our plugin
$updates->response['plugin-name/plugin-name.php'] = (object) array(
'slug' => 'plugin-name',
'new_version' => $this->response->version,
'url' => $this->response->url,
'package' => $this->response->download_url,
'sections' => array(
'description' => $this->response->sections->description,
'installation' => $this->response->sections->installation,
'changelog' => $this->response->sections->changelog,
'screenshots' => $this->response->sections->screenshots,
)
);
}
return $updates;
}
//
public function register_plugin_details_overrides($result, $action, $args)
{
if ($action !== 'plugin_information') {
return $result;
}
if ('plugin-name' !== $args->slug) {
return $result;
}
return (object) json_decode(json_encode($this->response), true);
}
//
public function queryPluginVersions()
{
// Build the query, appending ?v=<version>
$url = sprintf(
'%s?v=%s',
$this->endpoint_url,
$this->version
);
$remote = wp_remote_get($url, array(
'timeout' => 10,
'headers' => array(
'Accept' => 'application/json'
))
);
return json_decode($remote['body']);
}
//
Just imagine endpoint URL returns correct information, with a valid & correct v2.0.0 .zip/release
plugin-name
, so it is definitely WordPress doing it along the wayplugin-name.zip
, it’s the S3 bucket directory that contains the version and the zip name is the same throughout. Now I think of it, I need to zip it as a different name, so WP can unpack as something different (without conflict like there is now), delete the existing, and then rename the name back toplugin-name
. Does that sound about right?