home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-admin / includes / update.php < prev    next >
Encoding:
PHP Script  |  2017-08-22  |  25.3 KB  |  765 lines

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