Language_Pack_Upgrader

Core class used for updating/installing language packs (translations) for plugins, themes, and core.

Defined (1)

The class is defined in the following location(s).

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