PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.24
Advanced Ads – Ad Manager & AdSense v2.0.24
2.0.25 2.0.24 2.0.23 2.0.22 2.0.21 1.38.0 1.39.0 1.39.1 1.39.2 1.39.3 1.39.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.42.1 1.42.2 1.43.0 1.44.0 1.44.1 1.45.0 1.45.1 1.46.0 1.47.0 1.47.1 1.47.2 1.47.3 1.47.4 1.47.5 1.48.0 1.48.1 1.49.0 1.5.0 1.5.0.1 1.5.1 1.5.2 1.5.2.1 1.5.4 1.5.4.1 1.5.5 1.50.0 1.51.0 1.51.1 1.51.2 1.51.3 1.52.0 1.52.1 1.52.2 1.52.3 1.52.4 1.53.0 1.53.1 1.53.2 1.54.0 1.54.1 1.55.0 1.56.0 1.56.1 1.56.2 1.56.3 1.56.4 1.6 1.6.1 1.6.10 1.6.10.1 1.6.10.2 1.6.11 1.6.11.1 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.17.1 1.6.17.2 1.6.2 1.6.2.1 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.6.1 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.6.8.3 1.6.9 1.6.9.1 1.6.9.2 1.6.9.3 1.6.9.4 1.7 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.1.1 1.7.1.2 1.7.1.3 1.7.1.4 1.7.1.5 1.7.10 trunk 1.7.11 1.0.1 1.7.12 1.0.2 1.7.13 1.0.3 1.7.14 1.1.0 1.7.15 1.1.1 1.7.16 1.1.2 1.7.17 1.1.3 1.7.18 1.10 1.7.19 1.10.1 1.7.2 1.10.10 1.7.2.1 1.10.11 1.7.20 1.10.12 1.7.21 1.10.2 1.7.22 1.10.3 1.7.23 1.10.4 1.7.24 1.10.5 1.7.25 1.10.6 1.7.3 1.10.7 1.7.4 1.10.8 1.7.4.1 1.10.9 1.7.4.2 1.11 1.7.4.3 1.11.1 1.7.4.4 1.11.2 1.7.4.5 1.12 1.7.5 1.13 1.7.5.1 1.13.1 1.7.6 1.13.2 1.7.7 1.13.3 1.7.8 1.13.4 1.7.9 1.13.5 1.7.9.1 1.13.6 1.7.9.2 1.13.7 1.7.9.3 1.13.8 1.8 1.14 1.8.1 1.14.1 1.8.10 1.14.10 1.8.11 1.14.11 1.8.12 1.14.2 1.8.13 1.14.3 1.8.14 1.14.4 1.8.15 1.14.5 1.8.16 1.14.6 1.8.17 1.14.7 1.8.18 1.14.8 1.8.19 1.14.9 1.8.2 1.15 1.8.20 1.16 1.8.21 1.16.1 1.8.22 1.17 1.8.23 1.17.1 1.8.24 1.17.10 1.8.25 1.17.10-rc.1 1.8.26 1.17.11 1.8.27 1.17.12 1.8.28 1.17.12-rc.1 1.8.29 1.17.2 1.8.3 1.17.3 1.8.30 1.17.4 1.8.4 1.17.5 1.8.5 1.17.6 1.8.6 1.17.7 1.8.7 1.17.8 1.8.8 1.17.9 1.8.9 1.17.9-beta.1 1.9 1.18.0 2.0.0 1.19.0 2.0.1 1.19.1 2.0.10 1.2 2.0.11 1.2.1 2.0.12 1.2.2 2.0.13 1.2.3 2.0.14 1.2.4 2.0.15 1.2.5 2.0.16 1.2.6 2.0.17 1.2.7 2.0.18 1.20.0 2.0.19 1.20.0-rc.1 2.0.2 1.20.0-rc.2 2.0.20 1.20.1 2.0.3 1.20.2 2.0.4 1.20.3 2.0.5 1.21.0 2.0.6 1.21.1 2.0.7 1.22.0 2.0.8 1.22.1 2.0.9 1.22.2 1.23.0 1.23.1 1.23.2 1.24.0 1.24.1 1.24.2 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.29.0 1.29.1 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.30.0 1.30.1 1.30.2 1.30.2-rc.1 1.30.3 1.30.4 1.30.4-rc.1 1.30.5 1.31.0 1.31.1 1.32.0 1.32.0-rc.1 1.33.0 1.33.1 1.33.2 1.34.0 1.35.0 1.35.1 1.36.0 1.36.1 1.36.2 1.36.3 1.37.0 1.37.1 1.37.2
advanced-ads / includes / admin / class-edd-updater.php
advanced-ads / includes / admin Last commit date
ads 1 week ago groups 1 week ago metaboxes 1 year ago pages 3 months ago placements 1 week ago class-action-links.php 1 week ago class-addon-box.php 1 year ago class-addon-updater.php 3 months ago class-admin-menu.php 1 week ago class-admin-notices.php 1 year ago class-ajax.php 3 months ago class-assets.php 1 week ago class-authors.php 1 year ago class-edd-updater.php 1 month ago class-list-filters.php 1 week ago class-marketing.php 1 year ago class-metabox-ad-settings.php 1 year ago class-metabox-ad.php 1 year ago class-misc.php 1 week ago class-page-quick-edit.php 1 year ago class-plugin-installer.php 1 year ago class-post-list.php 1 year ago class-post-types.php 1 week ago class-screen-options.php 3 months ago class-settings.php 1 year ago class-shortcode-creator.php 1 year ago class-system-info.php 1 year ago class-tinymce.php 2 years ago class-translation-promo.php 1 year ago class-upgrades.php 1 year ago class-version-control.php 3 months ago class-welcome.php 1 year ago class-wordpress-dashboard.php 1 year ago index.php 2 years ago
class-edd-updater.php
765 lines
1 <?php // phpcs:ignoreFile
2 /**
3 * Allows plugins to use their own update API.
4 *
5 * @package AdvancedAds
6 * @author Advanced Ads <info@wpadvancedads.com>
7 * @since 1.50.0
8 */
9
10 namespace AdvancedAds\Admin;
11
12 defined( 'ABSPATH' ) || exit;
13
14 /**
15 * Class Updater
16 */
17 class EDD_Updater {
18
19 /**
20 * The URL pointing to the custom API endpoint.
21 *
22 * @var string
23 */
24 private $api_url = '';
25
26 /**
27 * Optional data to send with API calls.
28 *
29 * @var array
30 */
31 private $api_data = [];
32
33 /**
34 * Path to the plugin file.
35 *
36 * @var string
37 */
38 private $plugin_file = '';
39
40 /**
41 * The plugin basename.
42 *
43 * @var string
44 */
45 private $name = '';
46
47 /**
48 * The plugin slug.
49 *
50 * @var string
51 */
52 private $slug = '';
53
54 /**
55 * The plugin version.
56 *
57 * @var string
58 */
59 private $version = '';
60
61 /**
62 * Whether to override the WordPress.org update check.
63 *
64 * @var bool
65 */
66 private $wp_override = false;
67
68 /**
69 * Whether to check for beta versions.
70 *
71 * @var bool
72 */
73 private $beta = false;
74
75 /**
76 * The cache key for failed requests.
77 *
78 * @var string
79 */
80 private $failed_request_cache_key;
81
82 /**
83 * Class constructor.
84 *
85 * @uses plugin_basename()
86 * @uses hook()
87 *
88 * @param string $_api_url The URL pointing to the custom API endpoint.
89 * @param string $_plugin_file Path to the plugin file.
90 * @param array $_api_data Optional data to send with API calls.
91 */
92 public function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
93 global $edd_plugin_data;
94
95 $this->api_url = trailingslashit( $_api_url );
96 $this->api_data = $_api_data;
97 $this->plugin_file = $_plugin_file;
98 $this->name = plugin_basename( $_plugin_file );
99 $this->slug = basename( dirname( $_plugin_file ) );
100 $this->version = $_api_data['version'];
101 $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
102 $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
103 $this->failed_request_cache_key = 'edd_sl_failed_http_' . md5( $this->api_url );
104
105 $edd_plugin_data[ $this->slug ] = $this->api_data;
106
107 /**
108 * Fires after the $edd_plugin_data is setup.
109 *
110 * @since x.x.x
111 *
112 * @param array $edd_plugin_data Array of EDD SL plugin data.
113 */
114 do_action( 'post_edd_sl_plugin_updater_setup', $edd_plugin_data );
115
116 // Set up hooks.
117 $this->init();
118 }
119
120 /**
121 * Set up WordPress filters to hook into WP's update process.
122 *
123 * @uses add_filter()
124 *
125 * @return void
126 */
127 public function init() {
128 add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'check_update' ] );
129 add_filter( 'plugins_api', [ $this, 'plugins_api_filter' ], 10, 3 );
130 add_action( 'after_plugin_row', [ $this, 'show_update_notification' ], 10, 2 );
131 add_action( 'admin_init', [ $this, 'show_changelog' ] );
132 }
133
134 /**
135 * Check for Updates at the defined API endpoint and modify the update array.
136 *
137 * This function dives into the update API just when WordPress creates its update array,
138 * then adds a custom API call and injects the custom plugin data retrieved from the API.
139 * It is reassembled from parts of the native WordPress plugin update code.
140 * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
141 *
142 * @uses api_request()
143 *
144 * @param array $_transient_data Update array build by WordPress.
145 * @return array Modified update array with custom plugin data.
146 */
147 public function check_update( $_transient_data ) {
148
149 if ( ! is_object( $_transient_data ) ) {
150 $_transient_data = new \stdClass();
151 }
152
153 if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
154 return $_transient_data;
155 }
156
157 $current = $this->get_update_transient_data();
158 if ( false !== $current && is_object( $current ) && isset( $current->new_version ) ) {
159 if ( version_compare( $this->version, $current->new_version, '<' ) ) {
160 $_transient_data->response[ $this->name ] = $current;
161 } else {
162 // Populating the no_update information is required to support auto-updates in WordPress 5.5.
163 $_transient_data->no_update[ $this->name ] = $current;
164 }
165 }
166 $_transient_data->last_checked = time();
167 $_transient_data->checked[ $this->name ] = $this->version;
168
169 return $_transient_data;
170 }
171
172 /**
173 * Get repo API data from store.
174 * Save to cache.
175 *
176 * @return \stdClass
177 */
178 public function get_repo_api_data() {
179 $version_info = $this->get_cached_version_info();
180
181 if ( false === $version_info ) {
182 $version_info = $this->api_request(
183 'plugin_latest_version',
184 [
185 'slug' => $this->slug,
186 'beta' => $this->beta,
187 ]
188 );
189 if ( ! $version_info ) {
190 return false;
191 }
192
193 // This is required for your plugin to support auto-updates in WordPress 5.5.
194 $version_info->plugin = $this->name;
195 $version_info->id = $this->name;
196 $version_info->tested = $this->get_tested_version( $version_info );
197 if ( ! isset( $version_info->requires ) ) {
198 $version_info->requires = '';
199 }
200 if ( ! isset( $version_info->requires_php ) ) {
201 $version_info->requires_php = '';
202 }
203
204 $this->set_version_info_cache( $version_info );
205 }
206
207 return $version_info;
208 }
209
210 /**
211 * Gets a limited set of data from the API response.
212 * This is used for the update_plugins transient.
213 *
214 * @since 3.8.12
215 * @return \stdClass|false
216 */
217 private function get_update_transient_data() {
218 $version_info = $this->get_repo_api_data();
219
220 if ( ! $version_info ) {
221 return false;
222 }
223
224 $limited_data = new \stdClass();
225 $limited_data->slug = $this->slug;
226 $limited_data->plugin = $this->name;
227 $limited_data->url = $version_info->url ?? '';
228 $limited_data->package = $version_info->package;
229 $limited_data->icons = $this->convert_object_to_array( $version_info->icons );
230 $limited_data->banners = $this->convert_object_to_array( $version_info->banners );
231 $limited_data->new_version = $version_info->new_version;
232 $limited_data->tested = $version_info->tested ?? '6.7';
233 $limited_data->requires = $version_info->requires ?? '5.7';
234 $limited_data->requires_php = $version_info->requires_php ?? '7.4';
235
236 return $limited_data;
237 }
238
239 /**
240 * Gets the plugin's tested version.
241 *
242 * @since 1.9.2
243 * @param object $version_info The version info object.
244 * @return null|string
245 */
246 private function get_tested_version( $version_info ) {
247
248 // There is no tested version.
249 if ( empty( $version_info->tested ) ) {
250 return null;
251 }
252
253 // Strip off extra version data so the result is x.y or x.y.z.
254 list( $current_wp_version ) = explode( '-', get_bloginfo( 'version' ) );
255
256 // The tested version is greater than or equal to the current WP version, no need to do anything.
257 if ( version_compare( $version_info->tested, $current_wp_version, '>=' ) ) {
258 return $version_info->tested;
259 }
260 $current_version_parts = explode( '.', $current_wp_version );
261 $tested_parts = explode( '.', $version_info->tested );
262
263 // The current WordPress version is x.y.z, so update the tested version to match it.
264 if ( isset( $current_version_parts[2] ) && $current_version_parts[0] === $tested_parts[0] && $current_version_parts[1] === $tested_parts[1] ) {
265 $tested_parts[2] = $current_version_parts[2];
266 }
267
268 return implode( '.', $tested_parts );
269 }
270
271 /**
272 * Show the update notification on multisite subsites.
273 *
274 * @param string $file The plugin file.
275 * @param array $plugin The plugin data.
276 */
277 public function show_update_notification( $file, $plugin ) {
278
279 // Return early if in the network admin, or if this is not a multisite install.
280 if ( is_network_admin() || ! is_multisite() ) {
281 return;
282 }
283
284 // Allow single site admins to see that an update is available.
285 if ( ! current_user_can( 'activate_plugins' ) ) {
286 return;
287 }
288
289 if ( $this->name !== $file ) {
290 return;
291 }
292
293 // Do not print any message if update does not exist.
294 $update_cache = get_site_transient( 'update_plugins' );
295
296 if ( ! isset( $update_cache->response[ $this->name ] ) ) {
297 if ( ! is_object( $update_cache ) ) {
298 $update_cache = new \stdClass();
299 }
300 $update_cache->response[ $this->name ] = $this->get_repo_api_data();
301 }
302
303 // 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.
304 if ( empty( $update_cache->response[ $this->name ] ) || version_compare( $this->version, $update_cache->response[ $this->name ]->new_version, '>=' ) ) {
305 return;
306 }
307
308 printf(
309 '<tr class="plugin-update-tr %3$s" id="%1$s-update" data-slug="%1$s" data-plugin="%2$s">',
310 $this->slug, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
311 $file, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
312 in_array( $this->name, $this->get_active_plugins(), true ) ? 'active' : 'inactive'
313 );
314
315 echo '<td colspan="3" class="plugin-update colspanchange">';
316 echo '<div class="update-message notice inline notice-warning notice-alt"><p>';
317
318 $changelog_link = '';
319 if ( ! empty( $update_cache->response[ $this->name ]->sections->changelog ) ) {
320 $changelog_link = add_query_arg(
321 [
322 'edd_sl_action' => 'view_plugin_changelog',
323 'plugin' => rawurlencode( $this->name ),
324 'slug' => rawurlencode( $this->slug ),
325 'TB_iframe' => 'true',
326 'width' => 77,
327 'height' => 911,
328 ],
329 self_admin_url( 'index.php' )
330 );
331 }
332 $update_link = add_query_arg(
333 [
334 'action' => 'upgrade-plugin',
335 'plugin' => rawurlencode( $this->name ),
336 ],
337 self_admin_url( 'update.php' )
338 );
339
340 printf(
341 /* translators: the plugin name. */
342 esc_html__( 'There is a new version of %1$s available.', 'advanced-ads' ),
343 esc_html( $plugin['Name'] )
344 );
345
346 if ( ! current_user_can( 'update_plugins' ) ) {
347 echo ' ';
348 esc_html_e( 'Contact your network administrator to install the update.', 'advanced-ads' );
349 } elseif ( empty( $update_cache->response[ $this->name ]->package ) && ! empty( $changelog_link ) ) {
350 echo ' ';
351 printf(
352 /* translators: 1: opening anchor tag, do not translate 2. the new plugin version 3. closing anchor tag, do not translate. */
353 __( '%1$sView version %2$s details%3$s.', 'advanced-ads' ), // phpcs:ignore
354 '<a target="_blank" class="thickbox open-plugin-details-modal" href="' . esc_url( $changelog_link ) . '">',
355 esc_html( $update_cache->response[ $this->name ]->new_version ),
356 '</a>'
357 );
358 } elseif ( ! empty( $changelog_link ) ) {
359 echo ' ';
360 printf(
361 /* translators: 1: opening anchor tag, do not translate 2. the new plugin version 3. closing anchor tag, do not translate 4. opening anchor tag, do not translate 5. closing anchor tag, do not translate. */
362 __( '%1$sView version %2$s details%3$s or %4$supdate now%5$s.', 'advanced-ads' ), // phpcs:ignore
363 '<a target="_blank" class="thickbox open-plugin-details-modal" href="' . esc_url( $changelog_link ) . '">',
364 esc_html( $update_cache->response[ $this->name ]->new_version ),
365 '</a>',
366 '<a target="_blank" class="update-link" href="' . esc_url( wp_nonce_url( $update_link, 'upgrade-plugin_' . $file ) ) . '">',
367 '</a>'
368 );
369 } else {
370 printf(
371 ' %1$s%2$s%3$s',
372 '<a target="_blank" class="update-link" href="' . esc_url( wp_nonce_url( $update_link, 'upgrade-plugin_' . $file ) ) . '">',
373 esc_html__( 'Update now.', 'advanced-ads' ),
374 '</a>'
375 );
376 }
377
378 do_action( "in_plugin_update_message-{$file}", $plugin, $plugin );
379
380 echo '</p></div></td></tr>';
381 }
382
383 /**
384 * Gets the plugins active in a multisite network.
385 *
386 * @return array
387 */
388 private function get_active_plugins() {
389 $active_plugins = (array) get_option( 'active_plugins' );
390 $active_network_plugins = (array) get_site_option( 'active_sitewide_plugins' );
391
392 return array_merge( $active_plugins, array_keys( $active_network_plugins ) );
393 }
394
395 /**
396 * Updates information on the "View version x.x details" page with custom data.
397 *
398 * @uses api_request()
399 *
400 * @param mixed $_data The data originally requested.
401 * @param string $_action The type of information being requested.
402 * @param object $_args Plugin API arguments.
403 * @return object $_data
404 */
405 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
406
407 if ( 'plugin_information' !== $_action ) {
408 return $_data;
409 }
410
411 if ( ! isset( $_args->slug ) || ( $_args->slug !== $this->slug ) ) {
412 return $_data;
413 }
414
415 $to_send = [
416 'slug' => $this->slug,
417 'is_ssl' => is_ssl(),
418 'fields' => [
419 'banners' => [],
420 'reviews' => false,
421 'icons' => [],
422 ],
423 ];
424
425 // Get the transient where we store the api request for this plugin for 24 hours.
426 $edd_api_request_transient = $this->get_cached_version_info();
427
428 // If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now.
429 if ( empty( $edd_api_request_transient ) ) {
430
431 $api_response = $this->api_request( 'plugin_information', $to_send );
432
433 // Expires in 3 hours.
434 $this->set_version_info_cache( $api_response );
435
436 if ( false !== $api_response ) {
437 $_data = $api_response;
438 }
439 } else {
440 $_data = $edd_api_request_transient;
441 }
442
443 // Safeguard: If the API failed or the transient returned false, ensure $_data is an object before proceeding.
444 if ( ! is_object( $_data ) ) {
445 return $_data;
446 }
447
448 // Convert sections into an associative array, since we're getting an object, but Core expects an array.
449 if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
450 $_data->sections = $this->convert_object_to_array( $_data->sections );
451 }
452
453 // Convert banners into an associative array, since we're getting an object, but Core expects an array.
454 if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
455 $_data->banners = $this->convert_object_to_array( $_data->banners );
456 }
457
458 // Convert icons into an associative array, since we're getting an object, but Core expects an array.
459 if ( isset( $_data->icons ) && ! is_array( $_data->icons ) ) {
460 $_data->icons = $this->convert_object_to_array( $_data->icons );
461 }
462
463 // Convert contributors into an associative array, since we're getting an object, but Core expects an array.
464 if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) {
465 $_data->contributors = $this->convert_object_to_array( $_data->contributors );
466 }
467
468 if ( ! isset( $_data->plugin ) ) {
469 $_data->plugin = $this->name;
470 }
471
472 if ( ! isset( $_data->version ) && ! empty( $_data->new_version ) ) {
473 $_data->version = $_data->new_version;
474 }
475
476 return $_data;
477 }
478
479 /**
480 * Convert some objects to arrays when injecting data into the update API
481 *
482 * Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON
483 * decoding, they are objects. This method allows us to pass in the object and return an associative array.
484 *
485 * @since 3.6.5
486 *
487 * @param \stdClass $data The object to convert to an array.
488 *
489 * @return array
490 */
491 private function convert_object_to_array( $data ) {
492 if ( ! is_array( $data ) && ! is_object( $data ) ) {
493 return [];
494 }
495 $new_data = [];
496 foreach ( $data as $key => $value ) {
497 $new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
498 }
499
500 return $new_data;
501 }
502
503 /**
504 * Disable SSL verification in order to prevent download update failures
505 *
506 * @param array $args Array of HTTP request arguments.
507 * @param string $url The request URL.
508 * @return object $array
509 */
510 public function http_request_args( $args, $url ) {
511
512 if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
513 $args['sslverify'] = $this->verify_ssl();
514 }
515 return $args;
516 }
517
518 /**
519 * Calls the API and, if successfull, returns the object delivered by the API.
520 *
521 * @uses get_bloginfo()
522 * @uses wp_remote_post()
523 * @uses is_wp_error()
524 *
525 * @param string $_action The requested action.
526 * @param array $_data Parameters for the API action.
527 * @return false|object|void
528 */
529 private function api_request( $_action, $_data ) {
530 $data = array_merge( $this->api_data, $_data );
531
532 if ( $data['slug'] !== $this->slug ) {
533 return;
534 }
535
536 // Don't allow a plugin to ping itself.
537 if ( trailingslashit( home_url() ) === $this->api_url ) {
538 return false;
539 }
540
541 if ( $this->request_recently_failed() ) {
542 return false;
543 }
544
545 return $this->get_version_from_remote();
546 }
547
548 /**
549 * Determines if a request has recently failed.
550 *
551 * @since 1.9.1
552 *
553 * @return bool
554 */
555 private function request_recently_failed() {
556 $failed_request_details = get_option( $this->failed_request_cache_key );
557
558 // Request has never failed.
559 if ( empty( $failed_request_details ) || ! is_numeric( $failed_request_details ) ) {
560 return false;
561 }
562
563 /*
564 * Request previously failed, but the timeout has expired.
565 * This means we're allowed to try again.
566 */
567 if ( time() > $failed_request_details ) {
568 delete_option( $this->failed_request_cache_key );
569
570 return false;
571 }
572
573 return true;
574 }
575
576 /**
577 * Logs a failed HTTP request for this API URL.
578 * We set a timestamp for 1 hour from now. This prevents future API requests from being
579 * made to this domain for 1 hour. Once the timestamp is in the past, API requests
580 * will be allowed again. This way if the site is down for some reason we don't bombard
581 * it with failed API requests.
582 *
583 * @see EDD_SL_Plugin_Updater::request_recently_failed
584 *
585 * @since 1.9.1
586 */
587 private function log_failed_request() {
588 update_option( $this->failed_request_cache_key, strtotime( '+1 hour' ) );
589 }
590
591 /**
592 * If available, show the changelog for sites in a multisite install.
593 */
594 public function show_changelog() {
595
596 if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action'] ) {
597 return;
598 }
599
600 if ( empty( $_REQUEST['plugin'] ) ) {
601 return;
602 }
603
604 if ( empty( $_REQUEST['slug'] ) || $this->slug !== $_REQUEST['slug'] ) {
605 return;
606 }
607
608 if ( ! current_user_can( 'update_plugins' ) ) {
609 wp_die( esc_html__( 'You do not have permission to install plugin updates', 'advanced-ads' ), esc_html__( 'Error', 'advanced-ads' ), [ 'response' => 403 ] );
610 }
611
612 $version_info = $this->get_repo_api_data();
613 if ( isset( $version_info->sections ) ) {
614 $sections = $this->convert_object_to_array( $version_info->sections );
615 if ( ! empty( $sections['changelog'] ) ) {
616 echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
617 }
618 }
619
620 exit;
621 }
622
623 /**
624 * Gets the current version information from the remote site.
625 *
626 * @return array|false
627 */
628 private function get_version_from_remote() {
629 $api_params = [
630 'edd_action' => 'get_version',
631 'license' => ! empty( $this->api_data['license'] ) ? $this->api_data['license'] : '',
632 'item_name' => isset( $this->api_data['item_name'] ) ? $this->api_data['item_name'] : false,
633 'item_id' => isset( $this->api_data['item_id'] ) ? $this->api_data['item_id'] : false,
634 'version' => isset( $this->api_data['version'] ) ? $this->api_data['version'] : false,
635 'slug' => $this->slug,
636 'author' => $this->api_data['author'],
637 'url' => home_url(),
638 'beta' => $this->beta,
639 'php_version' => phpversion(),
640 'wp_version' => get_bloginfo( 'version' ),
641 ];
642
643 /**
644 * Filters the parameters sent in the API request.
645 *
646 * @param array $api_params The array of data sent in the request.
647 * @param array $this->api_data The array of data set up in the class constructor.
648 * @param string $this->plugin_file The full path and filename of the file.
649 */
650 $api_params = apply_filters( 'edd_sl_plugin_updater_api_params', $api_params, $this->api_data, $this->plugin_file );
651
652 $request = wp_remote_post(
653 $this->api_url,
654 [
655 'timeout' => 15,
656 'sslverify' => $this->verify_ssl(),
657 'body' => $api_params,
658 ]
659 );
660
661 if ( is_wp_error( $request ) || ( 200 !== wp_remote_retrieve_response_code( $request ) ) ) {
662 $this->log_failed_request();
663
664 return false;
665 }
666
667 $body = json_decode( wp_remote_retrieve_body( $request ) );
668
669 if ( $body && isset( $body->sections ) ) {
670 $body->sections = maybe_unserialize( $body->sections );
671 } else {
672 $body = false;
673 }
674
675 if ( $body && isset( $body->banners ) ) {
676 $body->banners = maybe_unserialize( $body->banners );
677 }
678
679 if ( $body && isset( $body->icons ) ) {
680 $body->icons = maybe_unserialize( $body->icons );
681 }
682
683 if ( ! empty( $body->sections ) ) {
684 foreach ( $body->sections as $key => $section ) {
685 $body->$key = (array) $section;
686 }
687 }
688
689 return $body;
690 }
691
692 /**
693 * Get the version info from the cache, if it exists.
694 *
695 * @param string $cache_key The cache key to use.
696 * @return object
697 */
698 public function get_cached_version_info( $cache_key = '' ) {
699
700 if ( empty( $cache_key ) ) {
701 $cache_key = $this->get_cache_key();
702 }
703
704 $cache = get_option( $cache_key );
705
706 // Cache is expired.
707 if ( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
708 return false;
709 }
710
711 // We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
712 $cache['value'] = json_decode( $cache['value'] );
713 if ( ! empty( $cache['value']->icons ) ) {
714 $cache['value']->icons = (array) $cache['value']->icons;
715 }
716
717 return $cache['value'];
718 }
719
720 /**
721 * Adds the plugin version information to the database.
722 *
723 * @param string $value The value to store.
724 * @param string $cache_key The cache key to use.
725 */
726 public function set_version_info_cache( $value = '', $cache_key = '' ) {
727
728 if ( empty( $cache_key ) ) {
729 $cache_key = $this->get_cache_key();
730 }
731
732 $data = [
733 'timeout' => strtotime( '+12 hours', time() ),
734 'value' => wp_json_encode( $value ),
735 ];
736
737 update_option( $cache_key, $data, 'no' );
738
739 // Delete the duplicate option.
740 delete_option( 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) ) );
741 }
742
743 /**
744 * Returns if the SSL of the store should be verified.
745 *
746 * @since 1.6.13
747 * @return bool
748 */
749 private function verify_ssl() {
750 return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
751 }
752
753 /**
754 * Gets the unique key (option name) for a plugin.
755 *
756 * @since 1.9.0
757 * @return string
758 */
759 private function get_cache_key() {
760 $string = $this->slug . $this->api_data['license'] . $this->beta;
761
762 return 'advads_edd_sl_' . md5( serialize( $string ) );
763 }
764 }
765