~canonical-sysadmins/wordpress/4.8.1

« back to all changes in this revision

Viewing changes to wp-admin/includes/class-language-pack-upgrader.php

  • Committer: Barry Price
  • Date: 2016-08-17 04:50:12 UTC
  • mfrom: (1.1.18 upstream)
  • Revision ID: barry.price@canonical.com-20160817045012-qfui81zhqnqv2ba9
Merge WP4.6 from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Upgrade API: Language_Pack_Upgrader class
 
4
 *
 
5
 * @package WordPress
 
6
 * @subpackage Upgrader
 
7
 * @since 4.6.0
 
8
 */
 
9
 
 
10
/**
 
11
 * Core class used for updating/installing language packs (translations)
 
12
 * for plugins, themes, and core.
 
13
 *
 
14
 * @since 3.7.0
 
15
 * @since 4.6.0 Moved to its own file from wp-admin/includes/class-wp-upgrader.php.
 
16
 *
 
17
 * @see WP_Upgrader
 
18
 */
 
19
class Language_Pack_Upgrader extends WP_Upgrader {
 
20
 
 
21
        /**
 
22
         * Result of the language pack upgrade.
 
23
         *
 
24
         * @since 3.7.0
 
25
         * @access public
 
26
         * @var array|WP_Error $result
 
27
         * @see WP_Upgrader::$result
 
28
         */
 
29
        public $result;
 
30
 
 
31
        /**
 
32
         * Whether a bulk upgrade/install is being performed.
 
33
         *
 
34
         * @since 3.7.0
 
35
         * @access public
 
36
         * @var bool $bulk
 
37
         */
 
38
        public $bulk = true;
 
39
 
 
40
        /**
 
41
         * Asynchronously upgrades language packs after other upgrades have been made.
 
42
         *
 
43
         * Hooked to the {@see 'upgrader_process_complete'} action by default.
 
44
         *
 
45
         * @since 3.7.0
 
46
         * @access public
 
47
         * @static
 
48
         *
 
49
         * @param false|WP_Upgrader $upgrader Optional. WP_Upgrader instance or false. If `$upgrader` is
 
50
         *                                    a Language_Pack_Upgrader instance, the method will bail to
 
51
         *                                    avoid recursion. Otherwise unused. Default false.
 
52
         */
 
53
        public static function async_upgrade( $upgrader = false ) {
 
54
                // Avoid recursion.
 
55
                if ( $upgrader && $upgrader instanceof Language_Pack_Upgrader ) {
 
56
                        return;
 
57
                }
 
58
 
 
59
                // Nothing to do?
 
60
                $language_updates = wp_get_translation_updates();
 
61
                if ( ! $language_updates ) {
 
62
                        return;
 
63
                }
 
64
 
 
65
                /*
 
66
                 * Avoid messing with VCS installs, at least for now.
 
67
                 * Noted: this is not the ideal way to accomplish this.
 
68
                 */
 
69
                $check_vcs = new WP_Automatic_Updater;
 
70
                if ( $check_vcs->is_vcs_checkout( WP_CONTENT_DIR ) ) {
 
71
                        return;
 
72
                }
 
73
 
 
74
                foreach ( $language_updates as $key => $language_update ) {
 
75
                        $update = ! empty( $language_update->autoupdate );
 
76
 
 
77
                        /**
 
78
                         * Filters whether to asynchronously update translation for core, a plugin, or a theme.
 
79
                         *
 
80
                         * @since 4.0.0
 
81
                         *
 
82
                         * @param bool   $update          Whether to update.
 
83
                         * @param object $language_update The update offer.
 
84
                         */
 
85
                        $update = apply_filters( 'async_update_translation', $update, $language_update );
 
86
 
 
87
                        if ( ! $update ) {
 
88
                                unset( $language_updates[ $key ] );
 
89
                        }
 
90
                }
 
91
 
 
92
                if ( empty( $language_updates ) ) {
 
93
                        return;
 
94
                }
 
95
 
 
96
                // Re-use the automatic upgrader skin if the parent upgrader is using it.
 
97
                if ( $upgrader && $upgrader->skin instanceof Automatic_Upgrader_Skin ) {
 
98
                        $skin = $upgrader->skin;
 
99
                } else {
 
100
                        $skin = new Language_Pack_Upgrader_Skin( array(
 
101
                                'skip_header_footer' => true,
 
102
                        ) );
 
103
                }
 
104
 
 
105
                $lp_upgrader = new Language_Pack_Upgrader( $skin );
 
106
                $lp_upgrader->bulk_upgrade( $language_updates );
 
107
        }
 
108
 
 
109
        /**
 
110
         * Initialize the upgrade strings.
 
111
         *
 
112
         * @since 3.7.0
 
113
         * @access public
 
114
         */
 
115
        public function upgrade_strings() {
 
116
                $this->strings['starting_upgrade'] = __( 'Some of your translations need updating. Sit tight for a few more seconds while we update them as well.' );
 
117
                $this->strings['up_to_date'] = __( 'The translations are up to date.' );
 
118
                $this->strings['no_package'] = __( 'Update package not available.' );
 
119
                $this->strings['downloading_package'] = __( 'Downloading translation from <span class="code">%s</span>&#8230;' );
 
120
                $this->strings['unpack_package'] = __( 'Unpacking the update&#8230;' );
 
121
                $this->strings['process_failed'] = __( 'Translation update failed.' );
 
122
                $this->strings['process_success'] = __( 'Translation updated successfully.' );
 
123
        }
 
124
 
 
125
        /**
 
126
         * Upgrade a language pack.
 
127
         *
 
128
         * @since 3.7.0
 
129
         * @access public
 
130
         *
 
131
         * @param string|false $update Optional. Whether an update offer is available. Default false.
 
132
         * @param array        $args   Optional. Other optional arguments, see
 
133
         *                             Language_Pack_Upgrader::bulk_upgrade(). Default empty array.
 
134
         * @return array|bool|WP_Error The result of the upgrade, or a WP_Error object instead.
 
135
         */
 
136
        public function upgrade( $update = false, $args = array() ) {
 
137
                if ( $update ) {
 
138
                        $update = array( $update );
 
139
                }
 
140
 
 
141
                $results = $this->bulk_upgrade( $update, $args );
 
142
 
 
143
                if ( ! is_array( $results ) ) {
 
144
                        return $results;
 
145
                }
 
146
 
 
147
                return $results[0];
 
148
        }
 
149
 
 
150
        /**
 
151
         * Bulk upgrade language packs.
 
152
         *
 
153
         * @since 3.7.0
 
154
         * @access public
 
155
         *
 
156
         * @global WP_Filesystem_Base $wp_filesystem Subclass
 
157
         *
 
158
         * @param array $language_updates Optional. Language pack updates. Default empty array.
 
159
         * @param array $args {
 
160
         *     Optional. Other arguments for upgrading multiple language packs. Default empty array
 
161
         *
 
162
         *     @type bool $clear_update_cache Whether to clear the update cache when done.
 
163
         *                                    Default true.
 
164
         * }
 
165
         * @return array|bool|WP_Error Will return an array of results, or true if there are no updates,
 
166
         *                                   false or WP_Error for initial errors.
 
167
         */
 
168
        public function bulk_upgrade( $language_updates = array(), $args = array() ) {
 
169
                global $wp_filesystem;
 
170
 
 
171
                $defaults = array(
 
172
                        'clear_update_cache' => true,
 
173
                );
 
174
                $parsed_args = wp_parse_args( $args, $defaults );
 
175
 
 
176
                $this->init();
 
177
                $this->upgrade_strings();
 
178
 
 
179
                if ( ! $language_updates )
 
180
                        $language_updates = wp_get_translation_updates();
 
181
 
 
182
                if ( empty( $language_updates ) ) {
 
183
                        $this->skin->header();
 
184
                        $this->skin->set_result( true );
 
185
                        $this->skin->feedback( 'up_to_date' );
 
186
                        $this->skin->bulk_footer();
 
187
                        $this->skin->footer();
 
188
                        return true;
 
189
                }
 
190
 
 
191
                if ( 'upgrader_process_complete' == current_filter() )
 
192
                        $this->skin->feedback( 'starting_upgrade' );
 
193
 
 
194
                // Remove any existing upgrade filters from the plugin/theme upgraders #WP29425 & #WP29230
 
195
                remove_all_filters( 'upgrader_pre_install' );
 
196
                remove_all_filters( 'upgrader_clear_destination' );
 
197
                remove_all_filters( 'upgrader_post_install' );
 
198
                remove_all_filters( 'upgrader_source_selection' );
 
199
 
 
200
                add_filter( 'upgrader_source_selection', array( $this, 'check_package' ), 10, 2 );
 
201
 
 
202
                $this->skin->header();
 
203
 
 
204
                // Connect to the Filesystem first.
 
205
                $res = $this->fs_connect( array( WP_CONTENT_DIR, WP_LANG_DIR ) );
 
206
                if ( ! $res ) {
 
207
                        $this->skin->footer();
 
208
                        return false;
 
209
                }
 
210
 
 
211
                $results = array();
 
212
 
 
213
                $this->update_count = count( $language_updates );
 
214
                $this->update_current = 0;
 
215
 
 
216
                /*
 
217
                 * The filesystem's mkdir() is not recursive. Make sure WP_LANG_DIR exists,
 
218
                 * as we then may need to create a /plugins or /themes directory inside of it.
 
219
                 */
 
220
                $remote_destination = $wp_filesystem->find_folder( WP_LANG_DIR );
 
221
                if ( ! $wp_filesystem->exists( $remote_destination ) )
 
222
                        if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) )
 
223
                                return new WP_Error( 'mkdir_failed_lang_dir', $this->strings['mkdir_failed'], $remote_destination );
 
224
 
 
225
                $language_updates_results = array();
 
226
 
 
227
                foreach ( $language_updates as $language_update ) {
 
228
 
 
229
                        $this->skin->language_update = $language_update;
 
230
 
 
231
                        $destination = WP_LANG_DIR;
 
232
                        if ( 'plugin' == $language_update->type )
 
233
                                $destination .= '/plugins';
 
234
                        elseif ( 'theme' == $language_update->type )
 
235
                                $destination .= '/themes';
 
236
 
 
237
                        $this->update_current++;
 
238
 
 
239
                        $options = array(
 
240
                                'package' => $language_update->package,
 
241
                                'destination' => $destination,
 
242
                                'clear_destination' => false,
 
243
                                'abort_if_destination_exists' => false, // We expect the destination to exist.
 
244
                                'clear_working' => true,
 
245
                                'is_multi' => true,
 
246
                                'hook_extra' => array(
 
247
                                        'language_update_type' => $language_update->type,
 
248
                                        'language_update' => $language_update,
 
249
                                )
 
250
                        );
 
251
 
 
252
                        $result = $this->run( $options );
 
253
 
 
254
                        $results[] = $this->result;
 
255
 
 
256
                        // Prevent credentials auth screen from displaying multiple times.
 
257
                        if ( false === $result ) {
 
258
                                break;
 
259
                        }
 
260
 
 
261
                        $language_updates_results[] = array(
 
262
                                'language' => $language_update->language,
 
263
                                'type'     => $language_update->type,
 
264
                                'slug'     => isset( $language_update->slug ) ? $language_update->slug : 'default',
 
265
                                'version'  => $language_update->version,
 
266
                        );
 
267
                }
 
268
 
 
269
                // Remove upgrade hooks which are not required for translation updates.
 
270
                remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
 
271
                remove_action( 'upgrader_process_complete', 'wp_version_check' );
 
272
                remove_action( 'upgrader_process_complete', 'wp_update_plugins' );
 
273
                remove_action( 'upgrader_process_complete', 'wp_update_themes' );
 
274
 
 
275
                /** This action is documented in wp-admin/includes/class-wp-upgrader.php */
 
276
                do_action( 'upgrader_process_complete', $this, array(
 
277
                        'action'       => 'update',
 
278
                        'type'         => 'translation',
 
279
                        'bulk'         => true,
 
280
                        'translations' => $language_updates_results
 
281
                ) );
 
282
 
 
283
                // Re-add upgrade hooks.
 
284
                add_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
 
285
                add_action( 'upgrader_process_complete', 'wp_version_check' );
 
286
                add_action( 'upgrader_process_complete', 'wp_update_plugins' );
 
287
                add_action( 'upgrader_process_complete', 'wp_update_themes' );
 
288
 
 
289
                $this->skin->bulk_footer();
 
290
 
 
291
                $this->skin->footer();
 
292
 
 
293
                // Clean up our hooks, in case something else does an upgrade on this connection.
 
294
                remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) );
 
295
 
 
296
                if ( $parsed_args['clear_update_cache'] ) {
 
297
                        wp_clean_update_cache();
 
298
                }
 
299
 
 
300
                return $results;
 
301
        }
 
302
 
 
303
        /**
 
304
         * Check the package source to make sure there are .mo and .po files.
 
305
         *
 
306
         * Hooked to the {@see 'upgrader_source_selection'} filter by
 
307
         * Language_Pack_Upgrader::bulk_upgrade().
 
308
         *
 
309
         * @since 3.7.0
 
310
         * @access public
 
311
         *
 
312
         * @global WP_Filesystem_Base $wp_filesystem Subclass
 
313
         *
 
314
         * @param string|WP_Error $source
 
315
         * @param string          $remote_source
 
316
         */
 
317
        public function check_package( $source, $remote_source ) {
 
318
                global $wp_filesystem;
 
319
 
 
320
                if ( is_wp_error( $source ) )
 
321
                        return $source;
 
322
 
 
323
                // Check that the folder contains a valid language.
 
324
                $files = $wp_filesystem->dirlist( $remote_source );
 
325
 
 
326
                // Check to see if a .po and .mo exist in the folder.
 
327
                $po = $mo = false;
 
328
                foreach ( (array) $files as $file => $filedata ) {
 
329
                        if ( '.po' == substr( $file, -3 ) )
 
330
                                $po = true;
 
331
                        elseif ( '.mo' == substr( $file, -3 ) )
 
332
                                $mo = true;
 
333
                }
 
334
 
 
335
                if ( ! $mo || ! $po ) {
 
336
                        return new WP_Error( 'incompatible_archive_pomo', $this->strings['incompatible_archive'],
 
337
                                /* translators: 1: .po 2: .mo */
 
338
                                sprintf( __( 'The language pack is missing either the %1$s or %2$s files.' ),
 
339
                                        '<code>.po</code>',
 
340
                                        '<code>.mo</code>'
 
341
                                )
 
342
                        );
 
343
                }
 
344
 
 
345
                return $source;
 
346
        }
 
347
 
 
348
        /**
 
349
         * Get the name of an item being updated.
 
350
         *
 
351
         * @since 3.7.0
 
352
         * @access public
 
353
         *
 
354
         * @param object $update The data for an update.
 
355
         * @return string The name of the item being updated.
 
356
         */
 
357
        public function get_name_for_update( $update ) {
 
358
                switch ( $update->type ) {
 
359
                        case 'core':
 
360
                                return 'WordPress'; // Not translated
 
361
 
 
362
                        case 'theme':
 
363
                                $theme = wp_get_theme( $update->slug );
 
364
                                if ( $theme->exists() )
 
365
                                        return $theme->Get( 'Name' );
 
366
                                break;
 
367
                        case 'plugin':
 
368
                                $plugin_data = get_plugins( '/' . $update->slug );
 
369
                                $plugin_data = reset( $plugin_data );
 
370
                                if ( $plugin_data )
 
371
                                        return $plugin_data['Name'];
 
372
                                break;
 
373
                }
 
374
                return '';
 
375
        }
 
376
 
 
377
}