Make WordPress Core


Ignore:
Timestamp:
01/15/2024 07:03:27 PM (2 years ago)
Author:
swissspidy
Message:

I18N: Cache list of language file paths in WP_Textdomain_Registry.

Loading a list of language file paths using glob() can be expensive if involving thousands of files.

Expands scope of WP_Textdomain_Registry to cache list of language file paths in object cache and provides a way to invalidate that cache upon translation updates. Plugins can clear the cache using calls such as wp_cache_delete( 'cached_mo_files_' . md5( $path ), 'translations' );

Props mreishus, swissspidy
Fixes #58919

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-textdomain-registry.php

    r56178 r57287  
    5252     *
    5353     * @since 6.1.0
     54     * @since 6.5.0 This property is no longer used.
    5455     *
    5556     * @var array
     57     *
     58     * @deprecated
    5659     */
    5760    protected $cached_mo_files = array();
     
    6568     */
    6669    protected $domains_with_translations = array();
     70
     71    /**
     72     * Initializes the registry.
     73     *
     74     * Hooks into the {@see 'upgrader_process_complete'} filter
     75     * to invalidate MO files caches.
     76     *
     77     * @since 6.5.0
     78     */
     79    public function init() {
     80        add_action( 'upgrader_process_complete', array( $this, 'invalidate_mo_files_cache' ), 10, 2 );
     81    }
    6782
    6883    /**
     
    136151
    137152    /**
     153     * Retrieves .mo files from the specified path.
     154     *
     155     * Allows early retrieval through the {@see 'pre_get_mo_files_from_path'} filter to optimize
     156     * performance, especially in directories with many files.
     157     *
     158     * @since 6.5.0
     159     *
     160     * @param string $path The directory path to search for .mo files.
     161     * @return array Array of .mo file paths.
     162     */
     163    public function get_language_files_from_path( $path ) {
     164        $path = trailingslashit( $path );
     165
     166        /**
     167         * Filters the .mo files retrieved from a specified path before the actual lookup.
     168         *
     169         * Returning a non-null value from the filter will effectively short-circuit
     170         * the MO files lookup, returning that value instead.
     171         *
     172         * This can be useful in situations where the directory contains a large number of files
     173         * and the default glob() function becomes expensive in terms of performance.
     174         *
     175         * @since 6.5.0
     176         *
     177         * @param null|array $mo_files List of .mo files. Default null.
     178         * @param string $path The path from which .mo files are being fetched.
     179         **/
     180        $mo_files = apply_filters( 'pre_get_language_files_from_path', null, $path );
     181
     182        if ( null !== $mo_files ) {
     183            return $mo_files;
     184        }
     185
     186        $cache_key = 'cached_mo_files_' . md5( $path );
     187        $mo_files  = wp_cache_get( $cache_key, 'translations' );
     188
     189        if ( false === $mo_files ) {
     190            $mo_files = glob( $path . '*.mo' );
     191            if ( false === $mo_files ) {
     192                $mo_files = array();
     193            }
     194            wp_cache_set( $cache_key, $mo_files, 'translations' );
     195        }
     196
     197        return $mo_files;
     198    }
     199
     200    /**
     201     * Invalidate the cache for .mo files.
     202     *
     203     * This function deletes the cache entries related to .mo files when triggered
     204     * by specific actions, such as the completion of an upgrade process.
     205     *
     206     * @since 6.5.0
     207     *
     208     * @param WP_Upgrader $upgrader   Unused. WP_Upgrader instance. In other contexts this might be a
     209     *                                Theme_Upgrader, Plugin_Upgrader, Core_Upgrade, or Language_Pack_Upgrader instance.
     210     * @param array       $hook_extra {
     211     *     Array of bulk item update data.
     212     *
     213     *     @type string $action       Type of action. Default 'update'.
     214     *     @type string $type         Type of update process. Accepts 'plugin', 'theme', 'translation', or 'core'.
     215     *     @type bool   $bulk         Whether the update process is a bulk update. Default true.
     216     *     @type array  $plugins      Array of the basename paths of the plugins' main files.
     217     *     @type array  $themes       The theme slugs.
     218     *     @type array  $translations {
     219     *         Array of translations update data.
     220     *
     221     *         @type string $language The locale the translation is for.
     222     *         @type string $type     Type of translation. Accepts 'plugin', 'theme', or 'core'.
     223     *         @type string $slug     Text domain the translation is for. The slug of a theme/plugin or
     224     *                                'default' for core translations.
     225     *         @type string $version  The version of a theme, plugin, or core.
     226     *     }
     227     * }
     228     * @return void
     229     */
     230    public function invalidate_mo_files_cache( $upgrader, $hook_extra ) {
     231        if ( 'translation' !== $hook_extra['type'] || array() === $hook_extra['translations'] ) {
     232            return;
     233        }
     234
     235        $translation_types = array_unique( wp_list_pluck( $hook_extra['translations'], 'type' ) );
     236
     237        foreach ( $translation_types as $type ) {
     238            switch ( $type ) {
     239                case 'plugin':
     240                    wp_cache_delete( 'cached_mo_files_' . md5( trailingslashit( WP_LANG_DIR ) . '/plugins/' ), 'translations' );
     241                    break;
     242                case 'theme':
     243                    wp_cache_delete( 'cached_mo_files_' . md5( trailingslashit( WP_LANG_DIR ) . '/themes/' ), 'translations' );
     244                    break;
     245                default:
     246                    wp_cache_delete( 'cached_mo_files_' . md5( trailingslashit( WP_LANG_DIR ) ), 'translations' );
     247                    break;
     248            }
     249        }
     250    }
     251
     252    /**
    138253     * Returns possible language directory paths for a given text domain.
    139254     *
     
    157272
    158273    /**
    159      * Gets the path to the language directory for the current locale.
     274     * Gets the path to the language directory for the current domain and locale.
    160275     *
    161276     * Checks the plugins and themes language directories as well as any
     
    176291
    177292        foreach ( $locations as $location ) {
    178             if ( ! isset( $this->cached_mo_files[ $location ] ) ) {
    179                 $this->set_cached_mo_files( $location );
    180             }
     293            $files = $this->get_language_files_from_path( $location );
    181294
    182295            $path = "$location/$domain-$locale.mo";
    183296
    184             foreach ( $this->cached_mo_files[ $location ] as $mo_path ) {
     297            foreach ( $files as $mo_path ) {
    185298                if (
    186299                    ! in_array( $domain, $this->domains_with_translations, true ) &&
     
    216329        return false;
    217330    }
    218 
    219     /**
    220      * Reads and caches all available MO files from a given directory.
    221      *
    222      * @since 6.1.0
    223      *
    224      * @param string $path Language directory path.
    225      */
    226     private function set_cached_mo_files( $path ) {
    227         $this->cached_mo_files[ $path ] = array();
    228 
    229         $mo_files = glob( $path . '/*.mo' );
    230 
    231         if ( $mo_files ) {
    232             $this->cached_mo_files[ $path ] = $mo_files;
    233         }
    234     }
    235331}
Note: See TracChangeset for help on using the changeset viewer.