Send Email Notification given the language in which the order was placed

I am working on sending email notifications in the language in which the order was placed, using Polylang. Currently, my email notifications are sent in the language of the user who triggered these emails (e.g. admin, shop manager). I have written the code below, and I am confident that the functions map_language_to_locale() and get_locale_from_order_id() work correctly. The issue seems to be with this part of the set_email_locale_based_on_order() function: $order_id = $email->object->id;. When I run the set_email_locale_based_on_order() function with $locale = 'pt_BR';, the email notification is correctly sent in the language in which the order was placed. Anyone knows how to solve this? <?php add_filter($hook_name = 'woocommerce_allow_switching_email_locale', $callback = 'set_email_locale_based_on_order', $priority = 10, $accepted_args = 2); add_action($hook_name = 'woocommerce_email_footer', $callback = 'restore_email_locale', $priority = 10, $accepted_args = 1); function map_language_to_locale($language_slug) { // Define a mapping of language slugs to locale codes $mapping = array( 'de' => 'de_DE', 'en' => 'en_US', 'pt' => 'pt_BR', ); return isset($mapping[$language_slug]) ? $mapping[$language_slug] : false; } function get_locale_from_order_id($order_id) { if (function_exists('pll_get_post_language')) { $order_language = pll_get_post_language($order_id, 'slug'); return map_language_to_locale($order_language); } return null; } function set_email_locale_based_on_order($email_locale, $email) { // error_log('Email Object: ' . print_r($email, true)); $order_id = $email->object->id; // Get the order ID from the email object $locale = get_locale_from_order_id($order_id); // $locale = 'pt_BR'; // If I run this, it works switch_to_locale($locale); // Log the locale switch error_log("Switched to locale: " . $locale); // Filter on plugin_locale so load_plugin_textdomain loads the correct locale. add_filter($hook_name = 'plugin_locale', $callback = fn () => $locale); return $email_locale; } function restore_email_locale() { restore_previous_locale(); }

Comment (2)

Jese Leos

September 20, 2024

Verified user

There are some modifications needs to be made in order to make sure we are properly handling the email object to get the order ID. Also ensure the locale switching and restoring are correctly handled. We need to add debugging logs to identify where the issue might be. <?php add_filter( 'woocommerce_allow_switching_email_locale', 'set_email_locale_based_on_order', 10, 2 ); add_action( 'woocommerce_email_footer', 'restore_email_locale' ); function map_language_to_locale( $language_slug ) { // Here we have defined a mapping of language slugs to locale codes. $mapping = array( 'de' => 'de_DE', 'en' => 'en_US', 'pt' => 'pt_BR', ); return isset($mapping[$language_slug]) ? $mapping[$language_slug] : false; } function get_locale_from_order_id( $order_id ) { if ( function_exists( 'pll_get_post_language' ) ) { $order_language = pll_get_post_language($order_id, 'slug'); return map_language_to_locale( $order_language ); } return null; } function set_email_locale_based_on_order( $email_locale, $email ) { // This is to ensure the email object is of type WC_Order. if ( isset( $email->object ) && is_a( $email->object, 'WC_Order' ) ) { $order_id = $email->object->get_id(); // We need to use get_id() method to get the order ID. $locale = get_locale_from_order_id( $order_id ); // Add error logging for debugging error_log( 'Order ID: ' . $order_id ); // This is to Log the order ID. error_log( 'Locale: ' . $locale ); // This is to Log the locale. if ( $locale ) { global $current_locale; $current_locale = get_locale(); // Here we are saving the current locale. switch_to_locale( $locale ); // Here we are switching to the order's locale. // This is to Log the locale switch. error_log( 'Switched to locale: ' . $locale ); // Here we are using filter on plugin_locale so load_plugin_textdomain loads the correct locale. add_filter( 'plugin_locale', fn() => $locale ); } } return $email_locale; } function restore_email_locale() { global $current_locale; if ( isset( $current_locale ) ) { switch_to_locale( $current_locale ); // Restore the original locale } }

Jese Leos

September 20, 2024

Verified user

I was able to solve this issue. I have also included emails for shipping and invoice for the "Germanized for WooCommerce" plugin. if (class_exists('WooCommerce') && WC() && class_exists('Polylang')) { class WC_Email_Locale_Handler { public function __construct() { // Hook into the email header to switch locale before email content add_action($hook_name = 'woocommerce_email_header', $callback = [$this, 'set_email_locale_based_on_order'], $priority = 10, $accepted_args = 2); add_action($hook_name = 'woocommerce_email_before_order_table', $callback = [$this, 'set_email_locale_based_on_order'], $priority = 10, $accepted_args = 2); // Hook into the email footer to restore the original locale after email content add_action($hook_name = 'woocommerce_email_footer', $callback = [$this, 'restore_email_locale'], $priority = 10, $accepted_args = 1); // Hook into resending emails to handle locale switching add_action($hook_name = 'woocommerce_before_resend_order_emails', $callback = [$this, 'set_locale_on_woocommerce_before_resend_order_emails'], $priority = 10, $accepted_args = 1); // Hook into email recipient filter to switch locale before generating the subject add_filter($hook_name = 'woocommerce_email_recipient_new_order', $callback = [$this, 'set_locale_on_woocommerce_email_recipient_new_order'], $priority = 10, $accepted_args = 2); } public function set_email_locale_based_on_order($email_heading, $email) { if (isset($email->object)) { // Get the language locale of the order $order_locale = $this->get_locale_from_object($email->object); if ($order_locale) { // Switch to the order's locale switch_to_locale($order_locale); } } } public function restore_email_locale() { restore_previous_locale(); } public function set_locale_on_woocommerce_before_resend_order_emails($order) { if ($order) { // Get the language locale of the order $order_locale = $this->get_locale_from_object($order); if ($order_locale) { // Switch to the order's locale switch_to_locale($order_locale); } } } public function set_locale_on_woocommerce_email_recipient_new_order($to, $order) { // Get the order locale $order_locale = $this->get_locale_from_object($order); if ($order_locale) { // Switch to the order's locale before generating the subject switch_to_locale($order_locale); } return $to; } private function map_language_to_locale($language_slug) { // Define a mapping of language slugs to locale codes $mapping = array( 'de' => 'de_DE', 'en' => 'en_US', 'pt' => 'pt_BR', ); return isset($mapping[$language_slug]) ? $mapping[$language_slug] : false; } private function get_locale_from_object($object) { $order = null; // Check if the object is a WC_Order or if the object is a Shipment/Invoice from "Germanized for WooCommerce" plugin if (is_a($object, 'WC_Order')) { $order = $object; } elseif (is_a($object, 'Vendidero\Germanized\Shipments\Shipment') || is_a($object, 'Vendidero\StoreaBill\Invoice\Invoice')) { $order = $object->get_order(); } if ($order && function_exists('pll_get_post_language')) { // Get the language slug of the order $order_language = pll_get_post_language($order->get_id(), 'slug'); // Map the language slug to a locale code return $this->map_language_to_locale($order_language); } return null; } } // Initialize the handler class new WC_Email_Locale_Handler(); }

You’ll be in good company