admin-updates.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. if ( ! defined( 'ABSPATH' ) ) {
  3. exit; // Exit if accessed directly
  4. }
  5. if ( ! class_exists( 'ACF_Admin_Updates' ) ) :
  6. class ACF_Admin_Updates {
  7. /** @var array Data used in the view. */
  8. var $view = array();
  9. /**
  10. * __construct
  11. *
  12. * Sets up the class functionality.
  13. *
  14. * @date 23/06/12
  15. * @since 5.0.0
  16. *
  17. * @param void
  18. * @return void
  19. */
  20. function __construct() {
  21. // Add actions.
  22. add_action( 'admin_menu', array( $this, 'admin_menu' ), 20 );
  23. }
  24. /**
  25. * display_wp_error
  26. *
  27. * Adds an admin notice using the provided WP_Error.
  28. *
  29. * @date 14/1/19
  30. * @since 5.7.10
  31. *
  32. * @param WP_Error $wp_error The error to display.
  33. * @return void
  34. */
  35. function display_wp_error( $wp_error ) {
  36. // Only show one error on page.
  37. if ( acf_has_done( 'display_wp_error' ) ) {
  38. return;
  39. }
  40. // Create new notice.
  41. acf_new_admin_notice(
  42. array(
  43. 'text' => __( '<b>Error</b>. Could not connect to update server', 'acf' ) . ' <span class="description">(' . esc_html( $wp_error->get_error_message() ) . ').</span>',
  44. 'type' => 'error',
  45. )
  46. );
  47. }
  48. /**
  49. * get_changelog_changes
  50. *
  51. * Finds the specific changes for a given version from the provided changelog snippet.
  52. *
  53. * @date 14/1/19
  54. * @since 5.7.10
  55. *
  56. * @param string $changelog The changelog text.
  57. * @param string $version The version to find.
  58. * @return string
  59. */
  60. function get_changelog_changes( $changelog = '', $version = '' ) {
  61. // Explode changelog into sections.
  62. $bits = array_filter( explode( '<h4>', $changelog ) );
  63. // Loop over each version chunk.
  64. foreach ( $bits as $bit ) {
  65. // Find the version number for this chunk.
  66. $bit = explode( '</h4>', $bit );
  67. $bit_version = trim( $bit[0] );
  68. $bit_text = trim( $bit[1] );
  69. // Compare the chunk version number against param and return HTML.
  70. if ( acf_version_compare( $bit_version, '==', $version ) ) {
  71. return '<h4>' . esc_html( $bit_version ) . '</h4>' . acf_esc_html( $bit_text );
  72. }
  73. }
  74. // Return.
  75. return '';
  76. }
  77. /**
  78. * admin_menu
  79. *
  80. * Adds the admin menu subpage.
  81. *
  82. * @date 28/09/13
  83. * @since 5.0.0
  84. *
  85. * @param void
  86. * @return void
  87. */
  88. function admin_menu() {
  89. // Bail early if no show_admin.
  90. if ( ! acf_get_setting( 'show_admin' ) ) {
  91. return;
  92. }
  93. // Bail early if no show_updates.
  94. if ( ! acf_get_setting( 'show_updates' ) ) {
  95. return;
  96. }
  97. // Bail early if not a plugin (included in theme).
  98. if ( ! acf_is_plugin_active() ) {
  99. return;
  100. }
  101. // Add submenu.
  102. $page = add_submenu_page( 'edit.php?post_type=acf-field-group', __( 'Updates', 'acf' ), __( 'Updates', 'acf' ), acf_get_setting( 'capability' ), 'acf-settings-updates', array( $this, 'html' ) );
  103. // Add actions to page.
  104. add_action( "load-$page", array( $this, 'load' ) );
  105. }
  106. /**
  107. * load
  108. *
  109. * Runs when loading the submenu page.
  110. *
  111. * @date 7/01/2014
  112. * @since 5.0.0
  113. *
  114. * @param void
  115. * @return void
  116. */
  117. function load() {
  118. // Check activate.
  119. if ( acf_verify_nonce( 'activate_pro_license' ) ) {
  120. acf_pro_activate_license( sanitize_text_field( $_POST['acf_pro_license'] ) );
  121. // Check deactivate.
  122. } elseif ( acf_verify_nonce( 'deactivate_pro_license' ) ) {
  123. acf_pro_deactivate_license();
  124. }
  125. // vars
  126. $license = acf_pro_get_license_key();
  127. $this->view = array(
  128. 'license' => $license,
  129. 'active' => $license ? 1 : 0,
  130. 'current_version' => acf_get_setting( 'version' ),
  131. 'remote_version' => '',
  132. 'update_available' => false,
  133. 'changelog' => '',
  134. 'upgrade_notice' => '',
  135. 'is_defined_license' => defined( 'ACF_PRO_LICENSE' ) && ! empty( ACF_PRO_LICENSE ) && is_string( ACF_PRO_LICENSE ),
  136. 'license_error' => false,
  137. );
  138. // get plugin updates
  139. $force_check = ! empty( $_GET['force-check'] );
  140. $info = acf_updates()->get_plugin_info( 'pro', $force_check );
  141. // Display error.
  142. if ( is_wp_error( $info ) ) {
  143. return $this->display_wp_error( $info );
  144. }
  145. // add info to view
  146. $this->view['remote_version'] = $info['version'];
  147. // add changelog if the remote version is '>' than the current version
  148. $version = acf_get_setting( 'version' );
  149. // check if remote version is higher than current version
  150. if ( version_compare( $info['version'], $version, '>' ) ) {
  151. // update view
  152. $this->view['update_available'] = true;
  153. $this->view['changelog'] = $this->get_changelog_changes( $info['changelog'], $info['version'] );
  154. $this->view['upgrade_notice'] = $this->get_changelog_changes( $info['upgrade_notice'], $info['version'] );
  155. // perform update checks if license is active
  156. $basename = acf_get_setting( 'basename' );
  157. $update = acf_updates()->get_plugin_update( $basename );
  158. if ( $license ) {
  159. if ( isset( $update['license_valid'] ) && ! $update['license_valid'] ) {
  160. $this->view['license_error'] = true;
  161. acf_new_admin_notice(
  162. array(
  163. 'text' => __( '<b>Error</b>. Your license for this site has expired or been deactivated. Please reactivate your ACF PRO license.', 'acf' ),
  164. 'type' => 'error',
  165. )
  166. );
  167. } else {
  168. // display error if no package url
  169. // - possible if license key has been modified
  170. if ( $update && ! $update['package'] ) {
  171. $this->view['license_error'] = true;
  172. acf_new_admin_notice(
  173. array(
  174. 'text' => __( '<b>Error</b>. Could not authenticate update package. Please check again or deactivate and reactivate your ACF PRO license.', 'acf' ),
  175. 'type' => 'error',
  176. )
  177. );
  178. }
  179. }
  180. // refresh transient
  181. // - if no update exists in the transient
  182. // - or if the transient 'new_version' is stale
  183. if ( ! $update || $update['new_version'] !== $info['version'] ) {
  184. acf_updates()->refresh_plugins_transient();
  185. }
  186. }
  187. }
  188. }
  189. /**
  190. * html
  191. *
  192. * Displays the submenu page's HTML.
  193. *
  194. * @date 7/01/2014
  195. * @since 5.0.0
  196. *
  197. * @param void
  198. * @return void
  199. */
  200. function html() {
  201. acf_get_view( dirname( __FILE__ ) . '/views/html-settings-updates.php', $this->view );
  202. }
  203. }
  204. // Initialize.
  205. acf_new_instance( 'ACF_Admin_Updates' );
  206. endif; // class_exists check