skip to Main Content

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();
}

2

Answers


  1. Chosen as BEST ANSWER

    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, 'VendideroGermanizedShipmentsShipment') || is_a($object, 'VendideroStoreaBillInvoiceInvoice')) {
                    $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();
    }
    

  2. 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
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search