PluginProbe
Polylang / 3.6.7
Polylang v3.6.7
3.8.10 3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 All 234 releases
← All changes | install/plugin-updater.php +258 -237 3.0.1 → 3.6.7 View file →
@@ -1,8 +1,5 @@
1 1 <?php
2 -/**
3 - * @package Polylang
4 - */
5 2
6 3 // Exit if accessed directly
7 4 if ( ! defined( 'ABSPATH' ) ) {
8 5 exit;
@@ -9,25 +6,25 @@
9 6 }
10 7
11 8 /**
12 9 * Allows plugins to use their own update API.
13 - * Modified version with 'polylang' text domain and comments for translators.
10 + * Modified version with 'polylang' text domain and missing comments for translators.
14 11 *
15 12 * @author Easy Digital Downloads
16 - * @version 1.8.0
13 + * @version 1.9.1
17 14 */
18 15 class PLL_Plugin_Updater {
19 16
20 - private $api_url = '';
21 - private $api_data = array();
22 - private $name = '';
23 - private $slug = '';
24 - private $version = '';
25 - private $wp_override = false;
26 - private $cache_key = '';
17 + private $api_url = '';
18 + private $api_data = array();
19 + private $plugin_file = '';
20 + private $name = '';
21 + private $slug = '';
22 + private $version = '';
23 + private $wp_override = false;
24 + private $beta = false;
25 + private $failed_request_cache_key;
27 26
28 - private $health_check_timeout = 5;
29 -
30 27 /**
31 28 * Class constructor.
32 29 *
33 30 * @uses plugin_basename()
@@ -40,16 +37,17 @@
40 37 public function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
41 38
42 39 global $edd_plugin_data;
43 40
44 - $this->api_url = trailingslashit( $_api_url );
45 - $this->api_data = $_api_data;
46 - $this->name = plugin_basename( $_plugin_file );
47 - $this->slug = basename( $_plugin_file, '.php' );
48 - $this->version = $_api_data['version'];
49 - $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
50 - $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
51 - $this->cache_key = 'edd_sl_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );
41 + $this->api_url = trailingslashit( $_api_url );
42 + $this->api_data = $_api_data;
43 + $this->plugin_file = $_plugin_file;
44 + $this->name = plugin_basename( $_plugin_file );
45 + $this->slug = basename( $_plugin_file, '.php' );
46 + $this->version = $_api_data['version'];
47 + $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
48 + $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
49 + $this->failed_request_cache_key = 'edd_sl_failed_http_' . md5( $this->api_url );
52 50
53 51 $edd_plugin_data[ $this->slug ] = $this->api_data;
54 52
55 53 /**
@@ -76,10 +74,9 @@
76 74 public function init() {
77 75
78 76 add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
79 77 add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
80 - remove_action( 'after_plugin_row_' . $this->name, 'wp_plugin_update_row', 10 );
81 - add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 );
78 + add_action( 'after_plugin_row', array( $this, 'show_update_notification' ), 10, 2 );
82 79 add_action( 'admin_init', array( $this, 'show_changelog' ) );
83 80
84 81 }
85 82
@@ -100,15 +97,11 @@
100 97
101 98 global $pagenow;
102 99
103 100 if ( ! is_object( $_transient_data ) ) {
104 - $_transient_data = new stdClass;
101 + $_transient_data = new stdClass();
105 102 }
106 103
107 - if ( 'plugins.php' == $pagenow && is_multisite() ) {
108 - return $_transient_data;
109 - }
110 -
111 104 if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
112 105 return $_transient_data;
113 106 }
114 107
@@ -158,9 +151,9 @@
158 151 return $version_info;
159 152 }
160 153
161 154 /**
162 - * show update nofication row -- needed for multisite subsites, because WP won't tell you otherwise!
155 + * Show the update notification on multisite subsites.
163 156 *
164 157 * @param string $file
165 158 * @param array $plugin
166 159 */
@@ -165,119 +158,122 @@
165 158 * @param array $plugin
166 159 */
167 160 public function show_update_notification( $file, $plugin ) {
168 161
169 - if ( is_network_admin() ) {
162 + // Return early if in the network admin, or if this is not a multisite install.
163 + if ( is_network_admin() || ! is_multisite() ) {
170 164 return;
171 165 }
172 166
173 - if( ! current_user_can( 'update_plugins' ) ) {
167 + // Allow single site admins to see that an update is available.
168 + if ( ! current_user_can( 'activate_plugins' ) ) {
174 169 return;
175 170 }
176 171
177 - if( ! is_multisite() ) {
172 + if ( $this->name !== $file ) {
178 173 return;
179 174 }
180 175
181 - if ( $this->name != $file ) {
182 - return;
183 - }
184 -
185 - // Remove our filter on the site transient
186 - remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 );
187 -
176 + // Do not print any message if update does not exist.
188 177 $update_cache = get_site_transient( 'update_plugins' );
189 178
190 - $update_cache = is_object( $update_cache ) ? $update_cache : new stdClass();
179 + if ( ! isset( $update_cache->response[ $this->name ] ) ) {
180 + if ( ! is_object( $update_cache ) ) {
181 + $update_cache = new stdClass();
182 + }
183 + $update_cache->response[ $this->name ] = $this->get_repo_api_data();
184 + }
191 185
192 - if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) {
186 + // Return early if this plugin isn't in the transient->response or if the site is running the current or newer version of the plugin.
187 + if ( empty( $update_cache->response[ $this->name ] ) || version_compare( $this->version, $update_cache->response[ $this->name ]->new_version, '>=' ) ) {
188 + return;
189 + }
193 190
194 - $version_info = $this->get_repo_api_data();
191 + printf(
192 + '<tr class="plugin-update-tr %3$s" id="%1$s-update" data-slug="%1$s" data-plugin="%2$s">',
193 + $this->slug,
194 + $file,
195 + in_array( $this->name, $this->get_active_plugins(), true ) ? 'active' : 'inactive'
196 + );
195 197
196 - if ( false === $version_info ) {
197 - $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
198 + echo '<td colspan="3" class="plugin-update colspanchange">';
199 + echo '<div class="update-message notice inline notice-warning notice-alt"><p>';
198 200
199 - // Since we disabled our filter for the transient, we aren't running our object conversion on banners, sections, or icons. Do this now:
200 - if ( isset( $version_info->banners ) && ! is_array( $version_info->banners ) ) {
201 - $version_info->banners = $this->convert_object_to_array( $version_info->banners );
202 - }
201 + $changelog_link = '';
202 + if ( ! empty( $update_cache->response[ $this->name ]->sections->changelog ) ) {
203 + $changelog_link = add_query_arg(
204 + array(
205 + 'edd_sl_action' => 'view_plugin_changelog',
206 + 'plugin' => urlencode( $this->name ),
207 + 'slug' => urlencode( $this->slug ),
208 + 'TB_iframe' => 'true',
209 + 'width' => 77,
210 + 'height' => 911,
211 + ),
212 + self_admin_url( 'index.php' )
213 + );
214 + }
215 + $update_link = add_query_arg(
216 + array(
217 + 'action' => 'upgrade-plugin',
218 + 'plugin' => urlencode( $this->name ),
219 + ),
220 + self_admin_url( 'update.php' )
221 + );
203 222
204 - if ( isset( $version_info->sections ) && ! is_array( $version_info->sections ) ) {
205 - $version_info->sections = $this->convert_object_to_array( $version_info->sections );
206 - }
223 + printf(
224 + /* translators: the plugin name. */
225 + esc_html__( 'There is a new version of %1$s available.', 'polylang' ),
226 + esc_html( $plugin['Name'] )
227 + );
207 228
208 - if ( isset( $version_info->icons ) && ! is_array( $version_info->icons ) ) {
209 - $version_info->icons = $this->convert_object_to_array( $version_info->icons );
210 - }
211 -
212 - if ( isset( $version_info->contributors ) && ! is_array( $version_info->contributors ) ) {
213 - $version_info->contributors = $this->convert_object_to_array( $version_info->contributors );
214 - }
215 -
216 - $this->set_version_info_cache( $version_info );
217 - }
218 -
219 - if ( ! is_object( $version_info ) ) {
220 - return;
221 - }
222 -
223 - if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
224 - $update_cache->response[ $this->name ] = $version_info;
225 - } else {
226 - $update_cache->no_update[ $this->name ] = $version_info;
227 - }
228 -
229 - $update_cache->last_checked = time();
230 - $update_cache->checked[ $this->name ] = $this->version;
231 -
232 - set_site_transient( 'update_plugins', $update_cache );
233 -
229 + if ( ! current_user_can( 'update_plugins' ) ) {
230 + echo ' ';
231 + esc_html_e( 'Contact your network administrator to install the update.', 'polylang' );
232 + } elseif ( empty( $update_cache->response[ $this->name ]->package ) && ! empty( $changelog_link ) ) {
233 + echo ' ';
234 + printf(
235 + /* translators: 1. opening anchor tag, do not translate 2. the new plugin version 3. closing anchor tag, do not translate. */
236 + __( '%1$sView version %2$s details%3$s.', 'polylang' ),
237 + '<a target="_blank" class="thickbox open-plugin-details-modal" href="' . esc_url( $changelog_link ) . '">',
238 + esc_html( $update_cache->response[ $this->name ]->new_version ),
239 + '</a>'
240 + );
241 + } elseif ( ! empty( $changelog_link ) ) {
242 + echo ' ';
243 + printf(
244 + /* translators: 1. and 4. are opening anchor tags 2. the new plugin version 3. and 5. are closing anchor tags. */
245 + __( '%1$sView version %2$s details%3$s or %4$supdate now%5$s.', 'polylang' ),
246 + '<a target="_blank" class="thickbox open-plugin-details-modal" href="' . esc_url( $changelog_link ) . '">',
247 + esc_html( $update_cache->response[ $this->name ]->new_version ),
248 + '</a>',
249 + '<a target="_blank" class="update-link" href="' . esc_url( wp_nonce_url( $update_link, 'upgrade-plugin_' . $file ) ) . '">',
250 + '</a>'
251 + );
234 252 } else {
235 -
236 - $version_info = $update_cache->response[ $this->name ];
237 -
253 + printf(
254 + ' %1$s%2$s%3$s',
255 + '<a target="_blank" class="update-link" href="' . esc_url( wp_nonce_url( $update_link, 'upgrade-plugin_' . $file ) ) . '">',
256 + esc_html__( 'Update now.', 'polylang' ),
257 + '</a>'
258 + );
238 259 }
239 260
240 - // Restore our filter
241 - add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
261 + do_action( "in_plugin_update_message-{$file}", $plugin, $plugin );
242 262
243 - if ( ! empty( $update_cache->response[ $this->name ] ) && version_compare( $this->version, $version_info->new_version, '<' ) ) {
263 + echo '</p></div></td></tr>';
264 + }
244 265
245 - // build a plugin list row, with update notification
246 - $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
247 - # <tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange">
248 - echo '<tr class="plugin-update-tr" id="' . $this->slug . '-update" data-slug="' . $this->slug . '" data-plugin="' . $this->slug . '/' . $file . '">';
249 - echo '<td colspan="3" class="plugin-update colspanchange">';
250 - echo '<div class="update-message notice inline notice-warning notice-alt">';
266 + /**
267 + * Gets the plugins active in a multisite network.
268 + *
269 + * @return array
270 + */
271 + private function get_active_plugins() {
272 + $active_plugins = (array) get_option( 'active_plugins' );
273 + $active_network_plugins = (array) get_site_option( 'active_sitewide_plugins' );
251 274
252 - $changelog_link = self_admin_url( 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $this->name . '&slug=' . $this->slug . '&TB_iframe=true&width=772&height=911' );
253 -
254 - if ( empty( $version_info->download_link ) ) {
255 - printf(
256 - /* translators: %1$s plugin name, %3$s plugin version, %2$s is link start tag, %4$s is link end tag. */
257 - __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s.', 'polylang' ),
258 - esc_html( $version_info->name ),
259 - '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
260 - esc_html( $version_info->new_version ),
261 - '</a>'
262 - );
263 - } else {
264 - printf(
265 - /* translators: %1$s plugin name, %3$s plugin version, %2$s and %5$s are link start tags, %4$s and %6$s are link end tags. */
266 - __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s or %5$supdate now%6$s.', 'polylang' ),
267 - esc_html( $version_info->name ),
268 - '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
269 - esc_html( $version_info->new_version ),
270 - '</a>',
271 - '<a href="' . esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) ) .'">',
272 - '</a>'
273 - );
274 - }
275 -
276 - do_action( "in_plugin_update_message-{$file}", $plugin, $version_info );
277 -
278 - echo '</div></td></tr>';
279 - }
275 + return array_merge( $active_plugins, array_keys( $active_network_plugins ) );
280 276 }
281 277
282 278 /**
283 279 * Updates information on the "View version x.x details" page with custom data.
@@ -290,15 +286,15 @@
290 286 * @return object $_data
291 287 */
292 288 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
293 289
294 - if ( $_action != 'plugin_information' ) {
290 + if ( 'plugin_information' !== $_action ) {
295 291
296 292 return $_data;
297 293
298 294 }
299 295
300 - if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) {
296 + if ( ! isset( $_args->slug ) || ( $_args->slug !== $this->slug ) ) {
301 297
302 298 return $_data;
303 299
304 300 }
@@ -309,9 +305,9 @@
309 305 'fields' => array(
310 306 'banners' => array(),
311 307 'reviews' => false,
312 308 'icons' => array(),
313 - )
309 + ),
314 310 );
315 311
316 312 // Get the transient where we store the api request for this plugin for 24 hours
317 313 $edd_api_request_transient = $this->get_cached_version_info();
@@ -326,9 +322,8 @@
326 322
327 323 if ( false !== $api_response ) {
328 324 $_data = $api_response;
329 325 }
330 -
331 326 } else {
332 327 $_data = $edd_api_request_transient;
333 328 }
334 329
@@ -351,9 +346,9 @@
351 346 if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) {
352 347 $_data->contributors = $this->convert_object_to_array( $_data->contributors );
353 348 }
354 349
355 - if( ! isset( $_data->plugin ) ) {
350 + if ( ! isset( $_data->plugin ) ) {
356 351 $_data->plugin = $this->name;
357 352 }
358 353
359 354 return $_data;
@@ -371,8 +366,11 @@
371 366 *
372 367 * @return array
373 368 */
374 369 private function convert_object_to_array( $data ) {
370 + if ( ! is_array( $data ) && ! is_object( $data ) ) {
371 + return array();
372 + }
375 373 $new_data = array();
376 374 foreach ( $data as $key => $value ) {
377 375 $new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
378 376 }
@@ -388,11 +386,10 @@
388 386 * @return object $array
389 387 */
390 388 public function http_request_args( $args, $url ) {
391 389
392 - $verify_ssl = $this->verify_ssl();
393 390 if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
394 - $args['sslverify'] = $verify_ssl;
391 + $args['sslverify'] = $this->verify_ssl();
395 392 }
396 393 return $args;
397 394
398 395 }
@@ -397,9 +394,9 @@
397 394
398 395 }
399 396
400 397 /**
401 - * Calls the API and, if successfull, returns the object delivered by the API.
398 + * Calls the API and, if successful, returns the object delivered by the API.
402 399 *
403 400 * @uses get_bloginfo()
404 401 * @uses wp_remote_post()
405 402 * @uses is_wp_error()
@@ -405,87 +402,70 @@
405 402 * @uses is_wp_error()
406 403 *
407 404 * @param string $_action The requested action.
408 405 * @param array $_data Parameters for the API action.
409 - * @return false|object
406 + * @return false|object|void
410 407 */
411 408 private function api_request( $_action, $_data ) {
409 + $data = array_merge( $this->api_data, $_data );
412 410
413 - global $wp_version, $edd_plugin_url_available;
414 -
415 - $verify_ssl = $this->verify_ssl();
416 -
417 - // Do a quick status check on this domain if we haven't already checked it.
418 - $store_hash = md5( $this->api_url );
419 - if ( ! is_array( $edd_plugin_url_available ) || ! isset( $edd_plugin_url_available[ $store_hash ] ) ) {
420 - $test_url_parts = parse_url( $this->api_url );
421 -
422 - $scheme = ! empty( $test_url_parts['scheme'] ) ? $test_url_parts['scheme'] : 'http';
423 - $host = ! empty( $test_url_parts['host'] ) ? $test_url_parts['host'] : '';
424 - $port = ! empty( $test_url_parts['port'] ) ? ':' . $test_url_parts['port'] : '';
425 -
426 - if ( empty( $host ) ) {
427 - $edd_plugin_url_available[ $store_hash ] = false;
428 - } else {
429 - $test_url = $scheme . '://' . $host . $port;
430 - $response = wp_remote_get( $test_url, array( 'timeout' => $this->health_check_timeout, 'sslverify' => $verify_ssl ) );
431 - $edd_plugin_url_available[ $store_hash ] = is_wp_error( $response ) ? false : true;
432 - }
411 + if ( $data['slug'] !== $this->slug ) {
412 + return;
433 413 }
434 414
435 - if ( false === $edd_plugin_url_available[ $store_hash ] ) {
415 + // Don't allow a plugin to ping itself
416 + if ( trailingslashit( home_url() ) === $this->api_url ) {
436 417 return false;
437 418 }
438 419
439 - $data = array_merge( $this->api_data, $_data );
440 -
441 - if ( $data['slug'] != $this->slug ) {
420 + if ( $this->request_recently_failed() ) {
442 421 return false;
443 422 }
444 423
445 - if ( $this->api_url == trailingslashit ( home_url() ) ) {
446 - return false; // Don't allow a plugin to ping itself
447 - }
424 + return $this->get_version_from_remote();
425 + }
448 426
449 - $api_params = array(
450 - 'edd_action' => 'get_version',
451 - 'license' => ! empty( $data['license'] ) ? $data['license'] : '',
452 - 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
453 - 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
454 - 'version' => isset( $data['version'] ) ? $data['version'] : false,
455 - 'slug' => $data['slug'],
456 - 'author' => $data['author'],
457 - 'url' => home_url(),
458 - 'beta' => ! empty( $data['beta'] ),
459 - );
427 + /**
428 + * Determines if a request has recently failed.
429 + *
430 + * @since 1.9.1
431 + *
432 + * @return bool
433 + */
434 + private function request_recently_failed() {
435 + $failed_request_details = get_option( $this->failed_request_cache_key );
460 436
461 - $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
462 -
463 - if ( ! is_wp_error( $request ) ) {
464 - $request = json_decode( wp_remote_retrieve_body( $request ) );
437 + // Request has never failed.
438 + if ( empty( $failed_request_details ) || ! is_numeric( $failed_request_details ) ) {
439 + return false;
465 440 }
466 441
467 - if ( $request && isset( $request->sections ) ) {
468 - $request->sections = maybe_unserialize( $request->sections );
469 - } else {
470 - $request = false;
471 - }
442 + /*
443 + * Request previously failed, but the timeout has expired.
444 + * This means we're allowed to try again.
445 + */
446 + if ( time() > $failed_request_details ) {
447 + delete_option( $this->failed_request_cache_key );
472 448
473 - if ( $request && isset( $request->banners ) ) {
474 - $request->banners = maybe_unserialize( $request->banners );
449 + return false;
475 450 }
476 451
477 - if ( $request && isset( $request->icons ) ) {
478 - $request->icons = maybe_unserialize( $request->icons );
479 - }
452 + return true;
453 + }
480 454
481 - if ( ! empty( $request->sections ) ) {
482 - foreach( $request->sections as $key => $section ) {
483 - $request->$key = (array) $section;
484 - }
485 - }
486 -
487 - return $request;
455 + /**
456 + * Logs a failed HTTP request for this API URL.
457 + * We set a timestamp for 1 hour from now. This prevents future API requests from being
458 + * made to this domain for 1 hour. Once the timestamp is in the past, API requests
459 + * will be allowed again. This way if the site is down for some reason we don't bombard
460 + * it with failed API requests.
461 + *
462 + * @see EDD_SL_Plugin_Updater::request_recently_failed
463 + *
464 + * @since 1.9.1
465 + */
466 + private function log_failed_request() {
467 + update_option( $this->failed_request_cache_key, strtotime( '+1 hour' ) );
488 468 }
489 469
490 470 /**
491 471 * If available, show the changelog for sites in a multisite install.
@@ -491,92 +471,121 @@
491 471 * If available, show the changelog for sites in a multisite install.
492 472 */
493 473 public function show_changelog() {
494 474
495 - global $edd_plugin_data;
475 + if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action'] ) {
476 + return;
477 + }
496 478
497 - if( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) {
479 + if ( empty( $_REQUEST['plugin'] ) ) {
498 480 return;
499 481 }
500 482
501 - if( empty( $_REQUEST['plugin'] ) ) {
483 + if ( empty( $_REQUEST['slug'] ) || $this->slug !== $_REQUEST['slug'] ) {
502 484 return;
503 485 }
504 486
505 - if( empty( $_REQUEST['slug'] ) ) {
506 - return;
487 + if ( ! current_user_can( 'update_plugins' ) ) {
488 + wp_die( esc_html__( 'You do not have permission to install plugin updates', 'polylang' ), esc_html__( 'Error', 'polylang' ), array( 'response' => 403 ) );
507 489 }
508 490
509 - if( ! current_user_can( 'update_plugins' ) ) {
510 - wp_die( __( 'You do not have permission to install plugin updates', 'polylang' ), __( 'Error', 'polylang' ), array( 'response' => 403 ) );
491 + $version_info = $this->get_repo_api_data();
492 + if ( isset( $version_info->sections ) ) {
493 + $sections = $this->convert_object_to_array( $version_info->sections );
494 + if ( ! empty( $sections['changelog'] ) ) {
495 + echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
496 + }
511 497 }
512 498
513 - $data = $edd_plugin_data[ $_REQUEST['slug'] ];
514 - $version_info = $this->get_cached_version_info();
499 + exit;
500 + }
515 501
516 - if( false === $version_info ) {
502 + /**
503 + * Gets the current version information from the remote site.
504 + *
505 + * @return array|false
506 + */
507 + private function get_version_from_remote() {
508 + $api_params = array(
509 + 'edd_action' => 'get_version',
510 + 'license' => ! empty( $this->api_data['license'] ) ? $this->api_data['license'] : '',
511 + 'item_name' => isset( $this->api_data['item_name'] ) ? $this->api_data['item_name'] : false,
512 + 'item_id' => isset( $this->api_data['item_id'] ) ? $this->api_data['item_id'] : false,
513 + 'version' => isset( $this->api_data['version'] ) ? $this->api_data['version'] : false,
514 + 'slug' => $this->slug,
515 + 'author' => $this->api_data['author'],
516 + 'url' => home_url(),
517 + 'beta' => $this->beta,
518 + 'php_version' => phpversion(),
519 + 'wp_version' => get_bloginfo( 'version' ),
520 + );
517 521
518 - $api_params = array(
519 - 'edd_action' => 'get_version',
520 - 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
521 - 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
522 - 'slug' => $_REQUEST['slug'],
523 - 'author' => $data['author'],
524 - 'url' => home_url(),
525 - 'beta' => ! empty( $data['beta'] )
526 - );
522 + /**
523 + * Filters the parameters sent in the API request.
524 + *
525 + * @param array $api_params The array of data sent in the request.
526 + * @param array $this->api_data The array of data set up in the class constructor.
527 + * @param string $this->plugin_file The full path and filename of the file.
528 + */
529 + $api_params = apply_filters( 'edd_sl_plugin_updater_api_params', $api_params, $this->api_data, $this->plugin_file );
527 530
528 - $verify_ssl = $this->verify_ssl();
529 - $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
531 + $request = wp_remote_post(
532 + $this->api_url,
533 + array(
534 + 'timeout' => 15,
535 + 'sslverify' => $this->verify_ssl(),
536 + 'body' => $api_params,
537 + )
538 + );
530 539
531 - if ( ! is_wp_error( $request ) ) {
532 - $version_info = json_decode( wp_remote_retrieve_body( $request ) );
533 - }
540 + if ( is_wp_error( $request ) || ( 200 !== wp_remote_retrieve_response_code( $request ) ) ) {
541 + $this->log_failed_request();
534 542
535 - if ( ! empty( $version_info ) && isset( $version_info->sections ) ) {
536 - $version_info->sections = maybe_unserialize( $version_info->sections );
537 - } else {
538 - $version_info = false;
539 - }
543 + return false;
544 + }
540 545
541 - if( ! empty( $version_info ) ) {
542 - foreach( $version_info->sections as $key => $section ) {
543 - $version_info->$key = (array) $section;
544 - }
545 - }
546 + $request = json_decode( wp_remote_retrieve_body( $request ) );
546 547
547 - $this->set_version_info_cache( $version_info );
548 + if ( $request && isset( $request->sections ) ) {
549 + $request->sections = maybe_unserialize( $request->sections );
550 + } else {
551 + $request = false;
552 + }
548 553
549 - // Delete the unneeded option
550 - delete_option( md5( 'edd_plugin_' . sanitize_key( $_REQUEST['plugin'] ) . '_' . $this->beta . '_version_info' ) );
554 + if ( $request && isset( $request->banners ) ) {
555 + $request->banners = maybe_unserialize( $request->banners );
551 556 }
552 557
553 - if ( isset( $version_info->sections ) ) {
554 - $sections = $this->convert_object_to_array( $version_info->sections );
555 - if ( ! empty( $sections['changelog'] ) ) {
556 - echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
558 + if ( $request && isset( $request->icons ) ) {
559 + $request->icons = maybe_unserialize( $request->icons );
560 + }
561 +
562 + if ( ! empty( $request->sections ) ) {
563 + foreach ( $request->sections as $key => $section ) {
564 + $request->$key = (array) $section;
557 565 }
558 566 }
559 567
560 - exit;
568 + return $request;
561 569 }
562 570
563 571 /**
564 - * Gets the plugin's cached version information from the database.
572 + * Get the version info from the cache, if it exists.
565 573 *
566 574 * @param string $cache_key
567 - * @return boolean|string
575 + * @return object
568 576 */
569 577 public function get_cached_version_info( $cache_key = '' ) {
570 578
571 - if( empty( $cache_key ) ) {
572 - $cache_key = $this->cache_key;
579 + if ( empty( $cache_key ) ) {
580 + $cache_key = $this->get_cache_key();
573 581 }
574 582
575 583 $cache = get_option( $cache_key );
576 584
577 - if( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
578 - return false; // Cache is expired
585 + // Cache is expired
586 + if ( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
587 + return false;
579 588 }
580 589
581 590 // We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
582 591 $cache['value'] = json_decode( $cache['value'] );
@@ -595,15 +604,15 @@
595 604 * @param string $cache_key
596 605 */
597 606 public function set_version_info_cache( $value = '', $cache_key = '' ) {
598 607
599 - if( empty( $cache_key ) ) {
600 - $cache_key = $this->cache_key;
608 + if ( empty( $cache_key ) ) {
609 + $cache_key = $this->get_cache_key();
601 610 }
602 611
603 612 $data = array(
604 613 'timeout' => strtotime( '+3 hours', time() ),
605 - 'value' => json_encode( $value )
614 + 'value' => wp_json_encode( $value ),
606 615 );
607 616
608 617 update_option( $cache_key, $data, 'no' );
609 618
@@ -618,7 +627,19 @@
618 627 * @return bool
619 628 */
620 629 private function verify_ssl() {
621 630 return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
631 + }
632 +
633 + /**
634 + * Gets the unique key (option name) for a plugin.
635 + *
636 + * @since 1.9.0
637 + * @return string
638 + */
639 + private function get_cache_key() {
640 + $string = $this->slug . $this->api_data['license'] . $this->beta;
641 +
642 + return 'edd_sl_' . md5( serialize( $string ) );
622 643 }
623 644
624 645 }