- Copy content from the original post using Polylang in its free version
- Show the total number of posts translated with Polylang in each language
- Add native Polylang banners to any page or post
- Adding an SVG icon next to the language selector
- Show customisable warning of the existence of a foreign language version

Although there are different opinions about which is the best plugin to create a multilingual blog, and all of them have evolved a lot since their first versions simplifying and facilitating the task, one of the most used is Polylang.
With more than 700,000 active installations to date, it remains one of the lightest and most effective options.
Here is a small list of snippets with functions and filters that might be useful at some point. All of them work for the free version of Polylang and have been tested and/or used here.
Copy content from the original post using Polylang in its free version
If you use the free version of the Polylang plugin for WordPress, you already know that the new page or post it generates for translation does not copy the original content. This is one of the features of its paid version and in the free version you have to paste the content by hand.
To solve this and speed up the process, just add these functions in the functions.php file of your template. Now, when you add a new translation it will open with the original copied content (title and content).
// Copying content when creating a translation with Polylang
function jb_editor_content( $content ) {
// Polylang sets the 'from_post' parameter
if ( isset( $_GET['from_post'] ) ) {
$my_post = get_post( $_GET['from_post'] );
if ( $my_post )
return $my_post->post_content;
}
return $content;
}
add_filter( 'default_content', 'jb_editor_content' );
// Copy title when creating a translation with Polylang
function jb_editor_title( $title ) {
// Polylang sets the 'from_post' parameter
if ( isset( $_GET['from_post'] ) ) {
$my_post = get_post( $_GET['from_post'] );
if ( $my_post )
return $my_post->post_title;
}
return $title;
}
add_filter( 'default_title', 'jb_editor_title' );
*Thissnippet was found in a note from December 2020. Although it still works, it wouldn't hurt to keep an eye on it in case, with time and future Polylang updates, it fails.
Show the total number of posts translated with Polylang in each language
This function allows you to add a shortcode for each language that will show the total number of posts published in a language in which there are translations added with the Polylang plugin.
This function is more than tested and working properly on my statistics page and is useful for maintaining a list of counters that are automatically updated.
The snippet is added to the template's functions.php:
// Function to display number of published posts by language for Polylang
function polylang_post_count_by_language($atts) {
// Atributos del shortcode
$atts = shortcode_atts(array(
'lang' => '', // Código de idioma (ej: 'es', 'en', etc.)
), $atts, 'post_count_by_lang');
// Check if Polylang is active
if (!function_exists('pll_languages_list')) {
return 'Polylang plugin is not active.';
}
// Get the language code
$lang = $atts['lang'];
if (empty($lang)) {
return 'Language code is required.';
}
// Single key for transient
$transient_key = 'post_count_by_lang_' . $lang;
// Trying to get the count from the cache
$post_count = get_transient($transient_key);
// If there is no cache, perform the query
if (false === $post_count) {
// Configure the query to count posts by language
$args = array(
'lang' => $lang,
'post_type' => 'post', // Type of post (you can change it if necessary)
'post_status' => 'publish', // Only published posts
'fields' => 'ids', // Only obtain IDs to reduce the burden
'numberposts' => -1, // All posts
);
// Make an enquiry
$query = new WP_Query($args);
// Get the total number of posts
$post_count = $query->found_posts;
// Cache for 12 hours (43200 seconds)
set_transient($transient_key, $post_count, 43200);
}
// Return the number of posts
return $post_count;
}
add_shortcode('post_count_by_lang', 'polylang_post_count_by_language');
One of the problems we face here is that if you have a lot of posts in many different languages on your site, as is the case with this blog, the impact of the database query could slow down the loading speed. The code takes this into account and the query is optimised using WP_Query with fields => 'ids' to reduce memory overhead by not loading whole post objects.
The post count is stored using set_transient and avoids repetitive database queries. In the example, the cache is updated every 12 hours, expressed in seconds (you can adjust this time according to your needs).
To optimise the query, WP_Query is used instead of get_posts to access found_posts, which returns the total number of posts without the need to load all objects.
The fields => 'ids' parameter reduces the memory load by retrieving only the post IDs.
If at some point you need to clear the cache manually (e.g. after publishing a new post) so that it does not show stale data you can use:
delete_transient('post_count_by_lang_' . $lang);
If you prefer to automate this process, the following function will delete the transient every time a post is published, updated or deleted. If you add it in the functions.php of your template, the hook will be activated for all these actions:
//Deleting the transient when publishing, updating or deleting a post
function clear_post_count_transient($post_id) {
// Check if the post is of type 'post' (or the type you are counting).
if (get_post_type($post_id) === 'post') {
// Get the language of the post using Polylang
if (function_exists('pll_get_post_language')) {
$lang = pll_get_post_language($post_id);
// If the language is obtained, delete the corresponding transient.
if ($lang) {
delete_transient('post_count_by_lang_' . $lang);
}
}
}
}
add_action('save_post', 'clear_post_count_transient'); // When publishing or updating
add_action('delete_post', 'clear_post_count_transient'); // By deleting
And this one clears the cache automatically according to a number of different possible scenarios(including the one above):
// Function to delete the transient when necessary
function clear_post_count_transient($post_id) {
if (get_post_type($post_id) === 'post') {
if (function_exists('pll_get_post_language')) {
$lang = pll_get_post_language($post_id);
if ($lang) {
delete_transient('post_count_by_lang_' . $lang);
}
}
}
}
add_action('save_post', 'clear_post_count_transient');
add_action('delete_post', 'clear_post_count_transient');
//Function to delete transient when changing the language of a post
function clear_post_count_transient_on_language_change($post_id, $lang) {
$old_lang = pll_get_post_language($post_id);
if ($old_lang) {
delete_transient('post_count_by_lang_' . $old_lang);
}
if ($lang) {
delete_transient('post_count_by_lang_' . $lang);
}
}
add_action('pll_save_post', 'clear_post_count_transient_on_language_change', 10, 2);
// Function to delete all transients when uninstalling or deactivating Polylang
function clear_all_post_count_transients() {
if (function_exists('pll_languages_list')) {
$languages = pll_languages_list();
foreach ($languages as $lang) {
delete_transient('post_count_by_lang_' . $lang);
}
}
}
register_deactivation_hook(__FILE__, 'clear_all_post_count_transients');
register_uninstall_hook(__FILE__, 'clear_all_post_count_transients');
The numbers are displayed using the shortcode for each language with its corresponding code wherever you want to display the number. It looks like this:
For Spanish: [post_count_by_lang lang="es"]
For English: [post_count_by_lang lang="en"]
For German: [post_count_by_lang lang="de"]
For French: [post_count_by_lang lang="fr"]
etc.
You can modify the 'post_type' in the code if you want to count other types of content (pages, custom post types, etc.).
In this URL you have an example of the shortcodes working.
Add native Polylang banners to any page or post
Since Polylang includes a collection of 249 16x11 flags in .png, we can use them to decorate lists, add them to tables, paragraphs, etc. without having to write HTML or CSS.
This function allows you to add the image of any native banner used by the plugin via a shortcode.
To make them available you add the snippet in the functions.php of your child theme, in a custom plugin or with Code Snippet, if you use it.
function polylang_flag_shortcode($atts) {
// Shortcode attributes
$atts = shortcode_atts(array(
'code' => '', // Flag code (e.g. 'es', 'en', 'fr')
'size' => '16', // Flag size (width in pixels)
), $atts, 'polylang_flag');
// Check if a flag code was provided
if (empty($atts['code'])) {
return 'Flag code not provided.';
}
// Polylang flag base route
$flag_path = plugins_url('polylang/flags/' . $atts['code'] . '.png');
// Create the HTML of the flag image
$flag_html = '<img src="' . esc_url($flag_path) . '" alt="' . esc_attr($atts['code']) . '" width="' . esc_attr($atts['size']) . '" height="auto" />';
return $flag_html;
}
add_shortcode('polylang_flag', 'polylang_flag_shortcode');
Once you have added the code you can use the shortcode with the corresponding country code on any WordPress page or post making sure it matches exactly the names of the flag files in the /wp-content/plugins/polylang/flags/ folder.
[polylang_flag code="en" size="32"]
[polylang_flag code="fr" size="24"]
//Original size
[polylang_flag code="de"]
To play with the size of the flags, simply change the value of the size attribute in the shortcode.
If you want to create and use your own banners or have another collection with a different design, just host the new ones (in .png) in a new folder with a different name (otherwise you will lose the changes when the plugin is updated) and add the new path to the code. For example:
$flag_path = plugins_url('polylang/nuevas_banderas/' . $atts['code'] . '.png');
Adding an SVG icon next to the language selector
This snippet adds an SVG icon with the "Translate" symbol to the left of Polylang's native language selector to make it more visually appealing and catch the visitor's attention. In the example, the icon is the one I use in this blog. You can look for the one you like the most and replace it. Here are a few of them.
function polylang_add_translate_icon($output) {
//SVG icon for "translate".
$translate_icon = '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align: middle; margin-right: 5px;"><path d="M24 24h-2.784l-1.07-3h-4.875l-1.077 3h-2.697l4.941-13h2.604l4.958 13zm-4.573-5.069l-1.705-4.903-1.712 4.903h3.417zm-9.252-12.804c.126-.486.201-.852.271-1.212l-2.199-.428c-.036.185-.102.533-.22 1-.742-.109-1.532-.122-2.332-.041.019-.537.052-1.063.098-1.569h2.456v-2.083h-2.161c.106-.531.198-.849.288-1.149l-2.147-.645c-.158.526-.29 1.042-.422 1.794h-2.451v2.083h2.184c-.058.673-.093 1.371-.103 2.077-2.413.886-3.437 2.575-3.437 4.107 0 1.809 1.427 3.399 3.684 3.194 2.802-.255 4.673-2.371 5.77-4.974 1.134.654 1.608 1.753 1.181 2.771-.396.941-1.561 1.838-3.785 1.792v2.242c2.469.038 4.898-.899 5.85-3.166.93-2.214-.132-4.635-2.525-5.793zm-2.892 1.531c-.349.774-.809 1.544-1.395 2.15-.09-.646-.151-1.353-.184-2.108.533-.07 1.072-.083 1.579-.042zm-3.788.724c.062.947.169 1.818.317 2.596-1.996.365-2.076-1.603-.317-2.596zm11.236-1.745l-2.075-5.533 5.414-1.104-.976 1.868c2.999 2.418 4.116 5.645 4.532 8.132-1.736-2.913-3.826-4.478-5.885-5.321l-1.01 1.958zm-7.895 10.781l1.985 5.566-5.43 1.016 1.006-1.852c-2.96-2.465-4.021-5.654-4.397-8.148 1.689 2.94 3.749 4.483 5.794 5.36l1.042-1.942zm10.795-6.029"/></svg>';
// Add the icon before the selector
return $translate_icon . '<span style="margin-left: 5px;">' . $output . '</span>';
}
add_filter('pll_the_languages', 'polylang_add_translate_icon');
Show customisable warning of the existence of a foreign language version
This function creates a shortcode to display a warning with a yellow background that can be added anywhere on a post or page. This message warns that the article has an English translation with Polylang and provides a link to the English version.
I have chosen this example because I have used it when an article, in any language, received more traffic from English-speaking countries and from English-language browsers (which also does not guarantee that the person behind it was looking for the English version). Still, it's a way to ensure visitor retention in some cases.
Code to add to functions.php
// English version notice
function polylang_translation_notice_shortcode() {
// Verifica si el plugin Polylang está activo
if (!function_exists('pll_the_languages')) {
return '';
}
// Get the ID of the current post
$post_id = get_the_ID();
// Get the English translation of the current post
$english_post_id = pll_get_post($post_id, 'en'); // 'en' es el código del idioma inglés
// Si no hay una traducción en inglés, no mostrará nada
if (!$english_post_id) {
return '';
}
// Get the link to the English version
$english_post_url = get_permalink($english_post_id);
// Crear el contenido del aviso
$ticker_content = sprintf(
'<div style="background-color: #ffffcc; padding: 10px; border-radius: 5px; margin-bottom: 20px; font-size: 14px;">
This article has an English version. <a href="%s" style="color: #0073e6; text-decoration: none; font-weight: bold;">Read</a>
</div>',
esc_url($english_post_url)
);
return $ticker_content;
}
add_shortcode('polylang_translation_notice', 'polylang_translation_notice_shortcode');
In style you can modify the message, the size of the text, the colours of the text, the background and the link to your liking.
To add the message wherever you want, just use this shortcode:
[polylang_translation_notice]
With the CSS in the example it looks like this.

If you want to add a notice to the translation in another language, just change the language code in pll_get_post($post_id, 'en'); to 'fr', 'de', 'it', etc. If you need to use multiple posts, you can add different snippets, one for each language. You could add them all in one snippet, but I only needed one.