~canonical-sysadmins/wordpress/4.7.2

« back to all changes in this revision

Viewing changes to wp-admin/includes/update.php

  • Committer: Jacek Nykis
  • Date: 2015-01-05 16:17:05 UTC
  • Revision ID: jacek.nykis@canonical.com-20150105161705-w544l1h5mcg7u4w9
Initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 bool|object 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 bool|array 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 install allows it, else, 1.2.3
 
67
 *
 
68
 * @since 3.7.0
 
69
 *
 
70
 * @return bool|array 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' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3 ),
 
111
        );
 
112
 
 
113
        $response = wp_remote_get( $url, $options );
 
114
        if ( $ssl && is_wp_error( $response ) ) {
 
115
                trigger_error( __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE );
 
116
                $response = wp_remote_get( $http_url, $options );
 
117
        }
 
118
 
 
119
        if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) )
 
120
                return false;
 
121
 
 
122
        $body = trim( wp_remote_retrieve_body( $response ) );
 
123
        $body = json_decode( $body, true );
 
124
 
 
125
        if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) )
 
126
                return false;
 
127
 
 
128
        return $body['checksums'];
 
129
}
 
130
 
 
131
function dismiss_core_update( $update ) {
 
132
        $dismissed = get_site_option( 'dismissed_update_core' );
 
133
        $dismissed[ $update->current . '|' . $update->locale ] = true;
 
134
        return update_site_option( 'dismissed_update_core', $dismissed );
 
135
}
 
136
 
 
137
function undismiss_core_update( $version, $locale ) {
 
138
        $dismissed = get_site_option( 'dismissed_update_core' );
 
139
        $key = $version . '|' . $locale;
 
140
 
 
141
        if ( ! isset( $dismissed[$key] ) )
 
142
                return false;
 
143
 
 
144
        unset( $dismissed[$key] );
 
145
        return update_site_option( 'dismissed_update_core', $dismissed );
 
146
}
 
147
 
 
148
function find_core_update( $version, $locale ) {
 
149
        $from_api = get_site_transient( 'update_core' );
 
150
 
 
151
        if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) )
 
152
                return false;
 
153
 
 
154
        $updates = $from_api->updates;
 
155
        foreach ( $updates as $update ) {
 
156
                if ( $update->current == $version && $update->locale == $locale )
 
157
                        return $update;
 
158
        }
 
159
        return false;
 
160
}
 
161
 
 
162
function core_update_footer( $msg = '' ) {
 
163
        if ( !current_user_can('update_core') )
 
164
                return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) );
 
165
 
 
166
        $cur = get_preferred_from_update_core();
 
167
        if ( ! is_object( $cur ) )
 
168
                $cur = new stdClass;
 
169
 
 
170
        if ( ! isset( $cur->current ) )
 
171
                $cur->current = '';
 
172
 
 
173
        if ( ! isset( $cur->url ) )
 
174
                $cur->url = '';
 
175
 
 
176
        if ( ! isset( $cur->response ) )
 
177
                $cur->response = '';
 
178
 
 
179
        switch ( $cur->response ) {
 
180
        case 'development' :
 
181
                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' ) );
 
182
 
 
183
        case 'upgrade' :
 
184
                return sprintf( '<strong>'.__( '<a href="%1$s">Get Version %2$s</a>' ).'</strong>', network_admin_url( 'update-core.php' ), $cur->current);
 
185
 
 
186
        case 'latest' :
 
187
        default :
 
188
                return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) );
 
189
        }
 
190
}
 
191
add_filter( 'update_footer', 'core_update_footer' );
 
192
 
 
193
function update_nag() {
 
194
        if ( is_multisite() && !current_user_can('update_core') )
 
195
                return false;
 
196
 
 
197
        global $pagenow;
 
198
 
 
199
        if ( 'update-core.php' == $pagenow )
 
200
                return;
 
201
 
 
202
        $cur = get_preferred_from_update_core();
 
203
 
 
204
        if ( ! isset( $cur->response ) || $cur->response != 'upgrade' )
 
205
                return false;
 
206
 
 
207
        if ( current_user_can('update_core') ) {
 
208
                $msg = sprintf( __('<a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> is available! <a href="%2$s">Please update now</a>.'), $cur->current, network_admin_url( 'update-core.php' ) );
 
209
        } else {
 
210
                $msg = sprintf( __('<a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> is available! Please notify the site administrator.'), $cur->current );
 
211
        }
 
212
        echo "<div class='update-nag'>$msg</div>";
 
213
}
 
214
add_action( 'admin_notices', 'update_nag', 3 );
 
215
add_action( 'network_admin_notices', 'update_nag', 3 );
 
216
 
 
217
// Called directly from dashboard
 
218
function update_right_now_message() {
 
219
        $theme_name = wp_get_theme();
 
220
        if ( current_user_can( 'switch_themes' ) ) {
 
221
                $theme_name = sprintf( '<a href="themes.php">%1$s</a>', $theme_name );
 
222
        }
 
223
 
 
224
        $msg = sprintf( __( 'WordPress %1$s running %2$s theme.' ), get_bloginfo( 'version', 'display' ), $theme_name );
 
225
 
 
226
        if ( current_user_can('update_core') ) {
 
227
                $cur = get_preferred_from_update_core();
 
228
 
 
229
                if ( isset( $cur->response ) && $cur->response == 'upgrade' )
 
230
                        $msg .= " <a href='" . network_admin_url( 'update-core.php' ) . "' class='button'>" . sprintf( __('Update to %s'), $cur->current ? $cur->current : __( 'Latest' ) ) . '</a>';
 
231
        }
 
232
 
 
233
        echo "<p id='wp-version-message'>$msg</p>";
 
234
}
 
235
 
 
236
function get_plugin_updates() {
 
237
        $all_plugins = get_plugins();
 
238
        $upgrade_plugins = array();
 
239
        $current = get_site_transient( 'update_plugins' );
 
240
        foreach ( (array)$all_plugins as $plugin_file => $plugin_data) {
 
241
                if ( isset( $current->response[ $plugin_file ] ) ) {
 
242
                        $upgrade_plugins[ $plugin_file ] = (object) $plugin_data;
 
243
                        $upgrade_plugins[ $plugin_file ]->update = $current->response[ $plugin_file ];
 
244
                }
 
245
        }
 
246
 
 
247
        return $upgrade_plugins;
 
248
}
 
249
 
 
250
function wp_plugin_update_rows() {
 
251
        if ( !current_user_can('update_plugins' ) )
 
252
                return;
 
253
 
 
254
        $plugins = get_site_transient( 'update_plugins' );
 
255
        if ( isset($plugins->response) && is_array($plugins->response) ) {
 
256
                $plugins = array_keys( $plugins->response );
 
257
                foreach( $plugins as $plugin_file ) {
 
258
                        add_action( "after_plugin_row_$plugin_file", 'wp_plugin_update_row', 10, 2 );
 
259
                }
 
260
        }
 
261
}
 
262
add_action( 'admin_init', 'wp_plugin_update_rows' );
 
263
 
 
264
function wp_plugin_update_row( $file, $plugin_data ) {
 
265
        $current = get_site_transient( 'update_plugins' );
 
266
        if ( !isset( $current->response[ $file ] ) )
 
267
                return false;
 
268
 
 
269
        $r = $current->response[ $file ];
 
270
 
 
271
        $plugins_allowedtags = array('a' => array('href' => array(),'title' => array()),'abbr' => array('title' => array()),'acronym' => array('title' => array()),'code' => array(),'em' => array(),'strong' => array());
 
272
        $plugin_name = wp_kses( $plugin_data['Name'], $plugins_allowedtags );
 
273
 
 
274
        $details_url = self_admin_url('plugin-install.php?tab=plugin-information&plugin=' . $r->slug . '&section=changelog&TB_iframe=true&width=600&height=800');
 
275
 
 
276
        $wp_list_table = _get_list_table('WP_Plugins_List_Table');
 
277
 
 
278
        if ( is_network_admin() || !is_multisite() ) {
 
279
                echo '<tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange"><div class="update-message">';
 
280
 
 
281
                if ( ! current_user_can('update_plugins') )
 
282
                        printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a>.'), $plugin_name, esc_url($details_url), esc_attr($plugin_name), $r->new_version );
 
283
                else if ( empty($r->package) )
 
284
                        printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a>. <em>Automatic update is unavailable for this plugin.</em>'), $plugin_name, esc_url($details_url), esc_attr($plugin_name), $r->new_version );
 
285
                else
 
286
                        printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a> or <a href="%5$s">update now</a>.'), $plugin_name, esc_url($details_url), esc_attr($plugin_name), $r->new_version, wp_nonce_url( self_admin_url('update.php?action=upgrade-plugin&plugin=') . $file, 'upgrade-plugin_' . $file) );
 
287
 
 
288
                /**
 
289
                 * Fires at the end of the update message container in each
 
290
                 * row of the plugins list table.
 
291
                 *
 
292
                 * The dynamic portion of the hook name, $file, refers to the path
 
293
                 * of the plugin's primary file relative to the plugins directory.
 
294
                 *
 
295
                 * @since 2.8.0
 
296
                 *
 
297
                 * @param array $plugin_data {
 
298
                 *     An array of plugin metadata.
 
299
                 *
 
300
                 *     @type string $name         The human-readable name of the plugin.
 
301
                 *     @type string $plugin_uri   Plugin URI.
 
302
                 *     @type string $version      Plugin version.
 
303
                 *     @type string $description  Plugin description.
 
304
                 *     @type string $author       Plugin author.
 
305
                 *     @type string $author_uri   Plugin author URI.
 
306
                 *     @type string $text_domain  Plugin text domain.
 
307
                 *     @type string $domain_path  Relative path to the plugin's .mo file(s).
 
308
                 *     @type bool   $network      Whether the plugin can only be activated network wide.
 
309
                 *     @type string $title        The human-readable title of the plugin.
 
310
                 *     @type string $author_name  Plugin author's name.
 
311
                 *     @type bool   $update       Whether there's an available update. Default null.
 
312
                 * }
 
313
                 * @param array $r {
 
314
                 *     An array of metadata about the available plugin update.
 
315
                 *
 
316
                 *     @type int    $id           Plugin ID.
 
317
                 *     @type string $slug         Plugin slug.
 
318
                 *     @type string $new_version  New plugin version.
 
319
                 *     @type string $url          Plugin URL.
 
320
                 *     @type string $package      Plugin update package URL.
 
321
                 * }
 
322
                 */
 
323
                do_action( "in_plugin_update_message-{$file}", $plugin_data, $r );
 
324
 
 
325
                echo '</div></td></tr>';
 
326
        }
 
327
}
 
328
 
 
329
function get_theme_updates() {
 
330
        $current = get_site_transient('update_themes');
 
331
 
 
332
        if ( ! isset( $current->response ) )
 
333
                return array();
 
334
 
 
335
        $update_themes = array();
 
336
        foreach ( $current->response as $stylesheet => $data ) {
 
337
                $update_themes[ $stylesheet ] = wp_get_theme( $stylesheet );
 
338
                $update_themes[ $stylesheet ]->update = $data;
 
339
        }
 
340
 
 
341
        return $update_themes;
 
342
}
 
343
 
 
344
function wp_theme_update_rows() {
 
345
        if ( !current_user_can('update_themes' ) )
 
346
                return;
 
347
 
 
348
        $themes = get_site_transient( 'update_themes' );
 
349
        if ( isset($themes->response) && is_array($themes->response) ) {
 
350
                $themes = array_keys( $themes->response );
 
351
 
 
352
                foreach( $themes as $theme ) {
 
353
                        add_action( "after_theme_row_$theme", 'wp_theme_update_row', 10, 2 );
 
354
                }
 
355
        }
 
356
}
 
357
add_action( 'admin_init', 'wp_theme_update_rows' );
 
358
 
 
359
function wp_theme_update_row( $theme_key, $theme ) {
 
360
        $current = get_site_transient( 'update_themes' );
 
361
        if ( !isset( $current->response[ $theme_key ] ) )
 
362
                return false;
 
363
        $r = $current->response[ $theme_key ];
 
364
 
 
365
        $details_url = add_query_arg( array( 'TB_iframe' => 'true', 'width' => 1024, 'height' => 800 ), $current->response[ $theme_key ]['url'] );
 
366
 
 
367
        $wp_list_table = _get_list_table('WP_MS_Themes_List_Table');
 
368
 
 
369
        echo '<tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange"><div class="update-message">';
 
370
        if ( ! current_user_can('update_themes') )
 
371
                printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a>.'), $theme['Name'], esc_url($details_url), esc_attr($theme['Name']), $r->new_version );
 
372
        else if ( empty( $r['package'] ) )
 
373
                printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>'), $theme['Name'], esc_url($details_url), esc_attr($theme['Name']), $r['new_version'] );
 
374
        else
 
375
                printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a> or <a href="%5$s">update now</a>.'), $theme['Name'], esc_url($details_url), esc_attr($theme['Name']), $r['new_version'], wp_nonce_url( self_admin_url('update.php?action=upgrade-theme&theme=') . $theme_key, 'upgrade-theme_' . $theme_key) );
 
376
 
 
377
        /**
 
378
         * Fires at the end of the update message container in each
 
379
         * row of the themes list table.
 
380
         *
 
381
         * The dynamic portion of the hook name, $theme_key, refers to
 
382
         * the theme slug as found in the WordPress.org themes repository.
 
383
         *
 
384
         * @since 3.1.0
 
385
         *
 
386
         * @param WP_Theme $theme The WP_Theme object.
 
387
         * @param array    $r {
 
388
         *     An array of metadata about the available theme update.
 
389
         *
 
390
         *     @type string $new_version New theme version.
 
391
         *     @type string $url         Theme URL.
 
392
         *     @type string $package     Theme update package URL.
 
393
         * }
 
394
         */
 
395
        do_action( "in_theme_update_message-{$theme_key}", $theme, $r );
 
396
 
 
397
        echo '</div></td></tr>';
 
398
}
 
399
 
 
400
function maintenance_nag() {
 
401
        include( ABSPATH . WPINC . '/version.php' ); // include an unmodified $wp_version
 
402
        global $upgrading;
 
403
        $nag = isset( $upgrading );
 
404
        if ( ! $nag ) {
 
405
                $failed = get_site_option( 'auto_core_update_failed' );
 
406
                /*
 
407
                 * If an update failed critically, we may have copied over version.php but not other files.
 
408
                 * In that case, if the install claims we're running the version we attempted, nag.
 
409
                 * This is serious enough to err on the side of nagging.
 
410
                 *
 
411
                 * If we simply failed to update before we tried to copy any files, then assume things are
 
412
                 * OK if they are now running the latest.
 
413
                 *
 
414
                 * This flag is cleared whenever a successful update occurs using Core_Upgrader.
 
415
                 */
 
416
                $comparison = ! empty( $failed['critical'] ) ? '>=' : '>';
 
417
                if ( version_compare( $failed['attempted'], $wp_version, $comparison ) )
 
418
                        $nag = true;
 
419
        }
 
420
 
 
421
        if ( ! $nag )
 
422
                return false;
 
423
 
 
424
        if ( current_user_can('update_core') )
 
425
                $msg = sprintf( __('An automated WordPress update has failed to complete - <a href="%s">please attempt the update again now</a>.'), 'update-core.php' );
 
426
        else
 
427
                $msg = __('An automated WordPress update has failed to complete! Please notify the site administrator.');
 
428
 
 
429
        echo "<div class='update-nag'>$msg</div>";
 
430
}
 
431
add_action( 'admin_notices', 'maintenance_nag' );
 
432
add_action( 'network_admin_notices', 'maintenance_nag' );