PluginProbe
APCu Manager / trunk
APCu Manager vtrunk
4.6.0 4.6.1 4.5.4 4.5.2 4.5.3 4.5.1 trunk 1.0.0 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 2.0.0 2.1.0 2.2.0 2.3.0 2.4.0 2.4.1 2.5.0 2.6.0 3.0.0 3.0.1 3.1.0 All 49 releases
apcu-manager / includes / plugin / class-updater.php

class-updater.php in APCu Manager trunk, at includes/plugin/class-updater.php

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