PluginProbe
Advanced Custom Fields (ACF®) / 5.7.9
Advanced Custom Fields (ACF®) v5.7.9
6.8.9 6.8.8 6.8.7 6.8.6 6.8.5 6.8.4 6.8.3 6.8.2 6.8.1 5.8.5 5.8.6 5.8.7 5.8.8 5.8.9 5.9.0 5.9.1 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 5.9.9 6.0.0 All 230 releases
advanced-custom-fields / includes / updates.php

updates.php in Advanced Custom Fields (ACF®) 5.7.9, at includes/updates.php

489 lines 10.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
4
5 if( ! class_exists('ACF_Updates') ) :
6
7 class ACF_Updates {
8
9 /** @var string The ACF_Updates version */
10 var $version = '2.4';
11
12 /** @var array The array of registered plugins */
13 var $plugins = array();
14
15 /** @var boolean Dev mode */
16 var $dev = false;
17
18 /** @var int Counts the number of plugin update checks */
19 var $checked = 0;
20
21 /*
22 * __construct
23 *
24 * Sets up the class functionality.
25 *
26 * @date 5/03/2014
27 * @since 5.0.0
28 *
29 * @param void
30 * @return void
31 */
32
33 function __construct() {
34
35 // append update information to transient
36 add_filter('pre_set_site_transient_update_plugins', array($this, 'modify_plugins_transient'), 10, 1);
37
38 // modify plugin data visible in the 'View details' popup
39 add_filter('plugins_api', array($this, 'modify_plugin_details'), 10, 3);
40 }
41
42 /*
43 * add_plugin
44 *
45 * Registeres a plugin for updates.
46 *
47 * @date 8/4/17
48 * @since 5.5.10
49 *
50 * @param array $plugin The plugin array.
51 * @return void
52 */
53
54 function add_plugin( $plugin ) {
55
56 // validate
57 $plugin = wp_parse_args($plugin, array(
58 'id' => '',
59 'key' => '',
60 'slug' => '',
61 'basename' => '',
62 'version' => '',
63 ));
64
65 // Check if is_plugin_active() function exists. This is required on the front end of the
66 // site, since it is in a file that is normally only loaded in the admin.
67 if( !function_exists( 'is_plugin_active' ) ) {
68 require_once ABSPATH . 'wp-admin/includes/plugin.php';
69 }
70
71 // add if is active plugin (not included in theme)
72 if( is_plugin_active($plugin['basename']) ) {
73 $this->plugins[ $plugin['basename'] ] = $plugin;
74 }
75 }
76
77 /**
78 * get_plugin_by
79 *
80 * Returns a registered plugin for the give key and value.
81 *
82 * @date 3/8/18
83 * @since 5.7.2
84 *
85 * @param string $key The array key to compare
86 * @param string $value The value to compare against
87 * @return array|false
88 */
89
90 function get_plugin_by( $key = '', $value = null ) {
91 foreach( $this->plugins as $plugin ) {
92 if( $plugin[$key] === $value ) {
93 return $plugin;
94 }
95 }
96 return false;
97 }
98
99 /*
100 * request
101 *
102 * Makes a request to the ACF connect server.
103 *
104 * @date 8/4/17
105 * @since 5.5.10
106 *
107 * @param string $query The api path. Defaults to 'index.php'
108 * @param array $body The body to post
109 * @return array|string|WP_Error
110 */
111
112 function request( $query = 'index.php', $body = null ) {
113
114 // vars
115 $url = 'https://connect.advancedcustomfields.com/' . $query;
116
117 // development mode
118 if( $this->dev ) {
119 $url = 'http://connect/' . $query;
120 acf_log('acf connect: '. $url, $body);
121 }
122
123 // post
124 $raw_response = wp_remote_post( $url, array(
125 'timeout' => 10,
126 'body' => $body
127 ));
128
129 // wp error
130 if( is_wp_error($raw_response) ) {
131 return $raw_response;
132
133 // http error
134 } elseif( wp_remote_retrieve_response_code($raw_response) != 200 ) {
135 return new WP_Error( 'server_error', wp_remote_retrieve_response_message($raw_response) );
136 }
137
138 // decode response
139 $json = json_decode( wp_remote_retrieve_body($raw_response), true );
140
141 // allow non json value
142 if( $json === null ) {
143 return wp_remote_retrieve_body($raw_response);
144 }
145
146 // return
147 return $json;
148 }
149
150 /*
151 * get_plugin_info
152 *
153 * Returns update information for the given plugin id.
154 *
155 * @date 9/4/17
156 * @since 5.5.10
157 *
158 * @param string $id The plugin id such as 'pro'.
159 * @param boolean $force_check Bypasses cached result. Defaults to false.
160 * @return array|WP_Error
161 */
162
163 function get_plugin_info( $id = '', $force_check = false ) {
164
165 // var
166 $transient_name = 'acf_plugin_info_' . $id;
167
168 // check cache but allow for $force_check override
169 if( !$force_check ) {
170 $transient = get_transient( $transient_name );
171 if( $transient !== false ) {
172 return $transient;
173 }
174 }
175
176 // connect
177 $response = $this->request('v2/plugins/get-info?p='.$id);
178
179 // convert string (misc error) to WP_Error object
180 if( is_string($response) ) {
181 $response = new WP_Error( 'server_error', esc_html($response) );
182 }
183
184 // allow json to include expiration but force minimum and max for safety
185 $expiration = $this->get_expiration($response, DAY_IN_SECONDS, MONTH_IN_SECONDS);
186
187 // update transient
188 set_transient( $transient_name, $response, $expiration );
189
190 // return
191 return $response;
192 }
193
194 /**
195 * get_plugin_update
196 *
197 * Returns specific data from the 'update-check' response.
198 *
199 * @date 3/8/18
200 * @since 5.7.2
201 *
202 * @param string $basename The plugin basename.
203 * @param boolean $force_check Bypasses cached result. Defaults to false
204 * @return array
205 */
206
207 function get_plugin_update( $basename = '', $force_check = false ) {
208
209 // get updates
210 $updates = $this->get_plugin_updates( $force_check );
211
212 // check for and return update
213 if( is_array($updates) && isset($updates['plugins'][ $basename ]) ) {
214 return $updates['plugins'][ $basename ];
215 }
216 return false;
217 }
218
219
220 /**
221 * get_plugin_updates
222 *
223 * Checks for plugin updates.
224 *
225 * @date 8/7/18
226 * @since 5.6.9
227 * @since 5.7.2 Added 'checked' comparison
228 *
229 * @param boolean $force_check Bypasses cached result. Defaults to false.
230 * @return array|WP_Error.
231 */
232
233 function get_plugin_updates( $force_check = false ) {
234
235 // var
236 $transient_name = 'acf_plugin_updates';
237
238 // construct array of 'checked' plugins
239 // sort by key to avoid detecting change due to "include order"
240 $checked = array();
241 foreach( $this->plugins as $basename => $plugin ) {
242 $checked[ $basename ] = $plugin['version'];
243 }
244 ksort($checked);
245
246 // $force_check prevents transient lookup
247 if( !$force_check ) {
248 $transient = get_transient($transient_name);
249
250 // if cached response was found, compare $transient['checked'] against $checked and ignore if they don't match (plugins/versions have changed)
251 if( is_array($transient) ) {
252 $transient_checked = isset($transient['checked']) ? $transient['checked'] : array();
253 if( wp_json_encode($checked) !== wp_json_encode($transient_checked) ) {
254 $transient = false;
255 }
256 }
257 if( $transient !== false ) {
258 return $transient;
259 }
260 }
261
262 // vars
263 $post = array(
264 'plugins' => wp_json_encode($this->plugins),
265 'wp' => wp_json_encode(array(
266 'wp_name' => get_bloginfo('name'),
267 'wp_url' => home_url(),
268 'wp_version' => get_bloginfo('version'),
269 'wp_language' => get_bloginfo('language'),
270 'wp_timezone' => get_option('timezone_string'),
271 )),
272 'acf' => wp_json_encode(array(
273 'acf_version' => get_option('acf_version'),
274 'acf_pro' => (defined('ACF_PRO') && ACF_PRO),
275 )),
276 );
277
278 // request
279 $response = $this->request('v2/plugins/update-check', $post);
280
281 // append checked reference
282 if( is_array($response) ) {
283 $response['checked'] = $checked;
284 }
285
286 // allow json to include expiration but force minimum and max for safety
287 $expiration = $this->get_expiration($response, DAY_IN_SECONDS, MONTH_IN_SECONDS);
288
289 // update transient
290 set_transient($transient_name, $response, $expiration );
291
292 // return
293 return $response;
294 }
295
296 /**
297 * get_expiration
298 *
299 * This function safely gets the expiration value from a response.
300 *
301 * @date 8/7/18
302 * @since 5.6.9
303 *
304 * @param mixed $response The response from the server. Default false.
305 * @param int $min The minimum expiration limit. Default 0.
306 * @param int $max The maximum expiration limit. Default 0.
307 * @return int
308 */
309
310 function get_expiration( $response = false, $min = 0, $max = 0 ) {
311
312 // vars
313 $expiration = 0;
314
315 // check
316 if( is_array($response) && isset($response['expiration']) ) {
317 $expiration = (int) $response['expiration'];
318 }
319
320 // min
321 if( $expiration < $min ) {
322 return $min;
323 }
324
325 // max
326 if( $expiration > $max ) {
327 return $max;
328 }
329
330 // return
331 return $expiration;
332 }
333
334 /*
335 * refresh_plugins_transient
336 *
337 * Deletes transients and allows a fresh lookup.
338 *
339 * @date 11/4/17
340 * @since 5.5.10
341 *
342 * @param void
343 * @return void
344 */
345
346 function refresh_plugins_transient() {
347 delete_site_transient('update_plugins');
348 delete_transient('acf_plugin_updates');
349 }
350
351 /*
352 * modify_plugins_transient
353 *
354 * Called when WP updates the 'update_plugins' site transient. Used to inject ACF plugin update info.
355 *
356 * @date 16/01/2014
357 * @since 5.0.0
358 *
359 * @param object $transient
360 * @return $transient
361 */
362
363 function modify_plugins_transient( $transient ) {
364
365 // bail early if no response (error)
366 if( !isset($transient->response) ) {
367 return $transient;
368 }
369
370 // force-check (only once)
371 $force_check = ($this->checked == 0) ? !empty($_GET['force-check']) : false;
372
373 // fetch updates (this filter is called multiple times during a single page load)
374 $updates = $this->get_plugin_updates( $force_check );
375
376 // append
377 if( is_array($updates) ) {
378 foreach( $updates['plugins'] as $basename => $update ) {
379 $transient->response[ $basename ] = (object) $update;
380 }
381 }
382
383 // increase
384 $this->checked++;
385
386 // return
387 return $transient;
388 }
389
390 /*
391 * modify_plugin_details
392 *
393 * Returns the plugin data visible in the 'View details' popup
394 *
395 * @date 17/01/2014
396 * @since 5.0.0
397 *
398 * @param object $result
399 * @param string $action
400 * @param object $args
401 * @return $result
402 */
403
404 function modify_plugin_details( $result, $action = null, $args = null ) {
405
406 // vars
407 $plugin = false;
408
409 // only for 'plugin_information' action
410 if( $action !== 'plugin_information' ) return $result;
411
412 // find plugin via slug
413 $plugin = $this->get_plugin_by('slug', $args->slug);
414 if( !$plugin ) return $result;
415
416 // connect
417 $response = $this->get_plugin_info($plugin['id']);
418
419 // bail early if no response
420 if( !is_array($response) ) return $result;
421
422 // remove tags (different context)
423 unset($response['tags']);
424
425 // convert to object
426 $response = (object) $response;
427
428 // sections
429 $sections = array(
430 'description' => '',
431 'installation' => '',
432 'changelog' => '',
433 'upgrade_notice' => ''
434 );
435 foreach( $sections as $k => $v ) {
436 $sections[ $k ] = $response->$k;
437 }
438 $response->sections = $sections;
439
440 // return
441 return $response;
442 }
443 }
444
445
446 /*
447 * acf_updates
448 *
449 * The main function responsible for returning the one true acf_updates instance to functions everywhere.
450 * Use this function like you would a global variable, except without needing to declare the global.
451 *
452 * Example: <?php $acf_updates = acf_updates(); ?>
453 *
454 * @date 9/4/17
455 * @since 5.5.12
456 *
457 * @param void
458 * @return object
459 */
460
461 function acf_updates() {
462 global $acf_updates;
463 if( !isset($acf_updates) ) {
464 $acf_updates = new ACF_Updates();
465 }
466 return $acf_updates;
467 }
468
469
470 /*
471 * acf_register_plugin_update
472 *
473 * Alias of acf_updates()->add_plugin().
474 *
475 * @type function
476 * @date 12/4/17
477 * @since 5.5.10
478 *
479 * @param array $plugin
480 * @return void
481 */
482
483 function acf_register_plugin_update( $plugin ) {
484 acf_updates()->add_plugin( $plugin );
485 }
486
487 endif; // class_exists check
488
489 ?>