Make WordPress Core


Ignore:
Timestamp:
01/15/2024 07:03:27 PM (3 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.