Fix: Uncanny Automator Translation Error On WordPress 6.7+
Hey everyone! Are you seeing a weird error after updating to WordPress 6.7 when using Uncanny Automator? You're not alone! Let's dive into this issue and figure out how to fix it.
The Problem: _load_textdomain_just_in_time Called Too Early
Since updating to WordPress 6.7, a doing_it_wrong notice pops up whenever Uncanny Automator loads integrations that use translation functions like __(), _x(), and esc_attr_x() before the init hook. This can be quite annoying, but don't worry; we'll get it sorted.
Here’s the full notice you might be seeing:
Function _load_textdomain_just_in_time was called incorrectly.
Translation loading for the "uncanny-automator" domain was triggered too early.
This is usually an indicator for some code in the plugin or theme running too early.
Translations should be loaded at the init action or later.
This message was added in version 6.7.0.
And here’s an example of the stack trace:
[internal] trigger_error
wp-includes/functions.php:6121 wp_trigger_error
wp-includes/functions.php:6061 _doing_it_wrong
wp-includes/l10n.php:1379 _load_textdomain_just_in_time
wp-includes/l10n.php:1409 get_translations_for_domain
wp-includes/l10n.php:262 translate_with_gettext_context
wp-includes/l10n.php:442 esc_attr_x
wp-content/plugins/uncanny-automator/src/integrations/campaign-monitor/actions/campaign-monitor-add-update-subscriber.php:58
Uncanny_Automator\Integrations\Campaign_Monitor\CAMPAIGN_MONITOR_ADD_UPDATE_SUBSCRIBER::setup_action
How to Reproduce the Issue
- Make sure you're on WordPress 6.7.0 or later.
- Activate Uncanny Automator and any integration that uses translations (like the Campaign Monitor integration).
- Load any frontend or admin page that kicks off Automator initialization.
- Check your logs or enable
WP_DEBUGto see the User Notice.
What’s Supposed to Happen?
The translations for the uncanny-automator text domain should load after the init hook. This prevents _load_textdomain_just_in_time from being called too early. It’s all about timing, guys!
Why This Happens
The _load_textdomain_just_in_time function is a mechanism in WordPress to load translations on demand. It's designed to improve performance by only loading translation files when they're actually needed. However, in WordPress 6.7, stricter checks were introduced to ensure that translations are loaded at the right time – specifically, after the init action. When a plugin or theme attempts to use translation functions like __(), _x(), or esc_attr_x() too early, WordPress triggers the doing_it_wrong notice to alert developers to the issue.
The primary reason this happens is that some plugins or themes might be calling these translation functions within constructors or static properties that execute before the init hook. This is problematic because the translation files haven't been loaded yet, leading to the just-in-time loading mechanism being triggered prematurely. The init hook is the recommended place to load translation files because it ensures that all necessary WordPress components are fully initialized.
To avoid this issue, developers need to ensure that translation calls are made only after the init hook has fired. This can be achieved by moving translation calls out of constructors or static properties that execute early, or by explicitly loading the plugin's text domain on the init action. By doing so, the translation files are guaranteed to be loaded before any translation functions are called, preventing the _load_textdomain_just_in_time function from being triggered too early and resolving the doing_it_wrong notice.
The Solution: Fixing the Translation Loading
To fix this, you have a couple of options. The main goal is to make sure translations are loaded at or after the init hook.
Option 1: Move Translation Calls
Move any translation calls (__(), _x(), esc_attr_x(), etc.) out of constructors or static properties that run before init. This might involve refactoring your code a bit to delay those calls until the appropriate time.
Option 2: Explicitly Load the Text Domain
Make sure load_plugin_textdomain( 'uncanny-automator', false, 'uncanny-automator/languages' ) runs on init before any translated strings are accessed. Here’s how you can do it:
add_action( 'init', function() {
load_plugin_textdomain( 'uncanny-automator', false, 'uncanny-automator/languages' );
});
This code snippet adds an action to the init hook that loads the text domain for Uncanny Automator. By doing this, you ensure that the translation files are loaded before any translated strings are used, which should prevent the error.
A Deeper Dive into the Suggested Fix
Let's break down why the suggested fix works and how it addresses the root cause of the issue. The core problem is that WordPress 6.7 introduced stricter checks to ensure translations are loaded at the correct time, specifically after the init hook. When a plugin attempts to use translation functions before the translation files are loaded, WordPress triggers the _load_textdomain_just_in_time function, which is meant to load the translations on demand. However, if this happens too early, it results in a doing_it_wrong notice.
The suggested fix involves explicitly loading the plugin's text domain on the init action. This is achieved using the load_plugin_textdomain function, which tells WordPress to load the translation files for the specified text domain. By hooking this function to the init action, you ensure that the translation files are loaded before any translation functions are called within the plugin.
Here's a more detailed explanation of the code snippet:
add_action( 'init', function() {
load_plugin_textdomain( 'uncanny-automator', false, 'uncanny-automator/languages' );
});
add_action( 'init', function() { ... });: This line adds a function to theinitaction hook. Theinithook is triggered by WordPress after it has finished loading the core files and after the theme'sfunctions.phpfile is loaded. This is the recommended place to load translation files because it ensures that all necessary WordPress components are fully initialized.load_plugin_textdomain( 'uncanny-automator', false, 'uncanny-automator/languages' );: This function loads the translation files for theuncanny-automatortext domain. Let's break down the parameters:'uncanny-automator': This is the text domain for which the translation files should be loaded. The text domain is a unique identifier for the plugin's translations.false: This parameter specifies whether to load the text domain in a child theme. Setting it tofalsemeans that the translations will be loaded from the plugin's directory, regardless of whether a child theme is active.'uncanny-automator/languages': This is the relative path to the directory containing the translation files. In this case, it specifies that the translation files are located in thelanguagesdirectory within theuncanny-automatorplugin directory.
By explicitly loading the text domain on the init action, you ensure that the translation files are loaded before any translation functions are called within the plugin. This prevents the _load_textdomain_just_in_time function from being triggered too early and resolves the doing_it_wrong notice. It's a simple yet effective way to address the translation loading issue in WordPress 6.7 and ensure that your plugin's translations are loaded correctly.
Environment Details
- WordPress: 6.7.0
- PHP: 8.2
- Plugin: Uncanny Automator (latest at the time of report)
- Integration: Campaign Monitor
- Site: (example site)
Example Mitigation in Detail
To provide a clearer picture, let's consider a practical example of how this mitigation can be applied within the Uncanny Automator plugin. Suppose you have a file named campaign-monitor-add-update-subscriber.php located in the src/integrations/campaign-monitor/actions/ directory of the plugin. This file contains a class called CAMPAIGN_MONITOR_ADD_UPDATE_SUBSCRIBER that defines an action to add or update a subscriber in Campaign Monitor.
Within this class, you might have code that uses translation functions like esc_attr_x to translate strings. If these translation calls are made within the class constructor or a static property that executes before the init hook, it can trigger the _load_textdomain_just_in_time error.
To mitigate this issue, you can modify the class to ensure that the translation calls are made after the init hook has fired. One way to achieve this is by moving the translation calls into a method that is called after the init hook. For example, you can create a method called setup_action that contains the translation calls and then hook this method to the init action.
Here's an example of how you can modify the campaign-monitor-add-update-subscriber.php file:
namespace Uncanny_Automator\Integrations\Campaign_Monitor;
class CAMPAIGN_MONITOR_ADD_UPDATE_SUBSCRIBER {
public function __construct() {
// Remove translation calls from the constructor
add_action( 'init', array( $this, 'setup_action' ) );
}
public function setup_action() {
// Move translation calls into this method
$this->action_title = esc_attr_x( 'Add/Update Subscriber in Campaign Monitor', 'Campaign Monitor', 'uncanny-automator' );
$this->action_label = esc_attr_x( 'Add/Update Subscriber', 'Campaign Monitor', 'uncanny-automator' );
// ... other code ...
}
// ... other methods ...
}
In this example, the __construct method is modified to remove the translation calls and instead add an action to the init hook that calls the setup_action method. The setup_action method then contains the translation calls that were previously in the constructor. By doing this, you ensure that the translation calls are made after the init hook has fired, preventing the _load_textdomain_just_in_time error.
Additionally, you need to ensure that the load_plugin_textdomain function is called on the init action as well. This ensures that the translation files are loaded before any translation functions are called within the plugin.
By combining these two steps, you can effectively mitigate the translation loading issue in Uncanny Automator and ensure that your plugin's translations are loaded correctly in WordPress 6.7 and later versions.
Wrapping Up
So, if you're seeing that _load_textdomain_just_in_time warning, don't panic! Just make sure your translations are loading at the right time (on or after the init hook), and you should be good to go. Happy automating!