Skip to content

Commit 4097adf

Browse files
committed
Adding plugin-update-checker.
1 parent 51cab71 commit 4097adf

File tree

114 files changed

+11056
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

114 files changed

+11056
-2
lines changed

built-core.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Plugin Name: Built Core
1111
* Plugin URI:
1212
* Description: Core functionality for the site. Adds security and hardening features and cleans up some default functionality.
13-
* Version: 1.0.0
13+
* Version: 1.1.0
1414
* Author: Built North
1515
* Author URI: https://builtnorth.co
1616
* License: GPL-2.0+
@@ -29,7 +29,7 @@
2929
* Define plugin version.
3030
* @link https://semver.org
3131
*/
32-
define( 'BUILT_CORE_VERSION', '1.0.0' );
32+
define( 'BUILT_CORE_VERSION', '1.1.0' );
3333

3434
/**
3535
* Define global constants.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace YahnisElsts\PluginUpdateChecker\v5;
4+
5+
if ( !class_exists(PucFactory::class, false) ):
6+
7+
class PucFactory extends \YahnisElsts\PluginUpdateChecker\v5p4\PucFactory {
8+
}
9+
10+
endif;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace YahnisElsts\PluginUpdateChecker\v5p4;
4+
5+
if ( !class_exists(Autoloader::class, false) ):
6+
7+
class Autoloader {
8+
const DEFAULT_NS_PREFIX = 'YahnisElsts\\PluginUpdateChecker\\';
9+
10+
private $prefix;
11+
private $rootDir;
12+
private $libraryDir;
13+
14+
private $staticMap;
15+
16+
public function __construct() {
17+
$this->rootDir = dirname(__FILE__) . '/';
18+
19+
$namespaceWithSlash = __NAMESPACE__ . '\\';
20+
$this->prefix = $namespaceWithSlash;
21+
22+
$this->libraryDir = $this->rootDir . '../..';
23+
if ( !self::isPhar() ) {
24+
$this->libraryDir = realpath($this->libraryDir);
25+
}
26+
$this->libraryDir = $this->libraryDir . '/';
27+
28+
//Usually, dependencies like Parsedown are in the global namespace,
29+
//but if someone adds a custom namespace to the entire library, they
30+
//will be in the same namespace as this class.
31+
$isCustomNamespace = (
32+
substr($namespaceWithSlash, 0, strlen(self::DEFAULT_NS_PREFIX)) !== self::DEFAULT_NS_PREFIX
33+
);
34+
$libraryPrefix = $isCustomNamespace ? $namespaceWithSlash : '';
35+
36+
$this->staticMap = array(
37+
$libraryPrefix . 'PucReadmeParser' => 'vendor/PucReadmeParser.php',
38+
$libraryPrefix . 'Parsedown' => 'vendor/Parsedown.php',
39+
);
40+
41+
//Add the generic, major-version-only factory class to the static map.
42+
$versionSeparatorPos = strrpos(__NAMESPACE__, '\\v');
43+
if ( $versionSeparatorPos !== false ) {
44+
$versionSegment = substr(__NAMESPACE__, $versionSeparatorPos + 1);
45+
$pointPos = strpos($versionSegment, 'p');
46+
if ( ($pointPos !== false) && ($pointPos > 1) ) {
47+
$majorVersionSegment = substr($versionSegment, 0, $pointPos);
48+
$majorVersionNs = __NAMESPACE__ . '\\' . $majorVersionSegment;
49+
$this->staticMap[$majorVersionNs . '\\PucFactory'] =
50+
'Puc/' . $majorVersionSegment . '/Factory.php';
51+
}
52+
}
53+
54+
spl_autoload_register(array($this, 'autoload'));
55+
}
56+
57+
/**
58+
* Determine if this file is running as part of a Phar archive.
59+
*
60+
* @return bool
61+
*/
62+
private static function isPhar() {
63+
//Check if the current file path starts with "phar://".
64+
static $pharProtocol = 'phar://';
65+
return (substr(__FILE__, 0, strlen($pharProtocol)) === $pharProtocol);
66+
}
67+
68+
public function autoload($className) {
69+
if ( isset($this->staticMap[$className]) && file_exists($this->libraryDir . $this->staticMap[$className]) ) {
70+
include($this->libraryDir . $this->staticMap[$className]);
71+
return;
72+
}
73+
74+
if ( strpos($className, $this->prefix) === 0 ) {
75+
$path = substr($className, strlen($this->prefix));
76+
$path = str_replace(array('_', '\\'), '/', $path);
77+
$path = $this->rootDir . $path . '.php';
78+
79+
if ( file_exists($path) ) {
80+
include $path;
81+
}
82+
}
83+
}
84+
}
85+
86+
endif;
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
<?php
2+
namespace YahnisElsts\PluginUpdateChecker\v5p4\DebugBar;
3+
4+
use YahnisElsts\PluginUpdateChecker\v5p4\PucFactory;
5+
use YahnisElsts\PluginUpdateChecker\v5p4\UpdateChecker;
6+
7+
if ( !class_exists(Extension::class, false) ):
8+
9+
class Extension {
10+
const RESPONSE_BODY_LENGTH_LIMIT = 4000;
11+
12+
/** @var UpdateChecker */
13+
protected $updateChecker;
14+
protected $panelClass = Panel::class;
15+
16+
public function __construct($updateChecker, $panelClass = null) {
17+
$this->updateChecker = $updateChecker;
18+
if ( isset($panelClass) ) {
19+
$this->panelClass = $panelClass;
20+
}
21+
22+
if ( (strpos($this->panelClass, '\\') === false) ) {
23+
$this->panelClass = __NAMESPACE__ . '\\' . $this->panelClass;
24+
}
25+
26+
add_filter('debug_bar_panels', array($this, 'addDebugBarPanel'));
27+
add_action('debug_bar_enqueue_scripts', array($this, 'enqueuePanelDependencies'));
28+
29+
add_action('wp_ajax_puc_v5_debug_check_now', array($this, 'ajaxCheckNow'));
30+
}
31+
32+
/**
33+
* Register the PUC Debug Bar panel.
34+
*
35+
* @param array $panels
36+
* @return array
37+
*/
38+
public function addDebugBarPanel($panels) {
39+
if ( $this->updateChecker->userCanInstallUpdates() ) {
40+
$panels[] = new $this->panelClass($this->updateChecker);
41+
}
42+
return $panels;
43+
}
44+
45+
/**
46+
* Enqueue our Debug Bar scripts and styles.
47+
*/
48+
public function enqueuePanelDependencies() {
49+
wp_enqueue_style(
50+
'puc-debug-bar-style-v5',
51+
$this->getLibraryUrl("/css/puc-debug-bar.css"),
52+
array('debug-bar'),
53+
'20221008'
54+
);
55+
56+
wp_enqueue_script(
57+
'puc-debug-bar-js-v5',
58+
$this->getLibraryUrl("/js/debug-bar.js"),
59+
array('jquery'),
60+
'20221008'
61+
);
62+
}
63+
64+
/**
65+
* Run an update check and output the result. Useful for making sure that
66+
* the update checking process works as expected.
67+
*/
68+
public function ajaxCheckNow() {
69+
//phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is checked in preAjaxRequest().
70+
if ( !isset($_POST['uid']) || ($_POST['uid'] !== $this->updateChecker->getUniqueName('uid')) ) {
71+
return;
72+
}
73+
$this->preAjaxRequest();
74+
$update = $this->updateChecker->checkForUpdates();
75+
if ( $update !== null ) {
76+
echo "An update is available:";
77+
//phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- For debugging output.
78+
echo '<pre>', esc_html(print_r($update, true)), '</pre>';
79+
} else {
80+
echo 'No updates found.';
81+
}
82+
83+
$errors = $this->updateChecker->getLastRequestApiErrors();
84+
if ( !empty($errors) ) {
85+
printf('<p>The update checker encountered %d API error%s.</p>', count($errors), (count($errors) > 1) ? 's' : '');
86+
87+
foreach (array_values($errors) as $num => $item) {
88+
$wpError = $item['error'];
89+
/** @var \WP_Error $wpError */
90+
printf('<h4>%d) %s</h4>', intval($num + 1), esc_html($wpError->get_error_message()));
91+
92+
echo '<dl>';
93+
printf('<dt>Error code:</dt><dd><code>%s</code></dd>', esc_html($wpError->get_error_code()));
94+
95+
if ( isset($item['url']) ) {
96+
printf('<dt>Requested URL:</dt><dd><code>%s</code></dd>', esc_html($item['url']));
97+
}
98+
99+
if ( isset($item['httpResponse']) ) {
100+
if ( is_wp_error($item['httpResponse']) ) {
101+
$httpError = $item['httpResponse'];
102+
/** @var \WP_Error $httpError */
103+
printf(
104+
'<dt>WordPress HTTP API error:</dt><dd>%s (<code>%s</code>)</dd>',
105+
esc_html($httpError->get_error_message()),
106+
esc_html($httpError->get_error_code())
107+
);
108+
} else {
109+
//Status code.
110+
printf(
111+
'<dt>HTTP status:</dt><dd><code>%d %s</code></dd>',
112+
esc_html(wp_remote_retrieve_response_code($item['httpResponse'])),
113+
esc_html(wp_remote_retrieve_response_message($item['httpResponse']))
114+
);
115+
116+
//Headers.
117+
echo '<dt>Response headers:</dt><dd><pre>';
118+
foreach (wp_remote_retrieve_headers($item['httpResponse']) as $name => $value) {
119+
printf("%s: %s\n", esc_html($name), esc_html($value));
120+
}
121+
echo '</pre></dd>';
122+
123+
//Body.
124+
$body = wp_remote_retrieve_body($item['httpResponse']);
125+
if ( $body === '' ) {
126+
$body = '(Empty response.)';
127+
} else if ( strlen($body) > self::RESPONSE_BODY_LENGTH_LIMIT ) {
128+
$length = strlen($body);
129+
$body = substr($body, 0, self::RESPONSE_BODY_LENGTH_LIMIT)
130+
. sprintf("\n(Long string truncated. Total length: %d bytes.)", $length);
131+
}
132+
133+
printf('<dt>Response body:</dt><dd><pre>%s</pre></dd>', esc_html($body));
134+
}
135+
}
136+
echo '<dl>';
137+
}
138+
}
139+
140+
exit;
141+
}
142+
143+
/**
144+
* Check access permissions and enable error display (for debugging).
145+
*/
146+
protected function preAjaxRequest() {
147+
if ( !$this->updateChecker->userCanInstallUpdates() ) {
148+
die('Access denied');
149+
}
150+
check_ajax_referer('puc-ajax');
151+
152+
//phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting -- Part of a debugging feature.
153+
error_reporting(E_ALL);
154+
//phpcs:ignore WordPress.PHP.IniSet.display_errors_Blacklisted
155+
@ini_set('display_errors', 'On');
156+
}
157+
158+
/**
159+
* Remove hooks that were added by this extension.
160+
*/
161+
public function removeHooks() {
162+
remove_filter('debug_bar_panels', array($this, 'addDebugBarPanel'));
163+
remove_action('debug_bar_enqueue_scripts', array($this, 'enqueuePanelDependencies'));
164+
remove_action('wp_ajax_puc_v5_debug_check_now', array($this, 'ajaxCheckNow'));
165+
}
166+
167+
/**
168+
* @param string $filePath
169+
* @return string
170+
*/
171+
private function getLibraryUrl($filePath) {
172+
$absolutePath = realpath(dirname(__FILE__) . '/../../../' . ltrim($filePath, '/'));
173+
174+
//Where is the library located inside the WordPress directory structure?
175+
$absolutePath = PucFactory::normalizePath($absolutePath);
176+
177+
$pluginDir = PucFactory::normalizePath(WP_PLUGIN_DIR);
178+
$muPluginDir = PucFactory::normalizePath(WPMU_PLUGIN_DIR);
179+
$themeDir = PucFactory::normalizePath(get_theme_root());
180+
181+
if ( (strpos($absolutePath, $pluginDir) === 0) || (strpos($absolutePath, $muPluginDir) === 0) ) {
182+
//It's part of a plugin.
183+
return plugins_url(basename($absolutePath), $absolutePath);
184+
} else if ( strpos($absolutePath, $themeDir) === 0 ) {
185+
//It's part of a theme.
186+
$relativePath = substr($absolutePath, strlen($themeDir) + 1);
187+
$template = substr($relativePath, 0, strpos($relativePath, '/'));
188+
$baseUrl = get_theme_root_uri($template);
189+
190+
if ( !empty($baseUrl) && $relativePath ) {
191+
return $baseUrl . '/' . $relativePath;
192+
}
193+
}
194+
195+
return '';
196+
}
197+
}
198+
199+
endif;

0 commit comments

Comments
 (0)