[wp-trac] [WordPress Trac] #64249: Automatic translation (JIT) loading doesn't work for network-activated plugins in multisite
WordPress Trac
noreply at wordpress.org
Fri Mar 13 06:12:56 UTC 2026
#64249: Automatic translation (JIT) loading doesn't work for network-activated
plugins in multisite
--------------------------+------------------------
Reporter: pelentak | Owner: (none)
Type: defect (bug) | Status: new
Priority: normal | Milestone: 7.1
Component: I18N | Version: 6.7
Severity: normal | Resolution:
Keywords: needs-patch | Focuses: multisite
--------------------------+------------------------
Comment (by sanket.parmar):
I've reviewed the issue and can confirm the root cause.
In `wp-settings.php`, the JIT translation registration introduced in
[59461] only runs for site-level active plugins. The network-activated
plugins loop (which runs earlier in the bootstrap) does not register text
domains with `$wp_textdomain_registry`, so the JIT mechanism
(`_load_textdomain_just_in_time()`) has no path to resolve translations
for those plugins.
The fix requires two related changes in `wp-settings.php`:
=== 1. Move the `plugin.php` include earlier ===
Currently, `get_plugin_data()` is made available ''after'' the network
plugins loop via:
{{{
// To make get_plugin_data() available in a way that's compatible with
plugins also loading this file, see #62244.
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}}}
This line needs to be moved to just ''before'' the `if ( is_multisite() )`
network plugins block, so that `get_plugin_data()` is available when
processing network plugins.
=== 2. Add text domain registration to the network plugins loop ===
Mirror the same registration logic already present in the site plugins
loop:
{{{
#!php
// Load network activated plugins.
if ( is_multisite() ) {
foreach ( wp_get_active_network_plugins() as $network_plugin ) {
wp_register_plugin_realpath( $network_plugin );
$plugin_data = get_plugin_data( $network_plugin, false, false );
$textdomain = $plugin_data['TextDomain'];
if ( $textdomain ) {
if ( $plugin_data['DomainPath'] ) {
$GLOBALS['wp_textdomain_registry']->set_custom_path(
$textdomain,
dirname( $network_plugin ) .
$plugin_data['DomainPath']
);
} else {
$GLOBALS['wp_textdomain_registry']->set_custom_path(
$textdomain,
dirname( $network_plugin )
);
}
}
$_wp_plugin_file = $network_plugin;
include_once $network_plugin;
$network_plugin = $_wp_plugin_file;
do_action( 'network_plugin_loaded', $network_plugin );
}
unset( $network_plugin, $_wp_plugin_file, $plugin_data, $textdomain );
}
}}}
=== Notes on safety ===
* Moving the `require_once` earlier is low risk — `plugin.php` was
already made safe for early loading as part of #62244.
* `get_plugin_data()` only reads the plugin file's comment header; it
makes no database calls and has no side effects.
* `set_custom_path()` is idempotent, so plugins that currently call
`load_plugin_textdomain()` explicitly as a workaround will continue to
work correctly — the registry entry will simply be set twice with the same
value.
* JavaScript translations are unaffected (they already work, as noted in
the ticket).
I'm happy to prepare a patch if this approach is agreeable.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/64249#comment:4>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list