PluginProbe
OPcache Manager / 3.3.0
OPcache Manager v3.3.0
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.2.0 1.3.0 1.3.1 1.3.2 2.0.0 2.1.0 2.10.0 2.11.0 2.12.0 2.13.0 2.13.1 2.14.0 2.2.0 2.3.0 2.3.1 2.3.2 2.4.0 2.5.0 2.6.0 All 36 releases
opcache-manager / includes / plugin / class-updater.php

class-updater.php in OPcache Manager 3.3.0, at includes/plugin/class-updater.php

283 lines 9.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin updates handling.
4 *
5 * @package Plugin
6 * @author Pierre Lannoy <https://pierre.lannoy.fr/>.
7 * @since 1.0.0
8 */
9
10 namespace OPcacheManager\Plugin;
11
12 use OPcacheManager\System\Nag;
13 use OPcacheManager\System\Option;
14 use Exception;
15 use OPcacheManager\System\Cache;
16 use OPcacheManager\System\Http;
17 use OPcacheManager\Plugin\Feature\Schema;
18 use OPcacheManager\System\Logger;
19 use OPcacheManager\System\Markdown;
20
21 /**
22 * Plugin updates handling.
23 *
24 * This class defines all code necessary to handle the plugin's updates.
25 *
26 * @package Plugin
27 * @author Pierre Lannoy <https://pierre.lannoy.fr/>.
28 * @since 1.0.0
29 */
30 class Updater {
31
32 private $name = OPCM_PRODUCT_NAME;
33
34 private $slug = OPCM_SLUG;
35
36 private $version = OPCM_VERSION;
37
38 private $product = OPCM_PRODUCT_URL;
39
40 /**
41 * Initializes the class, set its properties and performs
42 * post-update processes if needed.
43 *
44 * @since 1.0.0
45 */
46 public function __construct() {
47 $old = Option::network_get( 'version' );
48 Option::network_set( 'version', OPCM_VERSION );
49 if ( OPCM_VERSION !== $old ) {
50 if ( '0.0.0' === $old ) {
51 $this->install();
52 // phpcs:ignore
53 $message = sprintf( esc_html__( '%1$s has been correctly installed.', 'opcache-manager' ), OPCM_PRODUCT_NAME );
54 } else {
55 $this->update( $old );
56 // phpcs:ignore
57 $message = sprintf( esc_html__( '%1$s has been correctly updated from version %2$s to version %3$s.', 'opcache-manager' ), OPCM_PRODUCT_NAME, $old, OPCM_VERSION );
58 \DecaLog\Engine::eventsLogger( OPCM_SLUG )->notice( $message );
59 // phpcs:ignore
60 $message .= ' ' . sprintf( __( 'See <a href="%s">what\'s new</a>.', 'opcache-manager' ), admin_url( 'admin.php?page=opcm-settings&tab=about' ) );
61 }
62 Nag::add( 'update', 'info', $message );
63 }
64 if ( ! ( defined( 'POO_SELFUPDATE_BYPASS' ) && POO_SELFUPDATE_BYPASS ) ) {
65 add_filter( 'plugins_api', [ $this, 'plugin_info' ], PHP_INT_MAX, 3 );
66 add_filter( 'site_transient_update_plugins', [ $this, 'info_update' ] );
67 add_action( 'upgrader_process_complete', [ $this, 'info_reset' ], 10, 2 );
68 add_filter( 'clean_url', [ $this, 'filter_logo' ], PHP_INT_MAX, 3 );
69 }
70 }
71
72 /**
73 * Performs post-installation processes.
74 *
75 * @since 1.0.0
76 */
77 private function install() {
78
79 }
80
81 /**
82 * Performs post-update processes.
83 *
84 * @param string $from The version from which the plugin is updated.
85 * @since 1.0.0
86 */
87 private function update( $from ) {
88 $schema = new Schema();
89 $schema->update();
90 }
91
92 /**
93 * Get the changelog.
94 *
95 * @param array $attributes 'style' => 'markdown', 'html'.
96 * 'mode' => 'raw', 'clean'.
97 * @return string The output of the shortcode, ready to print.
98 * @since 1.0.0
99 */
100 public function sc_get_changelog( $attributes ) {
101 $md = new Markdown();
102
103 return $md->get_shortcode( 'CHANGELOG.md', $attributes );
104 }
105
106 /**
107 * Acquires infos about update
108 *
109 * @return object The remote info.
110 */
111 private function gather_info() {
112 $remotes = Cache::get_global( 'data_update-infos' );
113 if ( ! $remotes ) {
114 $remotes = new \stdClass();
115
116 $remote = wp_remote_get(
117 str_replace( 'github.com', 'raw.githubusercontent.com', $this->product ) . '/refs/heads/master/plugin.json',
118 [
119 'timeout' => 10,
120 'headers' => [
121 'Accept' => 'application/vnd.github+json',
122 'user-agent' => Http::user_agent(),
123 ]
124 ]
125 );
126 if ( is_wp_error( $remote ) || 200 !== wp_remote_retrieve_response_code( $remote ) || empty( wp_remote_retrieve_body( $remote ) ) ) {
127 return false;
128 }
129 $plugin_info = json_decode( wp_remote_retrieve_body( $remote ), true );
130 $remotes->tested = $plugin_info['tested'] ?? '7.0';
131 $remotes->requires = $plugin_info['requires'] ?? '6.2';
132 $remotes->requires_php = $plugin_info['requires_php'] ?? '7.1';
133 $remotes->author = $plugin_info['author'] ?? '<a href="https://perfops.one">Pierre Lannoy / PerfOps One</a>';
134 $remotes->author_profile = $plugin_info['author_profile'] ?? 'https://profiles.wordpress.org/pierrelannoy/';
135
136 $remote = wp_remote_get(
137 'https://releases.perfops.one/' . $this->slug . '.json',
138 [
139 'timeout' => 10,
140 'headers' => [
141 'user-agent' => Http::user_agent(),
142 ],
143 ]
144 );
145 if ( is_wp_error( $remote ) || 200 !== wp_remote_retrieve_response_code( $remote ) || empty( wp_remote_retrieve_body( $remote ) ) ) {
146 return false;
147 }
148 $release_info = json_decode( wp_remote_retrieve_body( $remote ), true );
149 if ( is_null( $release_info ) || ! is_array( $release_info ) ) {
150 return false;
151 }
152 if ( array_key_exists( 'tag_name', $release_info ) && array_key_exists( 'name', $release_info ) && array_key_exists( 'published_at', $release_info ) && array_key_exists( 'body', $release_info ) && array_key_exists( 'assets', $release_info ) && is_array( $release_info['assets'] ) ) {
153 $remotes->version = $release_info['tag_name'];
154 $remotes->download_url = $release_info['assets'][0]['browser_download_url'] ?? '-';
155 $remotes->last_updated = substr( $release_info['published_at'], 0, strpos( $release_info['published_at'], 'T' ) );
156 $remotes->changelog = '## ' . $release_info['name'] . "\r\n" . $release_info['body'];
157 } else {
158 return false;
159 }
160 if ( '-' === $remotes->download_url ) {
161 return false;
162 }
163
164 Cache::set_global( 'data_update-infos', $remotes, DAY_IN_SECONDS );
165 }
166
167 return $remotes;
168 }
169
170 /**
171 * Filters the url logo to be sure it is svg-inlined.
172 *
173 * @param string $good_protocol_url The cleaned URL to be returned.
174 * @param string $original_url The URL prior to cleaning.
175 * @param string $_context If 'display', replace ampersands and single quotes only.
176 *
177 * @return string $good_protocol_url The cleaned URL.
178 */
179 function filter_logo( $good_protocol_url, $original_url, $_context ) {
180 if ( 'https://data.' . $this->slug === $original_url ) {
181 return Core::get_base64_logo();
182 }
183
184 return $good_protocol_url;
185 }
186
187 /**
188 * Filters the response for the current WordPress.org Plugin Installation API request.
189 *
190 * @param false|object|array $result The result object or array.
191 * @param string $action The type of information being requested from the Plugin Installation API.
192 * @param object $args Plugin API arguments.
193 * @@return false|object|array The result object or array.
194 */
195 function plugin_info( $res, $action, $args ) {
196 if ( 'plugin_information' !== $action ) {
197 return $res;
198 }
199 if ( $this->slug !== $args->slug ) {
200 return $res;
201 }
202 $infos = $this->gather_info();
203 if ( ! $infos ) {
204 return $res;
205 }
206 $md = new Markdown();
207 if ( ! is_object( $res ) ) {
208 $res = new \stdClass();
209 }
210 $res->name = $this->name;
211 $res->homepage = 'https://perfops.one/' . $this->slug;
212 $res->slug = $this->slug;
213 $res->is_community = true;
214 $res->external_repository_url = $this->product;
215 $res->tested = $infos->tested;
216 $res->requires = $infos->requires;
217 $res->requires_php = $infos->requires_php;
218 $res->last_updated = $infos->last_updated;
219 $res->author = $infos->author;
220 $res->author_profile = $infos->author_profile;
221 $res->version = $infos->version;
222 $res->download_link = $infos->download_url;
223 $res->trunk = $infos->download_url;
224 if ( isset( $res->sections['changelog'] ) ) {
225 $res->sections['changelog'] = $md->get_inline( $infos->changelog, [] ) . '<br/><br/><p><a target="_blank" href="' . $res->homepage . '-changelog">CHANGELOG »</a></p>';
226 } else {
227 $res->sections = [
228 'changelog' => $md->get_inline( $infos->changelog, [] ) . '<br/><br/><p><a target="_blank" href="' . $res->homepage . '-changelog">CHANGELOG »</a></p>',
229 ];
230 }
231 if ( isset( $res->banners['low'] ) && isset( $res->banners['high'] )) {
232 $res->banners['low'] = str_replace( 'github.com', 'raw.githubusercontent.com', $this->product ) . '/refs/heads/master/.wordpress-org/banner-772x250.jpg';
233 $res->banners['high'] = str_replace( 'github.com', 'raw.githubusercontent.com', $this->product ) . '/refs/heads/master/.wordpress-org/banner-1544x500.jpg';
234 } else {
235 $res->banners = [
236 'low' => str_replace( 'github.com', 'raw.githubusercontent.com', $this->product ) . '/refs/heads/master/.wordpress-org/banner-772x250.jpg',
237 'high' => str_replace( 'github.com', 'raw.githubusercontent.com', $this->product ) . '/refs/heads/master/.wordpress-org/banner-1544x500.jpg'
238 ];
239 }
240 return $res;
241 }
242
243 /**
244 * Updates infos transient
245 *
246 * @param object $transient The transient to update.
247 *
248 * @return object The updated transient.
249 */
250 public function info_update( $transient ) {
251 if ( empty( $transient->checked ) ) {
252 return $transient;
253 }
254 $remote = $this->gather_info();
255 if ( $remote && version_compare( $this->version, $remote->version, '<' ) && version_compare( $remote->requires, get_bloginfo( 'version' ), '<=' ) && version_compare( $remote->requires_php, PHP_VERSION, '<' ) ) {
256 $res = new \stdClass();
257 $res->slug = $this->slug;
258 $res->plugin = $this->slug . '/' . $this->slug . '.php';
259 $res->new_version = $remote->version;
260 $res->tested = $remote->tested;
261 $res->package = $remote->download_url;
262 $res->icons = [
263 'svg' => 'https://data.' . $this->slug
264 ];
265 $transient->response[ $res->plugin ] = $res;
266 }
267
268 return $transient;
269 }
270
271 /**
272 * Reset update infos
273 *
274 * @param Plugin_Upgrader $upgrader Upgrader instance.
275 * @param array $options Array of bulk item update data.
276 */
277 public function info_reset( $upgrader, $options ) {
278 if ( 'update' === $options['action'] && 'plugin' === $options['type'] ) {
279 Cache::delete_global( 'data_update-infos' );
280 }
281 }
282 }
283