PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.1.0
GiveWP – Donation Plugin and Fundraising Platform v2.1.0
4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / admin / EDD_SL_Plugin_Updater.php
give / includes / admin Last commit date
donors 8 years ago emails 8 years ago forms 8 years ago payments 8 years ago reports 8 years ago settings 8 years ago shortcodes 8 years ago tools 8 years ago upgrades 8 years ago views 8 years ago EDD_SL_Plugin_Updater.php 8 years ago abstract-admin-settings-page.php 8 years ago add-ons.php 8 years ago admin-actions.php 8 years ago admin-filters.php 8 years ago admin-footer.php 8 years ago admin-pages.php 8 years ago class-addon-activation-banner.php 8 years ago class-admin-settings.php 8 years ago class-api-keys-table.php 8 years ago class-blank-slate.php 8 years ago class-give-settings.php 8 years ago class-i18n-module.php 8 years ago dashboard-widgets.php 8 years ago give-metabox-functions.php 8 years ago plugins.php 8 years ago welcome.php 8 years ago
EDD_SL_Plugin_Updater.php
477 lines
1 <?php
2
3 // Exit if accessed directly
4 if ( ! defined( 'ABSPATH' ) ) exit;
5
6 /**
7 * Allows plugins to use their own update API.
8 *
9 * @author Easy Digital Downloads
10 * @version 1.6.12
11 */
12 class EDD_SL_Plugin_Updater {
13
14 private $api_url = '';
15 private $api_data = array();
16 private $name = '';
17 private $slug = '';
18 private $version = '';
19 private $wp_override = false;
20 private $cache_key = '';
21
22 /**
23 * Class constructor.
24 *
25 * @uses plugin_basename()
26 * @uses hook()
27 *
28 * @param string $_api_url The URL pointing to the custom API endpoint.
29 * @param string $_plugin_file Path to the plugin file.
30 * @param array $_api_data Optional data to send with API calls.
31 */
32 public function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
33
34 global $edd_plugin_data;
35
36 $this->api_url = trailingslashit( $_api_url );
37 $this->api_data = $_api_data;
38 $this->name = plugin_basename( $_plugin_file );
39 $this->slug = basename( $_plugin_file, '.php' );
40 $this->version = $_api_data['version'];
41 $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
42 $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
43 $this->cache_key = md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );
44
45 $edd_plugin_data[ $this->slug ] = $this->api_data;
46
47 // Set up hooks.
48 $this->init();
49
50 }
51
52 /**
53 * Set up WordPress filters to hook into WP's update process.
54 *
55 * @uses add_filter()
56 *
57 * @return void
58 */
59 public function init() {
60
61 add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
62 add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
63 remove_action( 'after_plugin_row_' . $this->name, 'wp_plugin_update_row', 10 );
64 add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 );
65 add_action( 'admin_init', array( $this, 'show_changelog' ) );
66
67 }
68
69 /**
70 * Check for Updates at the defined API endpoint and modify the update array.
71 *
72 * This function dives into the update API just when WordPress creates its update array,
73 * then adds a custom API call and injects the custom plugin data retrieved from the API.
74 * It is reassembled from parts of the native WordPress plugin update code.
75 * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
76 *
77 * @uses api_request()
78 *
79 * @param array $_transient_data Update array build by WordPress.
80 * @return array Modified update array with custom plugin data.
81 */
82 public function check_update( $_transient_data ) {
83
84 global $pagenow;
85
86 if ( ! is_object( $_transient_data ) ) {
87 $_transient_data = new stdClass;
88 }
89
90 if ( 'plugins.php' == $pagenow && is_multisite() ) {
91 return $_transient_data;
92 }
93
94 if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
95 return $_transient_data;
96 }
97
98 $version_info = $this->get_cached_version_info();
99
100 if ( false === $version_info ) {
101 $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
102
103 $this->set_version_info_cache( $version_info );
104
105 }
106
107 if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
108
109 if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
110
111 $_transient_data->response[ $this->name ] = $version_info;
112
113 }
114
115 $_transient_data->last_checked = current_time( 'timestamp' );
116 $_transient_data->checked[ $this->name ] = $this->version;
117
118 }
119
120 return $_transient_data;
121 }
122
123 /**
124 * show update nofication row -- needed for multisite subsites, because WP won't tell you otherwise!
125 *
126 * @param string $file
127 * @param array $plugin
128 */
129 public function show_update_notification( $file, $plugin ) {
130
131 if ( is_network_admin() ) {
132 return;
133 }
134
135 if( ! current_user_can( 'update_plugins' ) ) {
136 return;
137 }
138
139 if( ! is_multisite() ) {
140 return;
141 }
142
143 if ( $this->name != $file ) {
144 return;
145 }
146
147 // Remove our filter on the site transient
148 remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 );
149
150 $update_cache = get_site_transient( 'update_plugins' );
151
152 $update_cache = is_object( $update_cache ) ? $update_cache : new stdClass();
153
154 if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) {
155
156 $version_info = $this->get_cached_version_info();
157
158 if ( false === $version_info ) {
159 $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
160
161 $this->set_version_info_cache( $version_info );
162 }
163
164 if ( ! is_object( $version_info ) ) {
165 return;
166 }
167
168 if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
169
170 $update_cache->response[ $this->name ] = $version_info;
171
172 }
173
174 $update_cache->last_checked = current_time( 'timestamp' );
175 $update_cache->checked[ $this->name ] = $this->version;
176
177 set_site_transient( 'update_plugins', $update_cache );
178
179 } else {
180
181 $version_info = $update_cache->response[ $this->name ];
182
183 }
184
185 // Restore our filter
186 add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
187
188 if ( ! empty( $update_cache->response[ $this->name ] ) && version_compare( $this->version, $version_info->new_version, '<' ) ) {
189
190 // build a plugin list row, with update notification
191 $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
192 # <tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange">
193 echo '<tr class="plugin-update-tr" id="' . $this->slug . '-update" data-slug="' . $this->slug . '" data-plugin="' . $this->slug . '/' . $file . '">';
194 echo '<td colspan="3" class="plugin-update colspanchange">';
195 echo '<div class="update-message notice inline notice-warning notice-alt">';
196
197 $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' );
198
199 if ( empty( $version_info->download_link ) ) {
200 printf(
201 __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s.', 'give' ),
202 esc_html( $version_info->name ),
203 '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
204 esc_html( $version_info->new_version ),
205 '</a>'
206 );
207 } else {
208 printf(
209 __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s or %5$supdate now%6$s.', 'give' ),
210 esc_html( $version_info->name ),
211 '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
212 esc_html( $version_info->new_version ),
213 '</a>',
214 '<a href="' . esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) ) .'">',
215 '</a>'
216 );
217 }
218
219 do_action( "in_plugin_update_message-{$file}", $plugin, $version_info );
220
221 echo '</div></td></tr>';
222 }
223 }
224
225 /**
226 * Updates information on the "View version x.x details" page with custom data.
227 *
228 * @uses api_request()
229 *
230 * @param mixed $_data
231 * @param string $_action
232 * @param object $_args
233 * @return object $_data
234 */
235 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
236
237 if ( $_action != 'plugin_information' ) {
238
239 return $_data;
240
241 }
242
243 if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) {
244
245 return $_data;
246
247 }
248
249 $to_send = array(
250 'slug' => $this->slug,
251 'is_ssl' => is_ssl(),
252 'fields' => array(
253 'banners' => array(),
254 'reviews' => false
255 )
256 );
257
258 $cache_key = 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );
259
260 // Get the transient where we store the api request for this plugin for 24 hours
261 $edd_api_request_transient = $this->get_cached_version_info( $cache_key );
262
263 //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.
264 if ( empty( $edd_api_request_transient ) ) {
265
266 $api_response = $this->api_request( 'plugin_information', $to_send );
267
268 // Expires in 3 hours
269 $this->set_version_info_cache( $api_response, $cache_key );
270
271 if ( false !== $api_response ) {
272 $_data = $api_response;
273 }
274
275 } else {
276 $_data = $edd_api_request_transient;
277 }
278
279 // Convert sections into an associative array, since we're getting an object, but Core expects an array.
280 if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
281 $new_sections = array();
282 foreach ( $_data->sections as $key => $value ) {
283 $new_sections[ $key ] = $value;
284 }
285
286 $_data->sections = $new_sections;
287 }
288
289 // Convert banners into an associative array, since we're getting an object, but Core expects an array.
290 if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
291 $new_banners = array();
292 foreach ( $_data->banners as $key => $value ) {
293 $new_banners[ $key ] = $value;
294 }
295
296 $_data->banners = $new_banners;
297 }
298
299 return $_data;
300 }
301
302 /**
303 * Disable SSL verification in order to prevent download update failures
304 *
305 * @param array $args
306 * @param string $url
307 * @return object $array
308 */
309 public function http_request_args( $args, $url ) {
310 // If it is an https request and we are performing a package download, disable ssl verification
311 if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
312 $args['sslverify'] = false;
313 }
314 return $args;
315 }
316
317 /**
318 * Calls the API and, if successfull, returns the object delivered by the API.
319 *
320 * @uses get_bloginfo()
321 * @uses wp_remote_post()
322 * @uses is_wp_error()
323 *
324 * @param string $_action The requested action.
325 * @param array $_data Parameters for the API action.
326 * @return false|object
327 */
328 private function api_request( $_action, $_data ) {
329
330 global $wp_version;
331
332 $data = array_merge( $this->api_data, $_data );
333
334 if ( $data['slug'] != $this->slug ) {
335 return;
336 }
337
338 if( $this->api_url == trailingslashit (home_url() ) ) {
339 return false; // Don't allow a plugin to ping itself
340 }
341
342 $api_params = array(
343 'edd_action' => 'get_version',
344 'license' => ! empty( $data['license'] ) ? $data['license'] : '',
345 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
346 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
347 'version' => isset( $data['version'] ) ? $data['version'] : false,
348 'slug' => $data['slug'],
349 'author' => $data['author'],
350 'url' => home_url(),
351 'beta' => ! empty( $data['beta'] ),
352 );
353
354 $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => false, 'body' => $api_params ) );
355
356 if ( ! is_wp_error( $request ) ) {
357 $request = json_decode( wp_remote_retrieve_body( $request ) );
358 }
359
360 if ( $request && isset( $request->sections ) ) {
361 $request->sections = maybe_unserialize( $request->sections );
362 } else {
363 $request = false;
364 }
365
366 if ( $request && isset( $request->banners ) ) {
367 $request->banners = maybe_unserialize( $request->banners );
368 }
369
370 if( ! empty( $request->sections ) ) {
371 foreach( $request->sections as $key => $section ) {
372 $request->$key = (array) $section;
373 }
374 }
375
376 return $request;
377 }
378
379 public function show_changelog() {
380
381 global $edd_plugin_data;
382
383 if( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) {
384 return;
385 }
386
387 if( empty( $_REQUEST['plugin'] ) ) {
388 return;
389 }
390
391 if( empty( $_REQUEST['slug'] ) ) {
392 return;
393 }
394
395 if( ! current_user_can( 'update_plugins' ) ) {
396 wp_die( __( 'You do not have permission to install plugin updates', 'give' ), __( 'Error', 'give' ), array( 'response' => 403 ) );
397 }
398
399 $data = $edd_plugin_data[ $_REQUEST['slug'] ];
400 $beta = ! empty( $data['beta'] ) ? true : false;
401 $cache_key = md5( 'edd_plugin_' . sanitize_key( $_REQUEST['plugin'] ) . '_' . $beta . '_version_info' );
402 $version_info = $this->get_cached_version_info( $cache_key );
403
404 if( false === $version_info ) {
405
406 $api_params = array(
407 'edd_action' => 'get_version',
408 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
409 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
410 'slug' => $_REQUEST['slug'],
411 'author' => $data['author'],
412 'url' => home_url(),
413 'beta' => ! empty( $data['beta'] )
414 );
415
416 $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => false, 'body' => $api_params ) );
417
418 if ( ! is_wp_error( $request ) ) {
419 $version_info = json_decode( wp_remote_retrieve_body( $request ) );
420 }
421
422
423 if ( ! empty( $version_info ) && isset( $version_info->sections ) ) {
424 $version_info->sections = maybe_unserialize( $version_info->sections );
425 } else {
426 $version_info = false;
427 }
428
429 if( ! empty( $version_info ) ) {
430 foreach( $version_info->sections as $key => $section ) {
431 $version_info->$key = (array) $section;
432 }
433 }
434
435 $this->set_version_info_cache( $version_info, $cache_key );
436
437 }
438
439 if( ! empty( $version_info ) && isset( $version_info->sections['changelog'] ) ) {
440 echo '<div style="background:#fff;padding:10px;">' . $version_info->sections['changelog'] . '</div>';
441 }
442
443 exit;
444 }
445
446 public function get_cached_version_info( $cache_key = '' ) {
447
448 if( empty( $cache_key ) ) {
449 $cache_key = $this->cache_key;
450 }
451
452 $cache = get_option( $cache_key );
453
454 if( empty( $cache['timeout'] ) || current_time( 'timestamp' ) > $cache['timeout'] ) {
455 return false; // Cache is expired
456 }
457
458 return json_decode( $cache['value'] );
459
460 }
461
462 public function set_version_info_cache( $value = '', $cache_key = '' ) {
463
464 if( empty( $cache_key ) ) {
465 $cache_key = $this->cache_key;
466 }
467
468 $data = array(
469 'timeout' => strtotime( '+3 hours', current_time( 'timestamp' ) ),
470 'value' => json_encode( $value )
471 );
472
473 update_option( $cache_key, $data );
474
475 }
476
477 }