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