123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- <?php
- if ( ! defined( 'ABSPATH' ) ) {
- exit; // Exit if accessed directly
- }
- if ( ! class_exists( 'ACF_Updates' ) ) :
- class ACF_Updates {
- /** @var string The ACF_Updates version */
- var $version = '2.4';
- /** @var array The array of registered plugins */
- var $plugins = array();
- /** @var int Counts the number of plugin update checks */
- var $checked = 0;
- /*
- * __construct
- *
- * Sets up the class functionality.
- *
- * @date 5/03/2014
- * @since 5.0.0
- *
- * @param void
- * @return void
- */
- function __construct() {
- // append update information to transient
- add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'modify_plugins_transient' ), 10, 1 );
- // modify plugin data visible in the 'View details' popup
- add_filter( 'plugins_api', array( $this, 'modify_plugin_details' ), 10, 3 );
- }
- /*
- * add_plugin
- *
- * Registeres a plugin for updates.
- *
- * @date 8/4/17
- * @since 5.5.10
- *
- * @param array $plugin The plugin array.
- * @return void
- */
- function add_plugin( $plugin ) {
- // validate
- $plugin = wp_parse_args(
- $plugin,
- array(
- 'id' => '',
- 'key' => '',
- 'slug' => '',
- 'basename' => '',
- 'version' => '',
- )
- );
- // Check if is_plugin_active() function exists. This is required on the front end of the
- // site, since it is in a file that is normally only loaded in the admin.
- if ( ! function_exists( 'is_plugin_active' ) ) {
- require_once ABSPATH . 'wp-admin/includes/plugin.php';
- }
- // add if is active plugin (not included in theme)
- if ( is_plugin_active( $plugin['basename'] ) ) {
- $this->plugins[ $plugin['basename'] ] = $plugin;
- }
- }
- /**
- * get_plugin_by
- *
- * Returns a registered plugin for the give key and value.
- *
- * @date 3/8/18
- * @since 5.7.2
- *
- * @param string $key The array key to compare
- * @param string $value The value to compare against
- * @return array|false
- */
- function get_plugin_by( $key = '', $value = null ) {
- foreach ( $this->plugins as $plugin ) {
- if ( $plugin[ $key ] === $value ) {
- return $plugin;
- }
- }
- return false;
- }
- /*
- * request
- *
- * Makes a request to the ACF connect server.
- *
- * @date 8/4/17
- * @since 5.5.10
- *
- * @param string $endpoint The API endpoint.
- * @param array $body The body to post.
- * @return (array|string|WP_Error)
- */
- function request( $endpoint = '', $body = null ) {
- // Determine URL.
- $url = "https://connect.advancedcustomfields.com/$endpoint";
- // Staging environment.
- if ( defined( 'ACF_DEV_API' ) && ACF_DEV_API ) {
- $url = trailingslashit( ACF_DEV_API ) . $endpoint;
- acf_log( $url, $body );
- }
- // Make request.
- $raw_response = wp_remote_post(
- $url,
- array(
- 'timeout' => 10,
- 'body' => $body,
- )
- );
- // Handle response error.
- if ( is_wp_error( $raw_response ) ) {
- return $raw_response;
- // Handle http error.
- } elseif ( wp_remote_retrieve_response_code( $raw_response ) != 200 ) {
- return new WP_Error( 'server_error', wp_remote_retrieve_response_message( $raw_response ) );
- }
- // Decode JSON response.
- $json = json_decode( wp_remote_retrieve_body( $raw_response ), true );
- // Allow non json value.
- if ( $json === null ) {
- return wp_remote_retrieve_body( $raw_response );
- }
- // return
- return $json;
- }
- /**
- * Returns update information for the given plugin id.
- *
- * @since 5.5.10
- *
- * @param string $id The plugin id such as 'pro'.
- * @param boolean $force_check Bypasses cached result. Defaults to false.
- * @return array|WP_Error
- */
- public function get_plugin_info( $id = '', $force_check = false ) {
- $transient_name = 'acf_plugin_info_' . $id;
- // check cache but allow for $force_check override.
- if ( ! $force_check ) {
- $transient = get_transient( $transient_name );
- if ( $transient !== false ) {
- return $transient;
- }
- }
- $response = $this->request( 'v2/plugins/get-info?p=' . $id );
- // convert string (misc error) to WP_Error object.
- if ( is_string( $response ) ) {
- $response = new WP_Error( 'server_error', esc_html( $response ) );
- }
- // allow json to include expiration but force minimum and max for safety.
- $expiration = $this->get_expiration( $response, DAY_IN_SECONDS, MONTH_IN_SECONDS );
- // update transient.
- set_transient( $transient_name, $response, $expiration );
- return $response;
- }
- /**
- * get_plugin_update
- *
- * Returns specific data from the 'update-check' response.
- *
- * @date 3/8/18
- * @since 5.7.2
- *
- * @param string $basename The plugin basename.
- * @param boolean $force_check Bypasses cached result. Defaults to false
- * @return array
- */
- function get_plugin_update( $basename = '', $force_check = false ) {
- // get updates
- $updates = $this->get_plugin_updates( $force_check );
- // check for and return update
- if ( is_array( $updates ) && isset( $updates['plugins'][ $basename ] ) ) {
- return $updates['plugins'][ $basename ];
- }
- return false;
- }
- /**
- * get_plugin_updates
- *
- * Checks for plugin updates.
- *
- * @date 8/7/18
- * @since 5.6.9
- * @since 5.7.2 Added 'checked' comparison
- *
- * @param boolean $force_check Bypasses cached result. Defaults to false.
- * @return array|WP_Error.
- */
- function get_plugin_updates( $force_check = false ) {
- // var
- $transient_name = 'acf_plugin_updates';
- // construct array of 'checked' plugins
- // sort by key to avoid detecting change due to "include order"
- $checked = array();
- foreach ( $this->plugins as $basename => $plugin ) {
- $checked[ $basename ] = $plugin['version'];
- }
- ksort( $checked );
- // $force_check prevents transient lookup
- if ( ! $force_check ) {
- $transient = get_transient( $transient_name );
- // if cached response was found, compare $transient['checked'] against $checked and ignore if they don't match (plugins/versions have changed)
- if ( is_array( $transient ) ) {
- $transient_checked = isset( $transient['checked'] ) ? $transient['checked'] : array();
- if ( wp_json_encode( $checked ) !== wp_json_encode( $transient_checked ) ) {
- $transient = false;
- }
- }
- if ( $transient !== false ) {
- return $transient;
- }
- }
- // vars
- $post = array(
- 'plugins' => wp_json_encode( $this->plugins ),
- 'wp' => wp_json_encode(
- array(
- 'wp_name' => get_bloginfo( 'name' ),
- 'wp_url' => acf_get_home_url(),
- 'wp_version' => get_bloginfo( 'version' ),
- 'wp_language' => get_bloginfo( 'language' ),
- 'wp_timezone' => get_option( 'timezone_string' ),
- 'php_version' => PHP_VERSION,
- )
- ),
- 'acf' => wp_json_encode(
- array(
- 'acf_version' => get_option( 'acf_version' ),
- 'acf_pro' => ( defined( 'ACF_PRO' ) && ACF_PRO ),
- 'block_count' => acf_pro_get_registered_block_count(),
- )
- ),
- );
- // request
- $response = $this->request( 'v2/plugins/update-check', $post );
- // append checked reference
- if ( is_array( $response ) ) {
- $response['checked'] = $checked;
- }
- // allow json to include expiration but force minimum and max for safety
- $expiration = $this->get_expiration( $response, DAY_IN_SECONDS, MONTH_IN_SECONDS );
- // update transient
- set_transient( $transient_name, $response, $expiration );
- // return
- return $response;
- }
- /**
- * This function safely gets the expiration value from a response.
- *
- * @since 5.6.9
- *
- * @param mixed $response The response from the server. Default false.
- * @param int $min The minimum expiration limit. Default 0.
- * @param int $max The maximum expiration limit. Default 0.
- * @return int
- */
- public function get_expiration( $response = false, $min = 0, $max = 0 ) {
- $expiration = 0;
- // check possible error conditions.
- if ( is_wp_error( $response ) || is_string( $response ) ) {
- return 5 * MINUTE_IN_SECONDS;
- }
- // use the server requested expiration if present.
- if ( is_array( $response ) && isset( $response['expiration'] ) ) {
- $expiration = (int) $response['expiration'];
- }
- // use the minimum if neither check matches, or ensure the server expiration isn't lower than our minimum.
- if ( $expiration < $min ) {
- return $min;
- }
- // ensure the server expiration isn't higher than our max.
- if ( $expiration > $max ) {
- return $max;
- }
- return $expiration;
- }
- /*
- * refresh_plugins_transient
- *
- * Deletes transients and allows a fresh lookup.
- *
- * @date 11/4/17
- * @since 5.5.10
- *
- * @param void
- * @return void
- */
- function refresh_plugins_transient() {
- delete_site_transient( 'update_plugins' );
- delete_transient( 'acf_plugin_updates' );
- }
- /*
- * modify_plugins_transient
- *
- * Called when WP updates the 'update_plugins' site transient. Used to inject ACF plugin update info.
- *
- * @date 16/01/2014
- * @since 5.0.0
- *
- * @param object $transient
- * @return $transient
- */
- function modify_plugins_transient( $transient ) {
- // bail early if no response (error)
- if ( ! isset( $transient->response ) ) {
- return $transient;
- }
- // force-check (only once)
- $force_check = ( $this->checked == 0 ) ? ! empty( $_GET['force-check'] ) : false; // phpcs:ignore -- False positive, value not used.
- // fetch updates (this filter is called multiple times during a single page load)
- $updates = $this->get_plugin_updates( $force_check );
- // append
- if ( is_array( $updates ) ) {
- foreach ( $updates['plugins'] as $basename => $update ) {
- $transient->response[ $basename ] = (object) $update;
- }
- }
- // increase
- $this->checked++;
- // return
- return $transient;
- }
- /*
- * modify_plugin_details
- *
- * Returns the plugin data visible in the 'View details' popup
- *
- * @date 17/01/2014
- * @since 5.0.0
- *
- * @param object $result
- * @param string $action
- * @param object $args
- * @return $result
- */
- function modify_plugin_details( $result, $action = null, $args = null ) {
- // vars
- $plugin = false;
- // only for 'plugin_information' action
- if ( $action !== 'plugin_information' ) {
- return $result;
- }
- // find plugin via slug
- $plugin = $this->get_plugin_by( 'slug', $args->slug );
- if ( ! $plugin ) {
- return $result;
- }
- // connect
- $response = $this->get_plugin_info( $plugin['id'] );
- // bail early if no response
- if ( ! is_array( $response ) ) {
- return $result;
- }
- // remove tags (different context)
- unset( $response['tags'] );
- // convert to object
- $response = (object) $response;
- // sections
- $sections = array(
- 'description' => '',
- 'installation' => '',
- 'changelog' => '',
- 'upgrade_notice' => '',
- );
- foreach ( $sections as $k => $v ) {
- $sections[ $k ] = $response->$k;
- }
- $response->sections = $sections;
- // return
- return $response;
- }
- }
- /*
- * acf_updates
- *
- * The main function responsible for returning the one true acf_updates instance to functions everywhere.
- * Use this function like you would a global variable, except without needing to declare the global.
- *
- * Example: <?php $acf_updates = acf_updates(); ?>
- *
- * @date 9/4/17
- * @since 5.5.12
- *
- * @param void
- * @return object
- */
- function acf_updates() {
- global $acf_updates;
- if ( ! isset( $acf_updates ) ) {
- $acf_updates = new ACF_Updates();
- }
- return $acf_updates;
- }
- /*
- * acf_register_plugin_update
- *
- * Alias of acf_updates()->add_plugin().
- *
- * @type function
- * @date 12/4/17
- * @since 5.5.10
- *
- * @param array $plugin
- * @return void
- */
- function acf_register_plugin_update( $plugin ) {
- acf_updates()->add_plugin( $plugin );
- }
- endif; // class_exists check
|