Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 

378 рядки
11 KiB

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