forked from Solo-Web-Works/Projects-Portfolio
Update bundled plugin-update-checker to v5.7 and remove broken setBranch() call
The bundled PUC was missing the setBranch() method on the main UpdateChecker class (it's only on Vcs\PluginUpdateChecker via the VcsCheckerMethods trait). When called with a non-VCS URL like the Gitea update URL, this caused a fatal error at plugin activation. Updating to PUC v5.7 (May 2026) which is the latest upstream release. The setBranch() call is removed because PUC doesn't recognize Gitea as a VCS host; the plugin falls back to PUC's plain JSON metadata mode, which is fine for a plugin hosted on a self-managed repo.
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
namespace YahnisElsts\PluginUpdateChecker\v5p7\DebugBar;
|
||||
|
||||
use YahnisElsts\PluginUpdateChecker\v5p7\PucFactory;
|
||||
use YahnisElsts\PluginUpdateChecker\v5p7\UpdateChecker;
|
||||
|
||||
if ( !class_exists(Extension::class, false) ):
|
||||
|
||||
class Extension {
|
||||
const RESPONSE_BODY_LENGTH_LIMIT = 4000;
|
||||
|
||||
/** @var UpdateChecker */
|
||||
protected $updateChecker;
|
||||
protected $panelClass = Panel::class;
|
||||
|
||||
public function __construct($updateChecker, $panelClass = null) {
|
||||
$this->updateChecker = $updateChecker;
|
||||
if ( isset($panelClass) ) {
|
||||
$this->panelClass = $panelClass;
|
||||
}
|
||||
|
||||
if ( (strpos($this->panelClass, '\\') === false) ) {
|
||||
$this->panelClass = __NAMESPACE__ . '\\' . $this->panelClass;
|
||||
}
|
||||
|
||||
add_filter('debug_bar_panels', array($this, 'addDebugBarPanel'));
|
||||
add_action('debug_bar_enqueue_scripts', array($this, 'enqueuePanelDependencies'));
|
||||
|
||||
add_action('wp_ajax_puc_v5_debug_check_now', array($this, 'ajaxCheckNow'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the PUC Debug Bar panel.
|
||||
*
|
||||
* @param array $panels
|
||||
* @return array
|
||||
*/
|
||||
public function addDebugBarPanel($panels) {
|
||||
if ( $this->updateChecker->userCanInstallUpdates() ) {
|
||||
$panels[] = new $this->panelClass($this->updateChecker);
|
||||
}
|
||||
return $panels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue our Debug Bar scripts and styles.
|
||||
*/
|
||||
public function enqueuePanelDependencies() {
|
||||
wp_enqueue_style(
|
||||
'puc-debug-bar-style-v5',
|
||||
$this->getLibraryUrl("/css/puc-debug-bar.css"),
|
||||
array('debug-bar'),
|
||||
'20221008'
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'puc-debug-bar-js-v5',
|
||||
$this->getLibraryUrl("/js/debug-bar.js"),
|
||||
array('jquery'),
|
||||
'20221008'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an update check and output the result. Useful for making sure that
|
||||
* the update checking process works as expected.
|
||||
*/
|
||||
public function ajaxCheckNow() {
|
||||
//phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is checked in preAjaxRequest().
|
||||
if ( !isset($_POST['uid']) || ($_POST['uid'] !== $this->updateChecker->getUniqueName('uid')) ) {
|
||||
return;
|
||||
}
|
||||
$this->preAjaxRequest();
|
||||
$update = $this->updateChecker->checkForUpdates();
|
||||
if ( $update !== null ) {
|
||||
echo "An update is available:";
|
||||
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- For debugging output.
|
||||
echo '<pre>', esc_html(print_r($update, true)), '</pre>';
|
||||
} else {
|
||||
echo 'No updates found.';
|
||||
}
|
||||
|
||||
$errors = $this->updateChecker->getLastRequestApiErrors();
|
||||
if ( !empty($errors) ) {
|
||||
printf('<p>The update checker encountered %d API error%s.</p>', count($errors), (count($errors) > 1) ? 's' : '');
|
||||
|
||||
foreach (array_values($errors) as $num => $item) {
|
||||
$wpError = $item['error'];
|
||||
/** @var \WP_Error $wpError */
|
||||
printf('<h4>%d) %s</h4>', intval($num + 1), esc_html($wpError->get_error_message()));
|
||||
|
||||
echo '<dl>';
|
||||
printf('<dt>Error code:</dt><dd><code>%s</code></dd>', esc_html($wpError->get_error_code()));
|
||||
|
||||
if ( isset($item['url']) ) {
|
||||
printf('<dt>Requested URL:</dt><dd><code>%s</code></dd>', esc_html($item['url']));
|
||||
}
|
||||
|
||||
if ( isset($item['httpResponse']) ) {
|
||||
if ( is_wp_error($item['httpResponse']) ) {
|
||||
$httpError = $item['httpResponse'];
|
||||
/** @var \WP_Error $httpError */
|
||||
printf(
|
||||
'<dt>WordPress HTTP API error:</dt><dd>%s (<code>%s</code>)</dd>',
|
||||
esc_html($httpError->get_error_message()),
|
||||
esc_html($httpError->get_error_code())
|
||||
);
|
||||
} else {
|
||||
//Status code.
|
||||
printf(
|
||||
'<dt>HTTP status:</dt><dd><code>%d %s</code></dd>',
|
||||
esc_html(wp_remote_retrieve_response_code($item['httpResponse'])),
|
||||
esc_html(wp_remote_retrieve_response_message($item['httpResponse']))
|
||||
);
|
||||
|
||||
//Headers.
|
||||
echo '<dt>Response headers:</dt><dd><pre>';
|
||||
foreach (wp_remote_retrieve_headers($item['httpResponse']) as $name => $value) {
|
||||
printf("%s: %s\n", esc_html($name), esc_html($value));
|
||||
}
|
||||
echo '</pre></dd>';
|
||||
|
||||
//Body.
|
||||
$body = wp_remote_retrieve_body($item['httpResponse']);
|
||||
if ( $body === '' ) {
|
||||
$body = '(Empty response.)';
|
||||
} else if ( strlen($body) > self::RESPONSE_BODY_LENGTH_LIMIT ) {
|
||||
$length = strlen($body);
|
||||
$body = substr($body, 0, self::RESPONSE_BODY_LENGTH_LIMIT)
|
||||
. sprintf("\n(Long string truncated. Total length: %d bytes.)", $length);
|
||||
}
|
||||
|
||||
printf('<dt>Response body:</dt><dd><pre>%s</pre></dd>', esc_html($body));
|
||||
}
|
||||
}
|
||||
echo '<dl>';
|
||||
}
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check access permissions and enable error display (for debugging).
|
||||
*/
|
||||
protected function preAjaxRequest() {
|
||||
if ( !$this->updateChecker->userCanInstallUpdates() ) {
|
||||
die('Access denied');
|
||||
}
|
||||
check_ajax_referer('puc-ajax');
|
||||
|
||||
//phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting -- Part of a debugging feature.
|
||||
error_reporting(E_ALL);
|
||||
//phpcs:ignore WordPress.PHP.IniSet.display_errors_Blacklisted
|
||||
@ini_set('display_errors', 'On');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove hooks that were added by this extension.
|
||||
*/
|
||||
public function removeHooks() {
|
||||
remove_filter('debug_bar_panels', array($this, 'addDebugBarPanel'));
|
||||
remove_action('debug_bar_enqueue_scripts', array($this, 'enqueuePanelDependencies'));
|
||||
remove_action('wp_ajax_puc_v5_debug_check_now', array($this, 'ajaxCheckNow'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filePath
|
||||
* @return string
|
||||
*/
|
||||
private function getLibraryUrl($filePath) {
|
||||
$absolutePath = realpath(dirname(__FILE__) . '/../../../' . ltrim($filePath, '/'));
|
||||
|
||||
//Where is the library located inside the WordPress directory structure?
|
||||
$absolutePath = PucFactory::normalizePath($absolutePath);
|
||||
|
||||
$pluginDir = PucFactory::normalizePath(WP_PLUGIN_DIR);
|
||||
$muPluginDir = PucFactory::normalizePath(WPMU_PLUGIN_DIR);
|
||||
$themeDir = PucFactory::normalizePath(get_theme_root());
|
||||
|
||||
if ( (strpos($absolutePath, $pluginDir) === 0) || (strpos($absolutePath, $muPluginDir) === 0) ) {
|
||||
//It's part of a plugin.
|
||||
return plugins_url(basename($absolutePath), $absolutePath);
|
||||
} else if ( strpos($absolutePath, $themeDir) === 0 ) {
|
||||
//It's part of a theme.
|
||||
$relativePath = substr($absolutePath, strlen($themeDir) + 1);
|
||||
$template = substr($relativePath, 0, strpos($relativePath, '/'));
|
||||
$baseUrl = get_theme_root_uri($template);
|
||||
|
||||
if ( !empty($baseUrl) && $relativePath ) {
|
||||
return $baseUrl . '/' . $relativePath;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
namespace YahnisElsts\PluginUpdateChecker\v5p7\DebugBar;
|
||||
|
||||
use YahnisElsts\PluginUpdateChecker\v5p7\UpdateChecker;
|
||||
|
||||
if ( !class_exists(Panel::class, false) && class_exists('Debug_Bar_Panel', false) ):
|
||||
|
||||
class Panel extends \Debug_Bar_Panel {
|
||||
/** @var UpdateChecker */
|
||||
protected $updateChecker;
|
||||
|
||||
private $responseBox = '<div class="puc-ajax-response" style="display: none;"></div>';
|
||||
|
||||
public function __construct($updateChecker) {
|
||||
$this->updateChecker = $updateChecker;
|
||||
$title = sprintf(
|
||||
'<span class="puc-debug-menu-link-%s">PUC (%s)</span>',
|
||||
esc_attr($this->updateChecker->getUniqueName('uid')),
|
||||
$this->updateChecker->slug
|
||||
);
|
||||
parent::__construct($title);
|
||||
}
|
||||
|
||||
public function render() {
|
||||
printf(
|
||||
'<div class="puc-debug-bar-panel-v5" id="%1$s" data-slug="%2$s" data-uid="%3$s" data-nonce="%4$s">',
|
||||
esc_attr($this->updateChecker->getUniqueName('debug-bar-panel')),
|
||||
esc_attr($this->updateChecker->slug),
|
||||
esc_attr($this->updateChecker->getUniqueName('uid')),
|
||||
esc_attr(wp_create_nonce('puc-ajax'))
|
||||
);
|
||||
|
||||
$this->displayConfiguration();
|
||||
$this->displayStatus();
|
||||
$this->displayCurrentUpdate();
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
private function displayConfiguration() {
|
||||
echo '<h3>Configuration</h3>';
|
||||
echo '<table class="puc-debug-data">';
|
||||
$this->displayConfigHeader();
|
||||
$this->row('Slug', esc_html($this->updateChecker->slug));
|
||||
$this->row('DB option', esc_html($this->updateChecker->optionName));
|
||||
|
||||
$requestInfoButton = $this->getMetadataButton();
|
||||
$this->row('Metadata URL', esc_html($this->updateChecker->metadataUrl) . ' ' . $requestInfoButton . $this->responseBox);
|
||||
|
||||
$scheduler = $this->updateChecker->scheduler;
|
||||
if ( $scheduler->checkPeriod > 0 ) {
|
||||
$this->row('Automatic checks', 'Every ' . $scheduler->checkPeriod . ' hours');
|
||||
} else {
|
||||
$this->row('Automatic checks', 'Disabled');
|
||||
}
|
||||
|
||||
if ( isset($scheduler->throttleRedundantChecks) ) {
|
||||
if ( $scheduler->throttleRedundantChecks && ($scheduler->checkPeriod > 0) ) {
|
||||
$this->row(
|
||||
'Throttling',
|
||||
sprintf(
|
||||
'Enabled. If an update is already available, check for updates every %1$d hours instead of every %2$d hours.',
|
||||
$scheduler->throttledCheckPeriod,
|
||||
$scheduler->checkPeriod
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$this->row('Throttling', 'Disabled');
|
||||
}
|
||||
}
|
||||
|
||||
$this->updateChecker->onDisplayConfiguration($this);
|
||||
|
||||
echo '</table>';
|
||||
}
|
||||
|
||||
protected function displayConfigHeader() {
|
||||
//Do nothing. This should be implemented in subclasses.
|
||||
}
|
||||
|
||||
protected function getMetadataButton() {
|
||||
return '';
|
||||
}
|
||||
|
||||
private function displayStatus() {
|
||||
echo '<h3>Status</h3>';
|
||||
echo '<table class="puc-debug-data">';
|
||||
$state = $this->updateChecker->getUpdateState();
|
||||
$checkButtonId = $this->updateChecker->getUniqueName('check-now-button');
|
||||
if ( function_exists('get_submit_button') ) {
|
||||
$checkNowButton = get_submit_button(
|
||||
'Check Now',
|
||||
'secondary',
|
||||
'puc-check-now-button',
|
||||
false,
|
||||
array('id' => $checkButtonId)
|
||||
);
|
||||
} else {
|
||||
//get_submit_button() is not available in the frontend. Make a button directly.
|
||||
//It won't look the same without admin styles, but it should still work.
|
||||
$checkNowButton = sprintf(
|
||||
'<input type="button" id="%1$s" name="puc-check-now-button" value="%2$s" class="button button-secondary" />',
|
||||
esc_attr($checkButtonId),
|
||||
esc_attr('Check Now')
|
||||
);
|
||||
}
|
||||
|
||||
if ( $state->getLastCheck() > 0 ) {
|
||||
$this->row('Last check', $this->formatTimeWithDelta($state->getLastCheck()) . ' ' . $checkNowButton . $this->responseBox);
|
||||
} else {
|
||||
$this->row('Last check', 'Never');
|
||||
}
|
||||
|
||||
$nextCheck = wp_next_scheduled($this->updateChecker->scheduler->getCronHookName());
|
||||
$this->row('Next automatic check', $this->formatTimeWithDelta($nextCheck));
|
||||
|
||||
if ( $state->getCheckedVersion() !== '' ) {
|
||||
$this->row('Checked version', esc_html($state->getCheckedVersion()));
|
||||
$this->row('Cached update', $state->getUpdate());
|
||||
}
|
||||
$this->row('Update checker class', esc_html(get_class($this->updateChecker)));
|
||||
echo '</table>';
|
||||
}
|
||||
|
||||
private function displayCurrentUpdate() {
|
||||
$update = $this->updateChecker->getUpdate();
|
||||
if ( $update !== null ) {
|
||||
echo '<h3>An Update Is Available</h3>';
|
||||
echo '<table class="puc-debug-data">';
|
||||
$fields = $this->getUpdateFields();
|
||||
foreach($fields as $field) {
|
||||
if ( property_exists($update, $field) ) {
|
||||
$this->row(
|
||||
ucwords(str_replace('_', ' ', $field)),
|
||||
isset($update->$field) ? esc_html($update->$field) : null
|
||||
);
|
||||
}
|
||||
}
|
||||
echo '</table>';
|
||||
} else {
|
||||
echo '<h3>No updates currently available</h3>';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getUpdateFields() {
|
||||
return array('version', 'download_url', 'slug',);
|
||||
}
|
||||
|
||||
private function formatTimeWithDelta($unixTime) {
|
||||
if ( empty($unixTime) ) {
|
||||
return 'Never';
|
||||
}
|
||||
|
||||
$delta = time() - $unixTime;
|
||||
$result = human_time_diff(time(), $unixTime);
|
||||
if ( $delta < 0 ) {
|
||||
$result = 'after ' . $result;
|
||||
} else {
|
||||
$result = $result . ' ago';
|
||||
}
|
||||
$result .= ' (' . $this->formatTimestamp($unixTime) . ')';
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function formatTimestamp($unixTime) {
|
||||
return gmdate('Y-m-d H:i:s', $unixTime + (get_option('gmt_offset') * 3600));
|
||||
}
|
||||
|
||||
public function row($name, $value) {
|
||||
if ( is_object($value) || is_array($value) ) {
|
||||
//This is specifically for debugging, so print_r() is fine.
|
||||
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
||||
$value = '<pre>' . esc_html(print_r($value, true)) . '</pre>';
|
||||
} else if ($value === null) {
|
||||
$value = '<code>null</code>';
|
||||
}
|
||||
printf(
|
||||
'<tr><th scope="row">%1$s</th> <td>%2$s</td></tr>',
|
||||
esc_html($name),
|
||||
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped above.
|
||||
$value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace YahnisElsts\PluginUpdateChecker\v5p7\DebugBar;
|
||||
|
||||
use YahnisElsts\PluginUpdateChecker\v5p7\Plugin\UpdateChecker;
|
||||
|
||||
if ( !class_exists(PluginExtension::class, false) ):
|
||||
|
||||
class PluginExtension extends Extension {
|
||||
/** @var UpdateChecker */
|
||||
protected $updateChecker;
|
||||
|
||||
public function __construct($updateChecker) {
|
||||
parent::__construct($updateChecker, PluginPanel::class);
|
||||
|
||||
add_action('wp_ajax_puc_v5_debug_request_info', array($this, 'ajaxRequestInfo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Request plugin info and output it.
|
||||
*/
|
||||
public function ajaxRequestInfo() {
|
||||
//phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is checked in preAjaxRequest().
|
||||
if ( !isset($_POST['uid']) || ($_POST['uid'] !== $this->updateChecker->getUniqueName('uid')) ) {
|
||||
return;
|
||||
}
|
||||
$this->preAjaxRequest();
|
||||
$info = $this->updateChecker->requestInfo();
|
||||
if ( $info !== null ) {
|
||||
echo 'Successfully retrieved plugin info from the metadata URL:';
|
||||
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- For debugging output.
|
||||
echo '<pre>', esc_html(print_r($info, true)), '</pre>';
|
||||
} else {
|
||||
echo 'Failed to retrieve plugin info from the metadata URL.';
|
||||
}
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace YahnisElsts\PluginUpdateChecker\v5p7\DebugBar;
|
||||
|
||||
use YahnisElsts\PluginUpdateChecker\v5p7\Plugin\UpdateChecker;
|
||||
|
||||
if ( !class_exists(PluginPanel::class, false) ):
|
||||
|
||||
class PluginPanel extends Panel {
|
||||
/**
|
||||
* @var UpdateChecker
|
||||
*/
|
||||
protected $updateChecker;
|
||||
|
||||
protected function displayConfigHeader() {
|
||||
$this->row('Plugin file', esc_html($this->updateChecker->pluginFile));
|
||||
parent::displayConfigHeader();
|
||||
}
|
||||
|
||||
protected function getMetadataButton() {
|
||||
$buttonId = $this->updateChecker->getUniqueName('request-info-button');
|
||||
if ( function_exists('get_submit_button') ) {
|
||||
$requestInfoButton = get_submit_button(
|
||||
'Request Info',
|
||||
'secondary',
|
||||
'puc-request-info-button',
|
||||
false,
|
||||
array('id' => $buttonId)
|
||||
);
|
||||
} else {
|
||||
$requestInfoButton = sprintf(
|
||||
'<input type="button" name="puc-request-info-button" id="%1$s" value="%2$s" class="button button-secondary" />',
|
||||
esc_attr($buttonId),
|
||||
esc_attr('Request Info')
|
||||
);
|
||||
}
|
||||
return $requestInfoButton;
|
||||
}
|
||||
|
||||
protected function getUpdateFields() {
|
||||
return array_merge(
|
||||
parent::getUpdateFields(),
|
||||
array('homepage', 'upgrade_notice', 'tested',)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace YahnisElsts\PluginUpdateChecker\v5p7\DebugBar;
|
||||
|
||||
use YahnisElsts\PluginUpdateChecker\v5p7\Theme\UpdateChecker;
|
||||
|
||||
if ( !class_exists(ThemePanel::class, false) ):
|
||||
|
||||
class ThemePanel extends Panel {
|
||||
/**
|
||||
* @var UpdateChecker
|
||||
*/
|
||||
protected $updateChecker;
|
||||
|
||||
protected function displayConfigHeader() {
|
||||
$this->row('Theme directory', esc_html($this->updateChecker->directoryName));
|
||||
parent::displayConfigHeader();
|
||||
}
|
||||
|
||||
protected function getUpdateFields() {
|
||||
return array_merge(parent::getUpdateFields(), array('details_url'));
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
Reference in New Issue
Block a user