home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-admin / includes / class-language-pack-upgrader.php < prev    next >
Encoding:
PHP Script  |  2017-10-18  |  10.8 KB  |  371 lines

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