Quick multi-lingual messages for WordPress/WooCommerce

Often you want to manage some customer alerts and keep them up to date and consistent across different languages and pages, for example:

  • This month’s special offer
  • December shipping note
  • Country-specific note:  note to customers from France, airport strike may affect deliveries… etc

Each of these types of note may appear on multiple pages, and with a manual update it is easy to miss a page out or forget to update the translation.

Polylang (and WPML) language tools have a string translation table that allows the site manager to review and update a whole group of strings at the same time.

So, why not add a group of strings to this table and use the existing APIs for a convenient implementation.

As it turns out this is really easy with Polylang.

Register the strings:

To add strings to the table all you need to do is this:

pll_register_string('saleflash', 'saleflash', 'Polylang User Alerts', TRUE);
pll_register_string('shippingnotice', 'shippingnotice', 'Polylang User Alerts', TRUE);

Define a shortcode

A shortcode is a piece of text that can be inserted into html when editing a page.  When the page is rendered, the contents are replaced by the results of a function.

Our simple shortcode might look like this:

[user_alert name="saleflash"]

To register it, we just need to map the user_alert shortcode to a function like this:

 add_shortcode('user_alert', 'user_alert');

And actually define the function, which takes an array of attributes which are the attributes provided on the page – in this example it will be (‘name’ => ‘saleflash’).

The minimum implementation would be:

function user_alert($atts = array()){
  return pll__($a['name']);

the pll__() function works like the standard __() function. Both detect the current language and attempt to find the language version of the requested string, __() looks in the compiled translation files and should be used for strings set at design time, pll__() looks in the string translation table and can be used for admin settings etc.

Within any wordpress code:

  • all string literals in source code should be wrapped in __(‘my string’, $myTextDomain)
  • all settings strings which can be changed by the site manager eg in the admin GUI should be wrapped in pll__($myString).

That code example is a bit too simple, let’s make it a little bit more elaborate.
Unfortunately the latest WordPress editor ‘improvements’ seem to make it impossible to correctly post code so let’s try a gist:

function user_alert($atts = array()){
$a = shortcode_atts( array(
'name' => 'saleflash',
), $atts );
$translation = pll__($a['name']);
/* don't output visible message if no translation available */
if ($translation == '' || $translation == $a['name']){
//on non-production environments script debug should be enabled
if (defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ){
$output = '<!– shortcode user-alert : no translation available for ' .
$a['name'] . ' –>';
} else {
$output = '<div class="user-alert ' . $a['name'] . '">' .
wpautop($translation) . '</div>';
return $output;

view raw


hosted with ❤ by GitHub

here we’ve added:

  • use standard function to check parameters and set default value for name if not provided
  • check if a translation has actually been set, otherwise return an html comment..
  • return the message in a div, with classes attached for convenient formatting – for example if you wanted to make the sale flash bold and red, you would add to your theme css: div.user-alert.saleflash{font-weight:bold;color:red;}
  • wpautop() is used for formatting the text, this is the standard function used also for WordPress posts (but not applied automatically to shortcodes).  As the string translation table doesn’t have a rich text editor, wpautop helps us preserve line breaks etc in the message without needing to type html.

So to get this working all we have to do is add a saleflash message in Admin, Languages, Strings translation:


Now we can add [user_alert] or [user_alert name=”saleflash”] on all pages where this message should appear.

Add messages to WooCommerce

Of course it is even easier if we don’t have to add the shortcode to different pages, instead we can programmatically add special messages where they are needed using wordpress filters or action hooks.

This example adds a row with a message to the shipping calculator section of WooCommerce, on both the cart page and the checkout page.

First we will need the code to output the row.  Here we’re using the user_alert shortcode function to get our text (in its div) and then returning it wrapped in a row:

function shippingalert(){
  $output = self::user_alert(array('name' => 'shippingnotice'));

So now this just needs to be hooked in the correct places – this will do it:

add_action( 'woocommerce_cart_totals_after_shipping', 'shippingalert', 60 );
add_action( 'woocommerce_review_order_after_shipping', shippingalert' , 60);

Then after setting the alert text we might get something like this:


In this case the alert message is added between the Shipping and Total, as if it were a native feature, it looks exactly the same on the Cart and Checkout pages and we have a screen to easily review and ensure consistent translation in all languages.

Wrapping it up

Most online examples point out that you can add this code to the functions.php file in your theme.

Adding a few functions to your theme php is the quickest way to get started but is also the wrong way.   As time grows the functions file gets complex and you have a whole bunch of functionality in what should simply be a set of design files.

You can avoid this by simply moving the code into a ‘plugin’.  A plugin can be a simple single code file if no settings are required, but a small amount of boilerplate code is recommended for startup, shutdown, dependency checks, settings.

If we move this into a separate plugin we get:

  • ability to turn on and off the plugin individually to test the effect of the code
  • independent component-level releases (which can be independently tested) and rollbacks
  • ability to profile the plugin independently (with tools like Query Monitor)
  • Easy to switch theme, eg for A/B testing etc:  if your functionality is separate from your theme you can easily switch to a completely different theme to test different visual layouts without breaking your functionality.

Depending on your needs you might have one or more inhouse plugins to wrap all your customisations or you might group by functionality and release on github and or wordpress plugin repository.  Please refer to the wordpress plugin guidelines for this, it will be easier to start off compliant from the beginning.

The plugin version of this code can be found at:


Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s