/wp-admin/includes/update.php

  1. <?php 
  2. /** 
  3. * WordPress Administration Update API 
  4. * 
  5. * @package WordPress 
  6. * @subpackage Administration 
  7. */ 
  8.  
  9. /** 
  10. * Selects the first update version from the update_core option. 
  11. * 
  12. * @return object|array|false The response from the API on success, false on failure. 
  13. */ 
  14. function get_preferred_from_update_core() { 
  15. $updates = get_core_updates(); 
  16. if ( ! is_array( $updates ) ) 
  17. return false; 
  18. if ( empty( $updates ) ) 
  19. return (object) array( 'response' => 'latest' ); 
  20. return $updates[0]; 
  21.  
  22. /** 
  23. * Get available core updates. 
  24. * 
  25. * @param array $options Set $options['dismissed'] to true to show dismissed upgrades too,  
  26. * set $options['available'] to false to skip not-dismissed updates. 
  27. * @return array|false Array of the update objects on success, false on failure. 
  28. */ 
  29. function get_core_updates( $options = array() ) { 
  30. $options = array_merge( array( 'available' => true, 'dismissed' => false ), $options ); 
  31. $dismissed = get_site_option( 'dismissed_update_core' ); 
  32.  
  33. if ( ! is_array( $dismissed ) ) 
  34. $dismissed = array(); 
  35.  
  36. $from_api = get_site_transient( 'update_core' ); 
  37.  
  38. if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) ) 
  39. return false; 
  40.  
  41. $updates = $from_api->updates; 
  42. $result = array(); 
  43. foreach ( $updates as $update ) { 
  44. if ( $update->response == 'autoupdate' ) 
  45. continue; 
  46.  
  47. if ( array_key_exists( $update->current . '|' . $update->locale, $dismissed ) ) { 
  48. if ( $options['dismissed'] ) { 
  49. $update->dismissed = true; 
  50. $result[] = $update; 
  51. } else { 
  52. if ( $options['available'] ) { 
  53. $update->dismissed = false; 
  54. $result[] = $update; 
  55. return $result; 
  56.  
  57. /** 
  58. * Gets the best available (and enabled) Auto-Update for WordPress Core. 
  59. * 
  60. * If there's 1.2.3 and 1.3 on offer, it'll choose 1.3 if the install allows it, else, 1.2.3 
  61. * 
  62. * @since 3.7.0 
  63. * 
  64. * @return array|false False on failure, otherwise the core update offering. 
  65. */ 
  66. function find_core_auto_update() { 
  67. $updates = get_site_transient( 'update_core' ); 
  68. if ( ! $updates || empty( $updates->updates ) ) 
  69. return false; 
  70.  
  71. include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' ); 
  72.  
  73. $auto_update = false; 
  74. $upgrader = new WP_Automatic_Updater; 
  75. foreach ( $updates->updates as $update ) { 
  76. if ( 'autoupdate' != $update->response ) 
  77. continue; 
  78.  
  79. if ( ! $upgrader->should_update( 'core', $update, ABSPATH ) ) 
  80. continue; 
  81.  
  82. if ( ! $auto_update || version_compare( $update->current, $auto_update->current, '>' ) ) 
  83. $auto_update = $update; 
  84. return $auto_update; 
  85.  
  86. /** 
  87. * Gets and caches the checksums for the given version of WordPress. 
  88. * 
  89. * @since 3.7.0 
  90. * 
  91. * @param string $version Version string to query. 
  92. * @param string $locale Locale to query. 
  93. * @return bool|array False on failure. An array of checksums on success. 
  94. */ 
  95. function get_core_checksums( $version, $locale ) { 
  96. $url = $http_url = 'http://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), null, '&' ); 
  97.  
  98. if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) 
  99. $url = set_url_scheme( $url, 'https' ); 
  100.  
  101. $options = array( 
  102. 'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3 ),  
  103. ); 
  104.  
  105. $response = wp_remote_get( $url, $options ); 
  106. if ( $ssl && is_wp_error( $response ) ) { 
  107. trigger_error( 
  108. sprintf( 
  109. /** translators: %s: support forums URL */ 
  110. __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),  
  111. __( 'https://wordpress.org/support/' ) 
  112. ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ),  
  113. headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE 
  114. ); 
  115. $response = wp_remote_get( $http_url, $options ); 
  116.  
  117. if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) 
  118. return false; 
  119.  
  120. $body = trim( wp_remote_retrieve_body( $response ) ); 
  121. $body = json_decode( $body, true ); 
  122.  
  123. if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) ) 
  124. return false; 
  125.  
  126. return $body['checksums']; 
  127.  
  128. /** 
  129. * 
  130. * @param object $update 
  131. * @return bool 
  132. */ 
  133. function dismiss_core_update( $update ) { 
  134. $dismissed = get_site_option( 'dismissed_update_core' ); 
  135. $dismissed[ $update->current . '|' . $update->locale ] = true; 
  136. return update_site_option( 'dismissed_update_core', $dismissed ); 
  137.  
  138. /** 
  139. * 
  140. * @param string $version 
  141. * @param string $locale 
  142. * @return bool 
  143. */ 
  144. function undismiss_core_update( $version, $locale ) { 
  145. $dismissed = get_site_option( 'dismissed_update_core' ); 
  146. $key = $version . '|' . $locale; 
  147.  
  148. if ( ! isset( $dismissed[$key] ) ) 
  149. return false; 
  150.  
  151. unset( $dismissed[$key] ); 
  152. return update_site_option( 'dismissed_update_core', $dismissed ); 
  153.  
  154. /** 
  155. * 
  156. * @param string $version 
  157. * @param string $locale 
  158. * @return object|false 
  159. */ 
  160. function find_core_update( $version, $locale ) { 
  161. $from_api = get_site_transient( 'update_core' ); 
  162.  
  163. if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) ) 
  164. return false; 
  165.  
  166. $updates = $from_api->updates; 
  167. foreach ( $updates as $update ) { 
  168. if ( $update->current == $version && $update->locale == $locale ) 
  169. return $update; 
  170. return false; 
  171.  
  172. /** 
  173. * 
  174. * @param string $msg 
  175. * @return string 
  176. */ 
  177. function core_update_footer( $msg = '' ) { 
  178. if ( !current_user_can('update_core') ) 
  179. return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) ); 
  180.  
  181. $cur = get_preferred_from_update_core(); 
  182. if ( ! is_object( $cur ) ) 
  183. $cur = new stdClass; 
  184.  
  185. if ( ! isset( $cur->current ) ) 
  186. $cur->current = ''; 
  187.  
  188. if ( ! isset( $cur->url ) ) 
  189. $cur->url = ''; 
  190.  
  191. if ( ! isset( $cur->response ) ) 
  192. $cur->response = ''; 
  193.  
  194. switch ( $cur->response ) { 
  195. case 'development' : 
  196. /** translators: 1: WordPress version number, 2: WordPress updates admin screen URL */ 
  197. return sprintf( __( 'You are using a development version (%1$s). Cool! Please <a href="%2$s">stay updated</a>.' ), get_bloginfo( 'version', 'display' ), network_admin_url( 'update-core.php' ) ); 
  198.  
  199. case 'upgrade' : 
  200. return '<strong><a href="' . network_admin_url( 'update-core.php' ) . '">' . sprintf( __( 'Get Version %s' ), $cur->current ) . '</a></strong>'; 
  201.  
  202. case 'latest' : 
  203. default : 
  204. return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) ); 
  205.  
  206. /** 
  207. * 
  208. * @global string $pagenow 
  209. * @return false|void 
  210. */ 
  211. function update_nag() { 
  212. if ( is_multisite() && !current_user_can('update_core') ) 
  213. return false; 
  214.  
  215. global $pagenow; 
  216.  
  217. if ( 'update-core.php' == $pagenow ) 
  218. return; 
  219.  
  220. $cur = get_preferred_from_update_core(); 
  221.  
  222. if ( ! isset( $cur->response ) || $cur->response != 'upgrade' ) 
  223. return false; 
  224.  
  225. if ( current_user_can( 'update_core' ) ) { 
  226. $msg = sprintf( 
  227. /** translators: 1: Codex URL to release notes, 2: new WordPress version, 3: URL to network admin, 4: accessibility text */ 
  228. __( '<a href="%1$s">WordPress %2$s</a> is available! <a href="%3$s" aria-label="%4$s">Please update now</a>.' ),  
  229. sprintf( 
  230. /** translators: %s: WordPress version */ 
  231. esc_url( __( 'https://codex.wordpress.org/Version_%s' ) ),  
  232. $cur->current 
  233. ),  
  234. $cur->current,  
  235. network_admin_url( 'update-core.php' ),  
  236. esc_attr__( 'Please update WordPress now' ) 
  237. ); 
  238. } else { 
  239. $msg = sprintf( 
  240. /** translators: 1: Codex URL to release notes, 2: new WordPress version */ 
  241. __( '<a href="%1$s">WordPress %2$s</a> is available! Please notify the site administrator.' ),  
  242. sprintf( 
  243. /** translators: %s: WordPress version */ 
  244. esc_url( __( 'https://codex.wordpress.org/Version_%s' ) ),  
  245. $cur->current 
  246. ),  
  247. $cur->current 
  248. ); 
  249. echo "<div class='update-nag'>$msg</div>"; 
  250.  
  251. // Called directly from dashboard 
  252. function update_right_now_message() { 
  253. $theme_name = wp_get_theme(); 
  254. if ( current_user_can( 'switch_themes' ) ) { 
  255. $theme_name = sprintf( '<a href="themes.php">%1$s</a>', $theme_name ); 
  256.  
  257. $msg = ''; 
  258.  
  259. if ( current_user_can('update_core') ) { 
  260. $cur = get_preferred_from_update_core(); 
  261.  
  262. if ( isset( $cur->response ) && $cur->response == 'upgrade' ) 
  263. $msg .= '<a href="' . network_admin_url( 'update-core.php' ) . '" class="button" aria-describedby="wp-version">' . sprintf( __( 'Update to %s' ), $cur->current ? $cur->current : __( 'Latest' ) ) . '</a> '; 
  264.  
  265. /** translators: 1: version number, 2: theme name */ 
  266. $content = __( 'WordPress %1$s running %2$s theme.' ); 
  267.  
  268. /** 
  269. * Filters the text displayed in the 'At a Glance' dashboard widget. 
  270. * 
  271. * Prior to 3.8.0, the widget was named 'Right Now'. 
  272. * 
  273. * @since 4.4.0 
  274. * 
  275. * @param string $content Default text. 
  276. */ 
  277. $content = apply_filters( 'update_right_now_text', $content ); 
  278.  
  279. $msg .= sprintf( '<span id="wp-version">' . $content . '</span>', get_bloginfo( 'version', 'display' ), $theme_name ); 
  280.  
  281. echo "<p id='wp-version-message'>$msg</p>"; 
  282.  
  283. /** 
  284. * @since 2.9.0 
  285. * 
  286. * @return array 
  287. */ 
  288. function get_plugin_updates() { 
  289. $all_plugins = get_plugins(); 
  290. $upgrade_plugins = array(); 
  291. $current = get_site_transient( 'update_plugins' ); 
  292. foreach ( (array)$all_plugins as $plugin_file => $plugin_data) { 
  293. if ( isset( $current->response[ $plugin_file ] ) ) { 
  294. $upgrade_plugins[ $plugin_file ] = (object) $plugin_data; 
  295. $upgrade_plugins[ $plugin_file ]->update = $current->response[ $plugin_file ]; 
  296.  
  297. return $upgrade_plugins; 
  298.  
  299. /** 
  300. * @since 2.9.0 
  301. */ 
  302. function wp_plugin_update_rows() { 
  303. if ( !current_user_can('update_plugins' ) ) 
  304. return; 
  305.  
  306. $plugins = get_site_transient( 'update_plugins' ); 
  307. if ( isset($plugins->response) && is_array($plugins->response) ) { 
  308. $plugins = array_keys( $plugins->response ); 
  309. foreach ( $plugins as $plugin_file ) { 
  310. add_action( "after_plugin_row_$plugin_file", 'wp_plugin_update_row', 10, 2 ); 
  311.  
  312. /** 
  313. * Displays update information for a plugin. 
  314. * 
  315. * @param string $file Plugin basename. 
  316. * @param array $plugin_data Plugin information. 
  317. * @return false|void 
  318. */ 
  319. function wp_plugin_update_row( $file, $plugin_data ) { 
  320. $current = get_site_transient( 'update_plugins' ); 
  321. if ( ! isset( $current->response[ $file ] ) ) { 
  322. return false; 
  323.  
  324. $response = $current->response[ $file ]; 
  325.  
  326. $plugins_allowedtags = array( 
  327. 'a' => array( 'href' => array(), 'title' => array() ),  
  328. 'abbr' => array( 'title' => array() ),  
  329. 'acronym' => array( 'title' => array() ),  
  330. 'code' => array(),  
  331. 'em' => array(),  
  332. 'strong' => array(),  
  333. ); 
  334.  
  335. $plugin_name = wp_kses( $plugin_data['Name'], $plugins_allowedtags ); 
  336. $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $response->slug . '§ion=changelog&TB_iframe=true&width=600&height=800' ); 
  337.  
  338. /** @var WP_Plugins_List_Table $wp_list_table */ 
  339. $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' ); 
  340.  
  341. if ( is_network_admin() || ! is_multisite() ) { 
  342. if ( is_network_admin() ) { 
  343. $active_class = is_plugin_active_for_network( $file ) ? ' active' : ''; 
  344. } else { 
  345. $active_class = is_plugin_active( $file ) ? ' active' : ''; 
  346.  
  347. echo '<tr class="plugin-update-tr' . $active_class . '" id="' . esc_attr( $response->slug . '-update' ) . '" data-slug="' . esc_attr( $response->slug ) . '" data-plugin="' . esc_attr( $file ) . '"><td colspan="' . esc_attr( $wp_list_table->get_column_count() ) . '" class="plugin-update colspanchange"><div class="update-message notice inline notice-warning notice-alt"><p>'; 
  348.  
  349. if ( ! current_user_can( 'update_plugins' ) ) { 
  350. /** translators: 1: plugin name, 2: details URL, 3: additional link attributes, 4: version number */ 
  351. printf( __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ),  
  352. $plugin_name,  
  353. esc_url( $details_url ),  
  354. sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"',  
  355. /** translators: 1: plugin name, 2: version number */ 
  356. esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) 
  357. ),  
  358. $response->new_version 
  359. ); 
  360. } elseif ( empty( $response->package ) ) { 
  361. /** translators: 1: plugin name, 2: details URL, 3: additional link attributes, 4: version number */ 
  362. printf( __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this plugin.</em>' ),  
  363. $plugin_name,  
  364. esc_url( $details_url ),  
  365. sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"',  
  366. /** translators: 1: plugin name, 2: version number */ 
  367. esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) 
  368. ),  
  369. $response->new_version 
  370. ); 
  371. } else { 
  372. /** translators: 1: plugin name, 2: details URL, 3: additional link attributes, 4: version number, 5: update URL, 6: additional link attributes */ 
  373. printf( __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ),  
  374. $plugin_name,  
  375. esc_url( $details_url ),  
  376. sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"',  
  377. /** translators: 1: plugin name, 2: version number */ 
  378. esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $response->new_version ) ) 
  379. ),  
  380. $response->new_version,  
  381. wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $file, 'upgrade-plugin_' . $file ),  
  382. sprintf( 'class="update-link" aria-label="%s"',  
  383. /** translators: %s: plugin name */ 
  384. esc_attr( sprintf( __( 'Update %s now' ), $plugin_name ) ) 
  385. ); 
  386.  
  387. /** 
  388. * Fires at the end of the update message container in each 
  389. * row of the plugins list table. 
  390. * 
  391. * The dynamic portion of the hook name, `$file`, refers to the path 
  392. * of the plugin's primary file relative to the plugins directory. 
  393. * 
  394. * @since 2.8.0 
  395. * 
  396. * @param array $plugin_data { 
  397. * An array of plugin metadata. 
  398. * 
  399. * @type string $name The human-readable name of the plugin. 
  400. * @type string $plugin_uri Plugin URI. 
  401. * @type string $version Plugin version. 
  402. * @type string $description Plugin description. 
  403. * @type string $author Plugin author. 
  404. * @type string $author_uri Plugin author URI. 
  405. * @type string $text_domain Plugin text domain. 
  406. * @type string $domain_path Relative path to the plugin's .mo file(s). 
  407. * @type bool $network Whether the plugin can only be activated network wide. 
  408. * @type string $title The human-readable title of the plugin. 
  409. * @type string $author_name Plugin author's name. 
  410. * @type bool $update Whether there's an available update. Default null. 
  411. * } 
  412. * @param array $response { 
  413. * An array of metadata about the available plugin update. 
  414. * 
  415. * @type int $id Plugin ID. 
  416. * @type string $slug Plugin slug. 
  417. * @type string $new_version New plugin version. 
  418. * @type string $url Plugin URL. 
  419. * @type string $package Plugin update package URL. 
  420. * } 
  421. */ 
  422. do_action( "in_plugin_update_message-{$file}", $plugin_data, $response ); 
  423.  
  424. echo '</p></div></td></tr>'; 
  425.  
  426. /** 
  427. * 
  428. * @return array 
  429. */ 
  430. function get_theme_updates() { 
  431. $current = get_site_transient('update_themes'); 
  432.  
  433. if ( ! isset( $current->response ) ) 
  434. return array(); 
  435.  
  436. $update_themes = array(); 
  437. foreach ( $current->response as $stylesheet => $data ) { 
  438. $update_themes[ $stylesheet ] = wp_get_theme( $stylesheet ); 
  439. $update_themes[ $stylesheet ]->update = $data; 
  440.  
  441. return $update_themes; 
  442.  
  443. /** 
  444. * @since 3.1.0 
  445. */ 
  446. function wp_theme_update_rows() { 
  447. if ( !current_user_can('update_themes' ) ) 
  448. return; 
  449.  
  450. $themes = get_site_transient( 'update_themes' ); 
  451. if ( isset($themes->response) && is_array($themes->response) ) { 
  452. $themes = array_keys( $themes->response ); 
  453.  
  454. foreach ( $themes as $theme ) { 
  455. add_action( "after_theme_row_$theme", 'wp_theme_update_row', 10, 2 ); 
  456.  
  457. /** 
  458. * Displays update information for a theme. 
  459. * 
  460. * @param string $theme_key Theme stylesheet. 
  461. * @param WP_Theme $theme Theme object. 
  462. * @return false|void 
  463. */ 
  464. function wp_theme_update_row( $theme_key, $theme ) { 
  465. $current = get_site_transient( 'update_themes' ); 
  466.  
  467. if ( ! isset( $current->response[ $theme_key ] ) ) { 
  468. return false; 
  469.  
  470. $response = $current->response[ $theme_key ]; 
  471.  
  472. $details_url = add_query_arg( array( 
  473. 'TB_iframe' => 'true',  
  474. 'width' => 1024,  
  475. 'height' => 800,  
  476. ), $current->response[ $theme_key ]['url'] ); 
  477.  
  478. /** @var WP_MS_Themes_List_Table $wp_list_table */ 
  479. $wp_list_table = _get_list_table( 'WP_MS_Themes_List_Table' ); 
  480.  
  481. $active = $theme->is_allowed( 'network' ) ? ' active' : ''; 
  482.  
  483. echo '<tr class="plugin-update-tr' . $active . '" id="' . esc_attr( $theme->get_stylesheet() . '-update' ) . '" data-slug="' . esc_attr( $theme->get_stylesheet() ) . '"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange"><div class="update-message notice inline notice-warning notice-alt"><p>'; 
  484. if ( ! current_user_can( 'update_themes' ) ) { 
  485. /** translators: 1: theme name, 2: details URL, 3: additional link attributes, 4: version number */ 
  486. printf( __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.'),  
  487. $theme['Name'],  
  488. esc_url( $details_url ),  
  489. sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"',  
  490. /** translators: 1: theme name, 2: version number */ 
  491. esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) 
  492. ),  
  493. $response['new_version'] 
  494. ); 
  495. } elseif ( empty( $response['package'] ) ) { 
  496. /** translators: 1: theme name, 2: details URL, 3: additional link attributes, 4: version number */ 
  497. printf( __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ),  
  498. $theme['Name'],  
  499. esc_url( $details_url ),  
  500. sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"',  
  501. /** translators: 1: theme name, 2: version number */ 
  502. esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) 
  503. ),  
  504. $response['new_version'] 
  505. ); 
  506. } else { 
  507. /** translators: 1: theme name, 2: details URL, 3: additional link attributes, 4: version number, 5: update URL, 6: additional link attributes */ 
  508. printf( __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ),  
  509. $theme['Name'],  
  510. esc_url( $details_url ),  
  511. sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"',  
  512. /** translators: 1: theme name, 2: version number */ 
  513. esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme['Name'], $response['new_version'] ) ) 
  514. ),  
  515. $response['new_version'],  
  516. wp_nonce_url( self_admin_url( 'update.php?action=upgrade-theme&theme=' ) . $theme_key, 'upgrade-theme_' . $theme_key ),  
  517. sprintf( 'class="update-link" aria-label="%s"',  
  518. /** translators: %s: theme name */ 
  519. esc_attr( sprintf( __( 'Update %s now' ), $theme['Name'] ) ) 
  520. ); 
  521.  
  522. /** 
  523. * Fires at the end of the update message container in each 
  524. * row of the themes list table. 
  525. * 
  526. * The dynamic portion of the hook name, `$theme_key`, refers to 
  527. * the theme slug as found in the WordPress.org themes repository. 
  528. * 
  529. * @since 3.1.0 
  530. * 
  531. * @param WP_Theme $theme The WP_Theme object. 
  532. * @param array $response { 
  533. * An array of metadata about the available theme update. 
  534. * 
  535. * @type string $new_version New theme version. 
  536. * @type string $url Theme URL. 
  537. * @type string $package Theme update package URL. 
  538. * } 
  539. */ 
  540. do_action( "in_theme_update_message-{$theme_key}", $theme, $response ); 
  541.  
  542. echo '</p></div></td></tr>'; 
  543.  
  544. /** 
  545. * 
  546. * @global int $upgrading 
  547. * @return false|void 
  548. */ 
  549. function maintenance_nag() { 
  550. include( ABSPATH . WPINC . '/version.php' ); // include an unmodified $wp_version 
  551. global $upgrading; 
  552. $nag = isset( $upgrading ); 
  553. if ( ! $nag ) { 
  554. $failed = get_site_option( 'auto_core_update_failed' ); 
  555. /** 
  556. * If an update failed critically, we may have copied over version.php but not other files. 
  557. * In that case, if the install claims we're running the version we attempted, nag. 
  558. * This is serious enough to err on the side of nagging. 
  559. * 
  560. * If we simply failed to update before we tried to copy any files, then assume things are 
  561. * OK if they are now running the latest. 
  562. * 
  563. * This flag is cleared whenever a successful update occurs using Core_Upgrader. 
  564. */ 
  565. $comparison = ! empty( $failed['critical'] ) ? '>=' : '>'; 
  566. if ( version_compare( $failed['attempted'], $wp_version, $comparison ) ) 
  567. $nag = true; 
  568.  
  569. if ( ! $nag ) 
  570. return false; 
  571.  
  572. if ( current_user_can('update_core') ) 
  573. $msg = sprintf( __('An automated WordPress update has failed to complete - <a href="%s">please attempt the update again now</a>.'), 'update-core.php' ); 
  574. else 
  575. $msg = __('An automated WordPress update has failed to complete! Please notify the site administrator.'); 
  576.  
  577. echo "<div class='update-nag'>$msg</div>"; 
  578.  
  579. /** 
  580. * Prints the JavaScript templates for update admin notices. 
  581. * 
  582. * Template takes one argument with four values: 
  583. * 
  584. * param {object} data { 
  585. * Arguments for admin notice. 
  586. * 
  587. * @type string id ID of the notice. 
  588. * @type string className Class names for the notice. 
  589. * @type string message The notice's message. 
  590. * @type string type The type of update the notice is for. Either 'plugin' or 'theme'. 
  591. * } 
  592. * 
  593. * @since 4.6.0 
  594. */ 
  595. function wp_print_admin_notice_templates() { 
  596. ?> 
  597. <script id="tmpl-wp-updates-admin-notice" type="text/html"> 
  598. <div <# if ( data.id ) { #>id="{{ data.id }}"<# } #> class="notice {{ data.className }}"><p>{{{ data.message }}}</p></div> 
  599. </script> 
  600. <script id="tmpl-wp-bulk-updates-admin-notice" type="text/html"> 
  601. <div id="{{ data.id }}" class="{{ data.className }} notice <# if ( data.errors ) { #>notice-error<# } else { #>notice-success<# } #>"> 
  602. <p> 
  603. <# if ( data.successes ) { #> 
  604. <# if ( 1 === data.successes ) { #> 
  605. <# if ( 'plugin' === data.type ) { #> 
  606. <?php 
  607. /** translators: %s: Number of plugins */ 
  608. printf( __( '%s plugin successfully updated.' ), '{{ data.successes }}' ); 
  609. ?> 
  610. <# } else { #> 
  611. <?php 
  612. /** translators: %s: Number of themes */ 
  613. printf( __( '%s theme successfully updated.' ), '{{ data.successes }}' ); 
  614. ?> 
  615. <# } #> 
  616. <# } else { #> 
  617. <# if ( 'plugin' === data.type ) { #> 
  618. <?php 
  619. /** translators: %s: Number of plugins */ 
  620. printf( __( '%s plugins successfully updated.' ), '{{ data.successes }}' ); 
  621. ?> 
  622. <# } else { #> 
  623. <?php 
  624. /** translators: %s: Number of themes */ 
  625. printf( __( '%s themes successfully updated.' ), '{{ data.successes }}' ); 
  626. ?> 
  627. <# } #> 
  628. <# } #> 
  629. <# } #> 
  630. <# if ( data.errors ) { #> 
  631. <button class="button-link bulk-action-errors-collapsed" aria-expanded="false"> 
  632. <# if ( 1 === data.errors ) { #> 
  633. <?php 
  634. /** translators: %s: Number of failed updates */ 
  635. printf( __( '%s update failed.' ), '{{ data.errors }}' ); 
  636. ?> 
  637. <# } else { #> 
  638. <?php 
  639. /** translators: %s: Number of failed updates */ 
  640. printf( __( '%s updates failed.' ), '{{ data.errors }}' ); 
  641. ?> 
  642. <# } #> 
  643. <span class="screen-reader-text"><?php _e( 'Show more details' ); ?></span> 
  644. <span class="toggle-indicator" aria-hidden="true"></span> 
  645. </button> 
  646. <# } #> 
  647. </p> 
  648. <# if ( data.errors ) { #> 
  649. <ul class="bulk-action-errors hidden"> 
  650. <# _.each( data.errorMessages, function( errorMessage ) { #> 
  651. <li>{{ errorMessage }}</li> 
  652. <# } ); #> 
  653. </ul> 
  654. <# } #> 
  655. </div> 
  656. </script> 
  657. <?php 
  658.  
  659. /** 
  660. * Prints the JavaScript templates for update and deletion rows in list tables. 
  661. * 
  662. * The update template takes one argument with four values: 
  663. * 
  664. * param {object} data { 
  665. * Arguments for the update row 
  666. * 
  667. * @type string slug Plugin slug. 
  668. * @type string plugin Plugin base name. 
  669. * @type string colspan The number of table columns this row spans. 
  670. * @type string content The row content. 
  671. * } 
  672. * 
  673. * The delete template takes one argument with four values: 
  674. * 
  675. * param {object} data { 
  676. * Arguments for the update row 
  677. * 
  678. * @type string slug Plugin slug. 
  679. * @type string plugin Plugin base name. 
  680. * @type string name Plugin name. 
  681. * @type string colspan The number of table columns this row spans. 
  682. * } 
  683. * 
  684. * @since 4.6.0 
  685. */ 
  686. function wp_print_update_row_templates() { 
  687. ?> 
  688. <script id="tmpl-item-update-row" type="text/template"> 
  689. <tr class="plugin-update-tr update" id="{{ data.slug }}-update" data-slug="{{ data.slug }}" <# if ( data.plugin ) { #>data-plugin="{{ data.plugin }}"<# } #>> 
  690. <td colspan="{{ data.colspan }}" class="plugin-update colspanchange"> 
  691. {{{ data.content }}} 
  692. </td> 
  693. </tr> 
  694. </script> 
  695. <script id="tmpl-item-deleted-row" type="text/template"> 
  696. <tr class="plugin-deleted-tr inactive deleted" id="{{ data.slug }}-deleted" data-slug="{{ data.slug }}" <# if ( data.plugin ) { #>data-plugin="{{ data.plugin }}"<# } #>> 
  697. <td colspan="{{ data.colspan }}" class="plugin-update colspanchange"> 
  698. <# if ( data.plugin ) { #> 
  699. <?php 
  700. printf( 
  701. /** translators: %s: Plugin name */ 
  702. _x( '%s was successfully deleted.', 'plugin' ),  
  703. '<strong>{{{ data.name }}}</strong>' 
  704. ); 
  705. ?> 
  706. <# } else { #> 
  707. <?php 
  708. printf( 
  709. /** translators: %s: Theme name */ 
  710. _x( '%s was successfully deleted.', 'theme' ),  
  711. '<strong>{{{ data.name }}}</strong>' 
  712. ); 
  713. ?> 
  714. <# } #> 
  715. </td> 
  716. </tr> 
  717. </script> 
  718. <?php 
.