diff --git a/plugin-update-checker/.gitattributes b/plugin-update-checker/.gitattributes
new file mode 100644
index 00000000..ba74e788
--- /dev/null
+++ b/plugin-update-checker/.gitattributes
@@ -0,0 +1 @@
+/build export-ignore
diff --git a/plugin-update-checker/Puc/v5/PucFactory.php b/plugin-update-checker/Puc/v5/PucFactory.php
index 9ea49a52..3cda059d 100644
--- a/plugin-update-checker/Puc/v5/PucFactory.php
+++ b/plugin-update-checker/Puc/v5/PucFactory.php
@@ -4,7 +4,7 @@
if ( !class_exists(PucFactory::class, false) ):
- class PucFactory extends \YahnisElsts\PluginUpdateChecker\v5p0\PucFactory {
+ class PucFactory extends \YahnisElsts\PluginUpdateChecker\v5p1\PucFactory {
}
endif;
diff --git a/plugin-update-checker/Puc/v5p0/Autoloader.php b/plugin-update-checker/Puc/v5p1/Autoloader.php
similarity index 98%
rename from plugin-update-checker/Puc/v5p0/Autoloader.php
rename to plugin-update-checker/Puc/v5p1/Autoloader.php
index dfd1ee6a..ecdede90 100644
--- a/plugin-update-checker/Puc/v5p0/Autoloader.php
+++ b/plugin-update-checker/Puc/v5p1/Autoloader.php
@@ -1,6 +1,6 @@
' . htmlentities(print_r($value, true)) . '';
} else if ($value === null) {
$value = 'null
';
}
- printf('
%1$s | %2$s |
', $name, $value);
+ printf(
+ '%1$s | %2$s |
',
+ esc_html($name),
+ //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped above.
+ $value
+ );
}
}
diff --git a/plugin-update-checker/Puc/v5p0/DebugBar/PluginExtension.php b/plugin-update-checker/Puc/v5p1/DebugBar/PluginExtension.php
similarity index 90%
rename from plugin-update-checker/Puc/v5p0/DebugBar/PluginExtension.php
rename to plugin-update-checker/Puc/v5p1/DebugBar/PluginExtension.php
index feaf2ff4..21fbe0b5 100644
--- a/plugin-update-checker/Puc/v5p0/DebugBar/PluginExtension.php
+++ b/plugin-update-checker/Puc/v5p1/DebugBar/PluginExtension.php
@@ -1,8 +1,8 @@
updateChecker->triggerError(
sprintf(
- "Can't to read the Version header for '%s'. The filename is incorrect or is not a plugin.",
+ "Cannot read the Version header for '%s'. The filename is incorrect or is not a plugin.",
$this->updateChecker->pluginFile
),
E_USER_WARNING
diff --git a/plugin-update-checker/Puc/v5p0/Plugin/PluginInfo.php b/plugin-update-checker/Puc/v5p1/Plugin/PluginInfo.php
similarity index 97%
rename from plugin-update-checker/Puc/v5p0/Plugin/PluginInfo.php
rename to plugin-update-checker/Puc/v5p1/Plugin/PluginInfo.php
index 45700f90..db8e51ef 100644
--- a/plugin-update-checker/Puc/v5p0/Plugin/PluginInfo.php
+++ b/plugin-update-checker/Puc/v5p1/Plugin/PluginInfo.php
@@ -1,7 +1,7 @@
checkPeriod . 'hours';
+ //phpcs:ignore WordPress.WP.CronInterval.ChangeDetected -- WPCS fails to parse the callback.
add_filter('cron_schedules', array($this, '_addCustomSchedule'));
}
@@ -79,6 +80,7 @@ public function __construct($updateChecker, $checkPeriod, $hourlyHooks = array('
//Like WordPress itself, we check more often on certain pages.
/** @see wp_update_plugins */
add_action('load-update-core.php', array($this, 'maybeCheckForUpdates'));
+ //phpcs:ignore Squiz.PHP.CommentedOutCode.Found -- Not actually code, just file names.
//"load-update.php" and "load-plugins.php" or "load-themes.php".
$this->hourlyCheckHooks = array_merge($this->hourlyCheckHooks, $hourlyHooks);
foreach($this->hourlyCheckHooks as $hook) {
diff --git a/plugin-update-checker/Puc/v5p0/StateStore.php b/plugin-update-checker/Puc/v5p1/StateStore.php
similarity index 95%
rename from plugin-update-checker/Puc/v5p0/StateStore.php
rename to plugin-update-checker/Puc/v5p1/StateStore.php
index ec26969f..b6f6cc10 100644
--- a/plugin-update-checker/Puc/v5p0/StateStore.php
+++ b/plugin-update-checker/Puc/v5p1/StateStore.php
@@ -1,5 +1,5 @@
updateClass;
}
- if ( ($updateClass !== null) && class_exists($updateClass) ) {
- $this->update = call_user_func(array($updateClass, 'fromObject'), $state->update);
+ $factory = array($updateClass, 'fromObject');
+ if ( ($updateClass !== null) && is_callable($factory) ) {
+ $this->update = call_user_func($factory, $state->update);
}
}
}
diff --git a/plugin-update-checker/Puc/v5p0/Theme/Package.php b/plugin-update-checker/Puc/v5p1/Theme/Package.php
similarity index 93%
rename from plugin-update-checker/Puc/v5p0/Theme/Package.php
rename to plugin-update-checker/Puc/v5p1/Theme/Package.php
index d6776144..030046ba 100644
--- a/plugin-update-checker/Puc/v5p0/Theme/Package.php
+++ b/plugin-update-checker/Puc/v5p1/Theme/Package.php
@@ -1,7 +1,7 @@
10, //seconds
+ 'timeout' => wp_doing_cron() ? 10 : 3,
'headers' => array(
'Accept' => 'application/json',
),
diff --git a/plugin-update-checker/Puc/v5p0/UpgraderStatus.php b/plugin-update-checker/Puc/v5p1/UpgraderStatus.php
similarity index 98%
rename from plugin-update-checker/Puc/v5p0/UpgraderStatus.php
rename to plugin-update-checker/Puc/v5p1/UpgraderStatus.php
index f95100dd..2dc67364 100644
--- a/plugin-update-checker/Puc/v5p0/UpgraderStatus.php
+++ b/plugin-update-checker/Puc/v5p1/UpgraderStatus.php
@@ -1,5 +1,5 @@
oauth->sign($url,'GET');
}
- $options = array('timeout' => 10);
+ $options = array('timeout' => wp_doing_cron() ? 10 : 3);
if ( !empty($this->httpFilterName) ) {
$options = apply_filters($this->httpFilterName, $options);
}
diff --git a/plugin-update-checker/Puc/v5p0/Vcs/GitHubApi.php b/plugin-update-checker/Puc/v5p1/Vcs/GitHubApi.php
similarity index 72%
rename from plugin-update-checker/Puc/v5p0/Vcs/GitHubApi.php
rename to plugin-update-checker/Puc/v5p1/Vcs/GitHubApi.php
index a1ca4c58..364584b8 100644
--- a/plugin-update-checker/Puc/v5p0/Vcs/GitHubApi.php
+++ b/plugin-update-checker/Puc/v5p1/Vcs/GitHubApi.php
@@ -1,11 +1,15 @@
api('/repos/:user/:repo/releases/latest');
- if ( is_wp_error($release) || !is_object($release) || !isset($release->tag_name) ) {
- return null;
+ //The "latest release" endpoint returns one release and always skips pre-releases,
+ //so we can only use it if that's compatible with the current filter settings.
+ if (
+ $this->shouldSkipPreReleases()
+ && (
+ ($this->releaseFilterMaxReleases === 1) || !$this->hasCustomReleaseFilter()
+ )
+ ) {
+ //Just get the latest release.
+ $release = $this->api('/repos/:user/:repo/releases/latest');
+ if ( is_wp_error($release) || !is_object($release) || !isset($release->tag_name) ) {
+ return null;
+ }
+ $foundReleases = array($release);
+ } else {
+ //Get a list of the most recent releases.
+ $foundReleases = $this->api(
+ '/repos/:user/:repo/releases',
+ array('per_page' => $this->releaseFilterMaxReleases)
+ );
+ if ( is_wp_error($foundReleases) || !is_array($foundReleases) ) {
+ return null;
+ }
}
- $reference = new Reference(array(
- 'name' => $release->tag_name,
- 'version' => ltrim($release->tag_name, 'v'), //Remove the "v" prefix from "v1.2.3".
- 'downloadUrl' => $release->zipball_url,
- 'updated' => $release->created_at,
- 'apiResponse' => $release,
- ));
+ foreach ($foundReleases as $release) {
+ //Always skip drafts.
+ if ( isset($release->draft) && !empty($release->draft) ) {
+ continue;
+ }
- if ( isset($release->assets[0]) ) {
- $reference->downloadCount = $release->assets[0]->download_count;
- }
+ //Skip pre-releases unless specifically included.
+ if (
+ $this->shouldSkipPreReleases()
+ && isset($release->prerelease)
+ && !empty($release->prerelease)
+ ) {
+ continue;
+ }
+
+ $versionNumber = ltrim($release->tag_name, 'v'); //Remove the "v" prefix from "v1.2.3".
+
+ //Custom release filtering.
+ if ( !$this->matchesCustomReleaseFilter($versionNumber, $release) ) {
+ continue;
+ }
+
+ $reference = new Reference(array(
+ 'name' => $release->tag_name,
+ 'version' => $versionNumber,
+ 'downloadUrl' => $release->zipball_url,
+ 'updated' => $release->created_at,
+ 'apiResponse' => $release,
+ ));
+
+ if ( isset($release->assets[0]) ) {
+ $reference->downloadCount = $release->assets[0]->download_count;
+ }
- if ( $this->releaseAssetsEnabled && isset($release->assets, $release->assets[0]) ) {
- //Use the first release asset that matches the specified regular expression.
- $matchingAssets = array_values(array_filter($release->assets, array($this, 'matchesAssetFilter')));
- if ( !empty($matchingAssets) ) {
- if ( $this->isAuthenticationEnabled() ) {
- /**
- * Keep in mind that we'll need to add an "Accept" header to download this asset.
- *
- * @see setUpdateDownloadHeaders()
- */
- $reference->downloadUrl = $matchingAssets[0]->url;
+ if ( $this->releaseAssetsEnabled ) {
+ //Use the first release asset that matches the specified regular expression.
+ if ( isset($release->assets, $release->assets[0]) ) {
+ $matchingAssets = array_values(array_filter($release->assets, array($this, 'matchesAssetFilter')));
} else {
- //It seems that browser_download_url only works for public repositories.
- //Using an access_token doesn't help. Maybe OAuth would work?
- $reference->downloadUrl = $matchingAssets[0]->browser_download_url;
+ $matchingAssets = array();
}
- $reference->downloadCount = $matchingAssets[0]->download_count;
+ if ( !empty($matchingAssets) ) {
+ if ( $this->isAuthenticationEnabled() ) {
+ /**
+ * Keep in mind that we'll need to add an "Accept" header to download this asset.
+ *
+ * @see setUpdateDownloadHeaders()
+ */
+ $reference->downloadUrl = $matchingAssets[0]->url;
+ } else {
+ //It seems that browser_download_url only works for public repositories.
+ //Using an access_token doesn't help. Maybe OAuth would work?
+ $reference->downloadUrl = $matchingAssets[0]->browser_download_url;
+ }
+
+ $reference->downloadCount = $matchingAssets[0]->download_count;
+ } else if ( $this->releaseAssetPreference === Api::REQUIRE_RELEASE_ASSETS ) {
+ //None of the assets match the filter, and we're not allowed
+ //to fall back to the auto-generated source ZIP.
+ return null;
+ }
}
- }
- if ( !empty($release->body) ) {
- $reference->changelog = Parsedown::instance()->text($release->body);
+ if ( !empty($release->body) ) {
+ $reference->changelog = Parsedown::instance()->text($release->body);
+ }
+
+ return $reference;
}
- return $reference;
+ return null;
}
/**
@@ -205,7 +248,7 @@ protected function api($url, $queryParams = array()) {
$baseUrl = $url;
$url = $this->buildApiUrl($url, $queryParams);
- $options = array('timeout' => 10);
+ $options = array('timeout' => wp_doing_cron() ? 10 : 3);
if ( $this->isAuthenticationEnabled() ) {
$options['headers'] = array('Authorization' => $this->getAuthorizationHeader());
}
@@ -315,7 +358,7 @@ public function setAuthentication($credentials) {
protected function getUpdateDetectionStrategies($configBranch) {
$strategies = array();
- if ( $configBranch === 'master' || $configBranch === 'main' ) {
+ if ( $configBranch === 'master' || $configBranch === 'main') {
//Use the latest release.
$strategies[self::STRATEGY_LATEST_RELEASE] = array($this, 'getLatestRelease');
//Failing that, use the tag with the highest version number.
@@ -323,7 +366,7 @@ protected function getUpdateDetectionStrategies($configBranch) {
}
//Alternatively, just use the branch itself.
- $strategies[self::STRATEGY_BRANCH] = function() use ($configBranch) {
+ $strategies[self::STRATEGY_BRANCH] = function () use ($configBranch) {
return $this->getBranch($configBranch);
};
@@ -331,43 +374,29 @@ protected function getUpdateDetectionStrategies($configBranch) {
}
/**
- * Enable updating via release assets.
- *
- * If the latest release contains no usable assets, the update checker
- * will fall back to using the automatically generated ZIP archive.
- *
- * Private repositories will only work with WordPress 3.7 or later.
+ * Get the unchanging part of a release asset URL. Used to identify download attempts.
*
- * @param string|null $fileNameRegex Optional. Use only those assets where the file name matches this regex.
+ * @return string
*/
- public function enableReleaseAssets($fileNameRegex = null) {
- $this->releaseAssetsEnabled = true;
- $this->assetFilterRegex = $fileNameRegex;
- $this->assetApiBaseUrl = sprintf(
+ protected function getAssetApiBaseUrl() {
+ return sprintf(
'//api.github.com/repos/%1$s/%2$s/releases/assets/',
$this->userName,
$this->repositoryName
);
}
- /**
- * Does this asset match the file name regex?
- *
- * @param \stdClass $releaseAsset
- * @return bool
- */
- protected function matchesAssetFilter($releaseAsset) {
- if ( $this->assetFilterRegex === null ) {
- //The default is to accept all assets.
- return true;
+ protected function getFilterableAssetName($releaseAsset) {
+ if ( isset($releaseAsset->name) ) {
+ return $releaseAsset->name;
}
- return isset($releaseAsset->name) && preg_match($this->assetFilterRegex, $releaseAsset->name);
+ return null;
}
/**
- * @internal
* @param bool $result
* @return bool
+ * @internal
*/
public function addHttpRequestFilter($result) {
if ( !$this->downloadFilterAdded && $this->isAuthenticationEnabled() ) {
@@ -383,6 +412,7 @@ public function addHttpRequestFilter($result) {
* Set the HTTP headers that are necessary to download updates from private repositories.
*
* See GitHub docs:
+ *
* @link https://developer.github.com/v3/repos/releases/#get-a-single-release-asset
* @link https://developer.github.com/v3/auth/#basic-authentication
*
@@ -393,7 +423,7 @@ public function addHttpRequestFilter($result) {
*/
public function setUpdateDownloadHeaders($requestArgs, $url = '') {
//Is WordPress trying to download one of our release assets?
- if ( $this->releaseAssetsEnabled && (strpos($url, $this->assetApiBaseUrl) !== false) ) {
+ if ( $this->releaseAssetsEnabled && (strpos($url, $this->getAssetApiBaseUrl()) !== false) ) {
$requestArgs['headers']['Accept'] = 'application/octet-stream';
}
//Use Basic authentication, but only if the download is from our repository.
@@ -409,9 +439,9 @@ public function setUpdateDownloadHeaders($requestArgs, $url = '') {
* the authorization header to other hosts. We don't want that because it breaks
* AWS downloads and can leak authorization information.
*
- * @internal
* @param string $location
* @param array $headers
+ * @internal
*/
public function removeAuthHeaderFromRedirects(&$location, &$headers) {
$repoApiBaseUrl = $this->buildApiUrl('/repos/:user/:repo/', array());
diff --git a/plugin-update-checker/Puc/v5p0/Vcs/GitLabApi.php b/plugin-update-checker/Puc/v5p1/Vcs/GitLabApi.php
similarity index 76%
rename from plugin-update-checker/Puc/v5p0/Vcs/GitLabApi.php
rename to plugin-update-checker/Puc/v5p1/Vcs/GitLabApi.php
index b43b4cef..663c2e7c 100644
--- a/plugin-update-checker/Puc/v5p0/Vcs/GitLabApi.php
+++ b/plugin-update-checker/Puc/v5p1/Vcs/GitLabApi.php
@@ -1,9 +1,13 @@
api('/:id/releases');
+ $releases = $this->api('/:id/releases', array('per_page' => $this->releaseFilterMaxReleases));
if ( is_wp_error($releases) || empty($releases) || !is_array($releases) ) {
return null;
}
foreach ($releases as $release) {
- if ( true !== $release->upcoming_release ) {
- break 1; //Break the loop on the first release we find that isn't an upcoming release
+ if (
+ //Skip invalid/unsupported releases.
+ !is_object($release)
+ || !isset($release->tag_name)
+ //Skip upcoming releases.
+ || (
+ !empty($release->upcoming_release)
+ && $this->shouldSkipPreReleases()
+ )
+ ) {
+ continue;
}
- }
- if ( is_wp_error($release) || !is_object($release) || !isset($release->tag_name) ) {
- return null;
- }
- $reference = new Reference(array(
- 'name' => $release->tag_name,
- 'version' => ltrim($release->tag_name, 'v'), //Remove the "v" prefix from "v1.2.3".
- 'downloadUrl' => '',
- 'updated' => $release->released_at,
- 'apiResponse' => $release,
- ));
- $download_url = false;
-
- if ( $this->releasePackageEnabled && isset($release->assets, $release->assets->links) ) {
- /**
- * Use the first asset LINK that is a zip format file generated by a Gitlab Release Pipeline
- *
- * @link https://gist.github.com/timwiel/9dfd3526c768efad4973254085e065ce
- */
- foreach ($release->assets->links as $link) {
- //TODO: Check the "format" property instead of the URL suffix.
- if ( 'zip' === substr($link->url, -3) ) {
- $download_url = $link->url;
- break 1;
- }
+ $versionNumber = ltrim($release->tag_name, 'v'); //Remove the "v" prefix from "v1.2.3".
+
+ //Apply custom filters.
+ if ( !$this->matchesCustomReleaseFilter($versionNumber, $release) ) {
+ continue;
}
- if ( empty( $download_url ) ) {
+
+ $downloadUrl = $this->findReleaseDownloadUrl($release);
+ if ( empty($downloadUrl) ) {
+ //The latest release doesn't have valid download URL.
return null;
}
- if ( ! empty( $this->accessToken ) ) {
- $download_url = add_query_arg('private_token', $this->accessToken, $download_url);
+
+ if ( !empty($this->accessToken) ) {
+ $downloadUrl = add_query_arg('private_token', $this->accessToken, $downloadUrl);
}
- $reference->downloadUrl = $download_url;
- return $reference;
-
- } elseif ( isset($release->assets) ) {
- /**
- * Use the first asset SOURCE file that is a zip format from a Gitlab Release which should be a zip file
- */
- foreach ($release->assets->sources as $source) {
- if ( 'zip' === $source->format ) {
- $download_url = $source->url;
- break 1;
+
+ return new Reference(array(
+ 'name' => $release->tag_name,
+ 'version' => $versionNumber,
+ 'downloadUrl' => $downloadUrl,
+ 'updated' => $release->released_at,
+ 'apiResponse' => $release,
+ ));
+ }
+
+ return null;
+ }
+
+ /**
+ * @param object $release
+ * @return string|null
+ */
+ protected function findReleaseDownloadUrl($release) {
+ if ( $this->releaseAssetsEnabled ) {
+ if ( isset($release->assets, $release->assets->links) ) {
+ //Use the first asset link where the URL matches the filter.
+ foreach ($release->assets->links as $link) {
+ if ( $this->matchesAssetFilter($link) ) {
+ return $link->url;
+ }
}
}
- if ( empty( $download_url ) ) {
+
+ if ( $this->releaseAssetPreference === Api::REQUIRE_RELEASE_ASSETS ) {
+ //Falling back to source archives is not allowed, so give up.
return null;
}
- if ( ! empty( $this->accessToken ) ) {
- $download_url = add_query_arg('private_token', $this->accessToken, $download_url);
- }
- $reference->downloadUrl = $download_url;
- return $reference;
+ }
+ //Use the first source code archive that's in ZIP format.
+ foreach ($release->assets->sources as $source) {
+ if ( isset($source->format) && ($source->format === 'zip') ) {
+ return $source->url;
+ }
}
- //If we get this far without a return then obviosuly noi release download urls were found
return null;
- }
+ }
/**
* Get the tag that looks like the highest version number.
@@ -251,7 +260,7 @@ protected function api($url, $queryParams = array()) {
$baseUrl = $url;
$url = $this->buildApiUrl($url, $queryParams);
- $options = array('timeout' => 10);
+ $options = array('timeout' => wp_doing_cron() ? 10 : 3);
if ( !empty($this->httpFilterName) ) {
$options = apply_filters($this->httpFilterName, $options);
}
@@ -365,7 +374,7 @@ protected function getUpdateDetectionStrategies($configBranch) {
$strategies[self::STRATEGY_LATEST_TAG] = array($this, 'getLatestTag');
}
- $strategies[self::STRATEGY_BRANCH] = function() use ($configBranch) {
+ $strategies[self::STRATEGY_BRANCH] = function () use ($configBranch) {
return $this->getBranch($configBranch);
};
@@ -377,16 +386,29 @@ public function setAuthentication($credentials) {
$this->accessToken = is_string($credentials) ? $credentials : null;
}
- public function enableReleaseAssets() {
- $this->releaseAssetsEnabled = true;
- $this->releasePackageEnabled = false;
- }
-
+ /**
+ * Use release assets that link to GitLab generic packages (e.g. .zip files)
+ * instead of automatically generated source archives.
+ *
+ * This is included for backwards compatibility with older versions of PUC.
+ *
+ * @return void
+ * @deprecated Use enableReleaseAssets() instead.
+ * @noinspection PhpUnused -- Public API
+ */
public function enableReleasePackages() {
- $this->releaseAssetsEnabled = false;
- $this->releasePackageEnabled = true;
+ $this->enableReleaseAssets(
+ /** @lang RegExp */ '/\.zip($|[?])/i',
+ Api::REQUIRE_RELEASE_ASSETS
+ );
}
+ protected function getFilterableAssetName($releaseAsset) {
+ if ( isset($releaseAsset->url) ) {
+ return $releaseAsset->url;
+ }
+ return null;
+ }
}
endif;
diff --git a/plugin-update-checker/Puc/v5p0/Vcs/PluginUpdateChecker.php b/plugin-update-checker/Puc/v5p1/Vcs/PluginUpdateChecker.php
similarity index 98%
rename from plugin-update-checker/Puc/v5p0/Vcs/PluginUpdateChecker.php
rename to plugin-update-checker/Puc/v5p1/Vcs/PluginUpdateChecker.php
index aa1dfae9..082a847f 100644
--- a/plugin-update-checker/Puc/v5p0/Vcs/PluginUpdateChecker.php
+++ b/plugin-update-checker/Puc/v5p1/Vcs/PluginUpdateChecker.php
@@ -1,8 +1,8 @@
releaseAssetsEnabled = true;
+ $this->assetFilterRegex = $nameRegex;
+ $this->releaseAssetPreference = $preference;
+ }
+
+ /**
+ * Disable release assets.
+ *
+ * @return void
+ * @noinspection PhpUnused -- Public API
+ */
+ public function disableReleaseAssets() {
+ $this->releaseAssetsEnabled = false;
+ $this->assetFilterRegex = null;
+ }
+
+ /**
+ * Does the specified asset match the name regex?
+ *
+ * @param mixed $releaseAsset Data type and structure depend on the host/API.
+ * @return bool
+ */
+ protected function matchesAssetFilter($releaseAsset) {
+ if ( $this->assetFilterRegex === null ) {
+ //The default is to accept all assets.
+ return true;
+ }
+
+ $name = $this->getFilterableAssetName($releaseAsset);
+ if ( !is_string($name) ) {
+ return false;
+ }
+ return (bool)preg_match($this->assetFilterRegex, $releaseAsset->name);
+ }
+
+ /**
+ * Get the part of asset data that will be checked against the filter regex.
+ *
+ * @param mixed $releaseAsset
+ * @return string|null
+ */
+ abstract protected function getFilterableAssetName($releaseAsset);
+ }
+
+endif;
\ No newline at end of file
diff --git a/plugin-update-checker/Puc/v5p1/Vcs/ReleaseFilteringFeature.php b/plugin-update-checker/Puc/v5p1/Vcs/ReleaseFilteringFeature.php
new file mode 100644
index 00000000..12ef54ed
--- /dev/null
+++ b/plugin-update-checker/Puc/v5p1/Vcs/ReleaseFilteringFeature.php
@@ -0,0 +1,108 @@
+ 100 ) {
+ throw new \InvalidArgumentException(sprintf(
+ 'The max number of releases is too high (%d). It must be 100 or less.',
+ $maxReleases
+ ));
+ } else if ( $maxReleases < 1 ) {
+ throw new \InvalidArgumentException(sprintf(
+ 'The max number of releases is too low (%d). It must be at least 1.',
+ $maxReleases
+ ));
+ }
+
+ $this->releaseFilterCallback = $callback;
+ $this->releaseFilterByType = $releaseTypes;
+ $this->releaseFilterMaxReleases = $maxReleases;
+ return $this;
+ }
+
+ /**
+ * Filter releases by their version number.
+ *
+ * @param string $regex A regular expression. The release version number must match this regex.
+ * @param int $releaseTypes
+ * @param int $maxReleasesToExamine
+ * @return $this
+ * @noinspection PhpUnused -- Public API
+ */
+ public function setReleaseVersionFilter(
+ $regex,
+ $releaseTypes = Api::RELEASE_FILTER_SKIP_PRERELEASE,
+ $maxReleasesToExamine = 20
+ ) {
+ return $this->setReleaseFilter(
+ function ($versionNumber) use ($regex) {
+ return (preg_match($regex, $versionNumber) === 1);
+ },
+ $releaseTypes,
+ $maxReleasesToExamine
+ );
+ }
+
+ /**
+ * @param string $versionNumber The detected release version number.
+ * @param object $releaseObject Varies depending on the host/API.
+ * @return bool
+ */
+ protected function matchesCustomReleaseFilter($versionNumber, $releaseObject) {
+ if ( !is_callable($this->releaseFilterCallback) ) {
+ return true; //No custom filter.
+ }
+ return call_user_func($this->releaseFilterCallback, $versionNumber, $releaseObject);
+ }
+
+ /**
+ * @return bool
+ */
+ protected function shouldSkipPreReleases() {
+ //Maybe this could be a bitfield in the future, if we need to support
+ //more release types.
+ return ($this->releaseFilterByType !== Api::RELEASE_FILTER_ALL);
+ }
+
+ /**
+ * @return bool
+ */
+ protected function hasCustomReleaseFilter() {
+ return isset($this->releaseFilterCallback) && is_callable($this->releaseFilterCallback);
+ }
+ }
+
+endif;
\ No newline at end of file
diff --git a/plugin-update-checker/Puc/v5p0/Vcs/ThemeUpdateChecker.php b/plugin-update-checker/Puc/v5p1/Vcs/ThemeUpdateChecker.php
similarity index 94%
rename from plugin-update-checker/Puc/v5p0/Vcs/ThemeUpdateChecker.php
rename to plugin-update-checker/Puc/v5p1/Vcs/ThemeUpdateChecker.php
index b8624c6b..c871ce9f 100644
--- a/plugin-update-checker/Puc/v5p0/Vcs/ThemeUpdateChecker.php
+++ b/plugin-update-checker/Puc/v5p1/Vcs/ThemeUpdateChecker.php
@@ -1,9 +1,9 @@
setBranch('stable-branch-name');
- ```
- - Caveats:
- - If you set the branch to `main` (the default) or `master` (the historical default), the update checker will look for recent releases and tags first. It'll only use the `main` or `master` branch if it doesn't find anything else suitable.
-
-2. **GitLab Releases using Generic Packages**:
- - Use a Gitlab CI/CD Pipeline to automatically generate your update on release using a Generic Package. The benefit of using Generic Package assets over the Source Code assets is that the code can already be built and production ready.
- - Add the following code:
- ```php
- //Add the following code to your main plugin file or `functions.php` file to check for a new update from releases using generic packages
- $myUpdateChecker->getVcsApi()->enableReleasePackages();
- ```
- - PUC will periodically check the release version (i.e. the tag name of the release) and will display a notification if the release is a greater version than the installed version.
- - The release tag name should loosely follow [SemVer](https://semver.org/) but these are all valid release names: `v1.2.3`, `v1.2-foo`, `1.2.3_rc1-ABC`, `1.2.3.4.5` However, be warned that it's not smart enough to filter out alpha/beta/RC versions. If that's a problem, you might want to use GitLab branches instead.
- - For more information about *Gitlab Release Generic Packages* refer to the following links:
+
+A GitLab repository can be checked for updates in 3 different ways.
+
+- **GitLab releases**
+
+ Create a new release using the "Releases" feature on GitLab. The tag name should match the version number. You can add a `v` prefix to the tag, like `v1.2.3`. Releases that are marked as ["Upcoming Release"](https://docs.gitlab.com/ee/user/project/releases/index.html#upcoming-releases) will be automatically ignored.
+
+ If you want to use custom release assets, call the `enableReleaseAssets()` method after creating the update checker instance:
+ ```php
+ $myUpdateChecker->getVcsApi()->enableReleaseAssets();
+ ```
+
+ By default, PUC will use the first available asset link, regardless of type. You can pass a regular expression to `enableReleaseAssets()` to make it pick the first link where the URL matches the regex. For example:
+ ```php
+ $myUpdateChecker->getVcsApi()->enableReleaseAssets('/\.zip($|[?])/i');
+ ```
+
+ **Tip:** You can use a Gitlab CI/CD Pipeline to automatically generate your update on release using a Generic Package. For more information about generic packages, refer to the following links:
- [Gitlab CI/CD Release Documentation](https://docs.gitlab.com/ee/user/project/releases/#create-release-from-gitlab-ci)
- [Gitlab Release Assets as Generic Package Documentation](https://gitlab.com/gitlab-org/release-cli/-/tree/master/docs/examples/release-assets-as-generic-package/)
- [Example .gitlab-ci.yml file using Release Generic Packages for generating a update package from the Sensei-LMS wordpress plugin](https://gist.github.com/timwiel/9dfd3526c768efad4973254085e065ce)
+- **Tags**
-3. **GitLab Releases using Source Code Assets**:
- - Create a new release using the "Releases" feature on Gitlab.
- - Add the following code:
- ```php
- //Add the following code to your main plugin file or `functions.php` file to check for a new update from releases using release assets
- $myUpdateChecker->getVcsApi()->enableReleaseAssets();
- ```
- - PUC will periodically check the release version (based on release tag name) and display a notification if the release version is greater than the installed version.
- - The release name should loosely follow [SemVer](https://semver.org/) but these are all valid release names: `v1.2.3`, `v1.2-foo`, `1.2.3_rc1-ABC`, `1.2.3.4.5` However, be warned that it's not smart enough to filter out alpha/beta/RC versions. If that's a problem, you might want to use GitLab branches instead.
+ To release version 1.2.3, create a new Git tag named `v1.2.3` or `1.2.3`. The update checker will look at recent tags and use the one that looks like the highest version number.
+
+ PUC doesn't require strict adherence to [SemVer](https://semver.org/). However, be warned that it's not smart enough to filter out alpha/beta/RC versions. If that's a problem, you might want to use GitLab branches instead.
+- **Stable branch**
-4. **Tags** (this is the default option):
- - To release version 1.2.3, create a new Git tag named `v1.2.3` or `1.2.3`.
- - Optionally, add the following code:
- ```php
- //Add the following code to your main plugin file or `functions.php` file to check for updates from the default branch
- $myUpdateChecker->setBranch('master'); //or 'main'
- ```
- - PUC doesn't require strict adherence to [SemVer](https://semver.org/). These are all valid tag names: `v1.2.3`, `v1.2-foo`, `1.2.3_rc1-ABC`, `1.2.3.4.5`. However, be warned that it's not smart enough to filter out alpha/beta/RC versions. If that's a problem, you might want to use GitLab branches instead.
+ Point the update checker at any stable, production-ready branch:
+ ```php
+ $myUpdateChecker->setBranch('stable-branch-name');
+ ```
+ PUC will periodically check the `Version` header in the main plugin file or `style.css` and display a notification if it's greater than the installed version. Caveat: Even if you set the branch to `main` (the default) or `master` (the historical default), the update checker will still look for recent releases and tags first.
Migrating from 4.x
------------------
@@ -358,14 +347,14 @@ Other classes have also been renamed, usually by simply removing the `Puc_vXpY_`
| Old class name | New class name |
|-------------------------------------|----------------------------------------------------------------|
| `Puc_v4_Factory` | `YahnisElsts\PluginUpdateChecker\v5\PucFactory` |
-| `Puc_v4p13_Factory` | `YahnisElsts\PluginUpdateChecker\v5p0\PucFactory` |
-| `Puc_v4p13_Plugin_UpdateChecker` | `YahnisElsts\PluginUpdateChecker\v5p0\Plugin\UpdateChecker` |
-| `Puc_v4p13_Theme_UpdateChecker` | `YahnisElsts\PluginUpdateChecker\v5p0\Theme\UpdateChecker` |
-| `Puc_v4p13_Vcs_PluginUpdateChecker` | `YahnisElsts\PluginUpdateChecker\v5p0\Vcs\PluginUpdateChecker` |
-| `Puc_v4p13_Vcs_ThemeUpdateChecker` | `YahnisElsts\PluginUpdateChecker\v5p0\Vcs\ThemeUpdateChecker` |
-| `Puc_v4p13_Vcs_GitHubApi` | `YahnisElsts\PluginUpdateChecker\v5p0\Vcs\GitHubApi` |
-| `Puc_v4p13_Vcs_GitLabApi` | `YahnisElsts\PluginUpdateChecker\v5p0\Vcs\GitLabApi` |
-| `Puc_v4p13_Vcs_BitBucketApi` | `YahnisElsts\PluginUpdateChecker\v5p0\Vcs\BitBucketApi` |
+| `Puc_v4p13_Factory` | `YahnisElsts\PluginUpdateChecker\v5p1\PucFactory` |
+| `Puc_v4p13_Plugin_UpdateChecker` | `YahnisElsts\PluginUpdateChecker\v5p1\Plugin\UpdateChecker` |
+| `Puc_v4p13_Theme_UpdateChecker` | `YahnisElsts\PluginUpdateChecker\v5p1\Theme\UpdateChecker` |
+| `Puc_v4p13_Vcs_PluginUpdateChecker` | `YahnisElsts\PluginUpdateChecker\v5p1\Vcs\PluginUpdateChecker` |
+| `Puc_v4p13_Vcs_ThemeUpdateChecker` | `YahnisElsts\PluginUpdateChecker\v5p1\Vcs\ThemeUpdateChecker` |
+| `Puc_v4p13_Vcs_GitHubApi` | `YahnisElsts\PluginUpdateChecker\v5p1\Vcs\GitHubApi` |
+| `Puc_v4p13_Vcs_GitLabApi` | `YahnisElsts\PluginUpdateChecker\v5p1\Vcs\GitLabApi` |
+| `Puc_v4p13_Vcs_BitBucketApi` | `YahnisElsts\PluginUpdateChecker\v5p1\Vcs\BitBucketApi` |
License Management
------------------
diff --git a/plugin-update-checker/composer.json b/plugin-update-checker/composer.json
index 0589f014..1a71ce83 100644
--- a/plugin-update-checker/composer.json
+++ b/plugin-update-checker/composer.json
@@ -18,6 +18,6 @@
"ext-json": "*"
},
"autoload": {
- "files": ["load-v5p0.php"]
+ "files": ["load-v5p1.php"]
}
}
diff --git a/plugin-update-checker/examples/plugin.json b/plugin-update-checker/examples/plugin.json
index fea211a1..946b7307 100644
--- a/plugin-update-checker/examples/plugin.json
+++ b/plugin-update-checker/examples/plugin.json
@@ -1,52 +1,52 @@
-{
- "name": "My Example Plugin",
- "version": "2.0",
- "download_url": "http://example.com/updates/example-plugin.zip",
-
- "homepage": "http://example.com/",
- "requires": "4.5",
- "tested": "4.8",
- "last_updated": "2017-01-01 16:17:00",
- "upgrade_notice": "Here's why you should upgrade...",
-
- "author": "Janis Elsts",
- "author_homepage": "http://example.com/",
-
- "sections": {
- "description": "(Required) Plugin description. Basic HTML can be used in all sections.",
- "installation": "(Recommended) Installation instructions.",
- "changelog": "(Recommended) Changelog. This section will be displayed by default when the user clicks 'View version x.y.z details'.
",
- "custom_section": "This is a custom section labeled 'Custom Section'."
- },
-
- "icons" : {
- "1x" : "http://w-shadow.com/files/external-update-example/assets/icon-128x128.png",
- "2x" : "http://w-shadow.com/files/external-update-example/assets/icon-256x256.png"
- },
-
- "banners": {
- "low": "http://w-shadow.com/files/external-update-example/assets/banner-772x250.png",
- "high": "http://w-shadow.com/files/external-update-example/assets/banner-1544x500.png"
- },
-
- "translations": [
- {
- "language": "fr_FR",
- "version": "4.0",
- "updated": "2016-04-22 23:22:42",
- "package": "http://example.com/updates/translations/french-language-pack.zip"
- },
- {
- "language": "de_DE",
- "version": "5.0",
- "updated": "2016-04-22 23:22:42",
- "package": "http://example.com/updates/translations/german-language-pack.zip"
- }
- ],
-
- "rating": 90,
- "num_ratings": 123,
-
- "downloaded": 1234,
- "active_installs": 12345
+{
+ "name": "My Example Plugin",
+ "version": "2.0",
+ "download_url": "http://example.com/updates/example-plugin.zip",
+
+ "homepage": "http://example.com/",
+ "requires": "4.5",
+ "tested": "4.8",
+ "last_updated": "2017-01-01 16:17:00",
+ "upgrade_notice": "Here's why you should upgrade...",
+
+ "author": "Janis Elsts",
+ "author_homepage": "http://example.com/",
+
+ "sections": {
+ "description": "(Required) Plugin description. Basic HTML can be used in all sections.",
+ "installation": "(Recommended) Installation instructions.",
+ "changelog": "(Recommended) Changelog. This section will be displayed by default when the user clicks 'View version x.y.z details'.
",
+ "custom_section": "This is a custom section labeled 'Custom Section'."
+ },
+
+ "icons" : {
+ "1x" : "http://w-shadow.com/files/external-update-example/assets/icon-128x128.png",
+ "2x" : "http://w-shadow.com/files/external-update-example/assets/icon-256x256.png"
+ },
+
+ "banners": {
+ "low": "http://w-shadow.com/files/external-update-example/assets/banner-772x250.png",
+ "high": "http://w-shadow.com/files/external-update-example/assets/banner-1544x500.png"
+ },
+
+ "translations": [
+ {
+ "language": "fr_FR",
+ "version": "4.0",
+ "updated": "2016-04-22 23:22:42",
+ "package": "http://example.com/updates/translations/french-language-pack.zip"
+ },
+ {
+ "language": "de_DE",
+ "version": "5.0",
+ "updated": "2016-04-22 23:22:42",
+ "package": "http://example.com/updates/translations/german-language-pack.zip"
+ }
+ ],
+
+ "rating": 90,
+ "num_ratings": 123,
+
+ "downloaded": 1234,
+ "active_installs": 12345
}
\ No newline at end of file
diff --git a/plugin-update-checker/examples/theme.json b/plugin-update-checker/examples/theme.json
index df6c8c79..0e080725 100644
--- a/plugin-update-checker/examples/theme.json
+++ b/plugin-update-checker/examples/theme.json
@@ -1,5 +1,5 @@
-{
- "version": "2.0",
- "details_url": "http://example.com/version-2.0-details.html",
- "download_url": "http://example.com/example-theme-2.0.zip"
+{
+ "version": "2.0",
+ "details_url": "http://example.com/version-2.0-details.html",
+ "download_url": "http://example.com/example-theme-2.0.zip"
}
\ No newline at end of file
diff --git a/plugin-update-checker/js/debug-bar.js b/plugin-update-checker/js/debug-bar.js
index 9cb65a01..80f53f11 100644
--- a/plugin-update-checker/js/debug-bar.js
+++ b/plugin-update-checker/js/debug-bar.js
@@ -14,6 +14,8 @@ jQuery(function($) {
_wpnonce: panel.data('nonce')
},
function(data) {
+ //The response contains HTML that should already be escaped in server-side code.
+ //phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
responseBox.html(data);
},
'html'
diff --git a/plugin-update-checker/languages/plugin-update-checker.pot b/plugin-update-checker/languages/plugin-update-checker.pot
index ec7bc19a..edc8de4f 100644
--- a/plugin-update-checker/languages/plugin-update-checker.pot
+++ b/plugin-update-checker/languages/plugin-update-checker.pot
@@ -17,33 +17,33 @@ msgstr ""
"X-Poedit-KeywordsList: __;_e;_x:1,2c;_x\n"
"X-Poedit-SearchPath-0: .\n"
-#: Puc/v5p0/Plugin/Ui.php:128
+#: Puc/v5p1/Plugin/Ui.php:128
msgid "Check for updates"
msgstr ""
-#: Puc/v5p0/Plugin/Ui.php:214
+#: Puc/v5p1/Plugin/Ui.php:214
#, php-format
msgctxt "the plugin title"
msgid "The %s plugin is up to date."
msgstr ""
-#: Puc/v5p0/Plugin/Ui.php:216
+#: Puc/v5p1/Plugin/Ui.php:216
#, php-format
msgctxt "the plugin title"
msgid "A new version of the %s plugin is available."
msgstr ""
-#: Puc/v5p0/Plugin/Ui.php:218
+#: Puc/v5p1/Plugin/Ui.php:218
#, php-format
msgctxt "the plugin title"
msgid "Could not determine if updates are available for %s."
msgstr ""
-#: Puc/v5p0/Plugin/Ui.php:224
+#: Puc/v5p1/Plugin/Ui.php:224
#, php-format
msgid "Unknown update checker status \"%s\""
msgstr ""
-#: Puc/v5p0/Vcs/PluginUpdateChecker.php:100
+#: Puc/v5p1/Vcs/PluginUpdateChecker.php:100
msgid "There is no changelog available."
msgstr ""
diff --git a/plugin-update-checker/load-v5p0.php b/plugin-update-checker/load-v5p1.php
similarity index 80%
rename from plugin-update-checker/load-v5p0.php
rename to plugin-update-checker/load-v5p1.php
index 7998cbfe..83cebcb6 100644
--- a/plugin-update-checker/load-v5p0.php
+++ b/plugin-update-checker/load-v5p1.php
@@ -1,14 +1,14 @@
$pucVersionedClass
) {
- MajorFactory::addVersion($pucGeneralClass, $pucVersionedClass, '5.0');
+ MajorFactory::addVersion($pucGeneralClass, $pucVersionedClass, '5.1');
//Also add it to the minor-version factory in case the major-version factory
//was already defined by another, older version of the update checker.
- MinorFactory::addVersion($pucGeneralClass, $pucVersionedClass, '5.0');
+ MinorFactory::addVersion($pucGeneralClass, $pucVersionedClass, '5.1');
}
diff --git a/plugin-update-checker/phpcs.xml b/plugin-update-checker/phpcs.xml
new file mode 100644
index 00000000..e8260b99
--- /dev/null
+++ b/plugin-update-checker/phpcs.xml
@@ -0,0 +1,21 @@
+
+
+ PHPCS settings for Plugin Update Checker
+
+
+
+
+
+
+
+ ./
+
+
+
+
+
+
+
+
+ ^vendor/*
+
diff --git a/plugin-update-checker/plugin-update-checker.php b/plugin-update-checker/plugin-update-checker.php
index 1d892f3f..ebf10bc7 100644
--- a/plugin-update-checker/plugin-update-checker.php
+++ b/plugin-update-checker/plugin-update-checker.php
@@ -1,10 +1,10 @@