hello! π Today we’re going to learn how to build a system to automatically translate existing and new posts on your WordPress site, and even optimize them for SEO.
in this lesson, we’ll utilize the DeepL API, the Polylang plugin, and Yoast SEOto create an environment that you can set up once and have translations happen automatically. π

as a reminder, the DEEP L API is free to use for translating up to 500,000 characters per month.
π Course Objectives
1οΈβ£ translate all existing Korean posts into English and Japanese
2οΈβ£ Automatically translate future posts as they are created
3οΈβ£ preserve the HTML structure of translated posts so that they don’t break
4οΈβ£ apply SEO (search engine optimization) settings to maximize search visibility
5οΈβ£ Prevent duplicate translations to avoid retranslating already translated posts
π‘ 1. Prepare your project
first, you need to prepare your project. it should have the following tasks done
π Required installations
β
WordPress site
polylang plugin (multilingual support)
yoast SEO plugin (search optimization)
deepL API key issued (to use the Translation API)
π Get DeepL API key
To use the DeepL translation API, you need an API key.
1οΈβ£ DeepLGo to the API website
sign up for 2οΈβ£ and get an API key
3οΈβ£ Copy your API key(
enter it in theYOUR_DEEPL_API_KEY
part)
π‘ 2. Writing the code: Building the automatic translation system
now, let’s build the translation system by adding code to functions.php
.
π 2-1. Code to automatically translate existing posts
first, let’s create code to automatically translate all posts that have already been created.
// function to check if a post is already translated (to avoid duplicate translations) function is_already_translated($post_id, $lang) { $translations = pll_get_post_translations($post_id); return isset($translations[$lang]); // check if a translation exists for the language } // function to translate all existing posts (run only once) function auto_translate_existing_posts() { $languages = [
'en' => ['prefix' => 'en', 'sep' => '-', 'sitename' => get_bloginfo('name')], 'ja' => ['prefix' => 'ja', 'sep' => '-', 'sitename' => get_bloginfo('name')], ]; $args = [
'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => -1, ]; $posts = get_posts($args); foreach ($posts as $post) { if (pll_get_post_language($post->ID) !== 'en') continue; foreach ($languages as $lang => $settings) { if (is_already_translated($post->ID, $lang)) { continue; // skip if already translated } $translated_title = deepl_translate_with_html($post->post_title, $lang); $translated_content = deepl_translate_with_html($post->post_content, $lang); $translated_slug = $settings['prefix'] . '-' . sanitize_title($translated_title); $seo_title = $translated_title . ' ' . $settings['sep'] . ' ' . $settings['sitename']; $translated_post_id = wp_insert_post([
'post_title' => $translated_title, 'post_content' => $translated_content, 'post_status' => 'publish', 'post_type' => $post->post_type, 'post_author' => $post->post_author, 'post_name' => $translated_slug, 'post_category' => wp_get_post_categories($post->ID), 'meta_input' => [
'_yoast_wpseo_title' => $seo_title, ], ]); pll_set_post_language($translated_post_id, $lang); pll_save_post_translations([ 'en' => $post->ID, $lang => $translated_post_id, ]);
} } } // Run translation of existing post (run only once) add_action('admin_init', function () { if (isset($_GET['run_translation']) && $_GET['run_translation'] === '1') { auto_translate_existing_posts(); wp_die('Translation for all existing posts completed.'); } })
π Now, if you run the URL below in your browser, all your existing posts will be translated!
(
Make sure to changeyour-site.com to your
site domain)
https://your-site.com/wp-admin/?run_translation=1
π 2-2. New post auto-translation code
β Nowset it up so that new posts are automatically translated when they are created.
function auto_translate_and_seo_publish($post_id) { $original_post = get_post($post_id); if ($original_post->post_status !== 'publish') return; $languages = [ 'en' => ['prefix' => 'en', 'sep' => '-', 'sitename' => get_bloginfo('name')], 'ja' => ['prefix' => 'ja', 'sep' => '-', 'sitename' => get_bloginfo('name')], ]; if (pll_get_post_language($post_id) !== 'en') return; foreach ($languages as $lang => $settings) { if (is_already_translated($post_id, $lang)) { continue; // skip if already translated } $translated_title = deepl_translate_with_html($original_post->post_title, $lang);
$translated_content = deepl_translate_with_html($original_post->post_content, $lang); $translated_slug = $settings['prefix'] . '-' . sanitize_title($translated_title); $seo_title = $translated_title . ' ' . $settings['sep'] . ' ' . $settings['sitename']; $translated_post_id = wp_insert_post([
'post_title' => $translated_title, 'post_content' => $translated_content, 'post_status' => 'publish', 'post_type' => $original_post->post_type, 'post_author' => $original_post->post_author, 'post_name' => $translated_slug, 'meta_input' => [
'_yoast_wpseo_title' => $seo_title, ], ]); pll_set_post_language($translated_post_id, $lang); pll_save_post_translations([
'en' => $post_id, $lang => $translated_post_id, ]); } } // Run automatic translation when a new post is published add_action('publish_post', 'auto_translate_and_seo_publish')
π Final wrap-up
β Want to translate all existing posts?
- run it once:
https://your-site.com/wp-admin/?run_translation=1
β Want to translate a new post?
- auto-translated after creating a new post. (No additional work required)
β Want to recreate a translated post?
- delete the existing translated post and run it again.
π‘ Now you can run multilingual content in WordPress completely automatically! π If you have any more questions, feel free to ask! π
π Additional things to check after the run
- check if your translated posts have been created
- check yourWordPress admin β “All Posts” to see if you have posts translated into
English (
EN) andJapanese (
JA).
- check yourWordPress admin β “All Posts” to see if you have posts translated into
- Check the URL
- korean posts:
https://example.co.kr/μ¬λ¦Όν½-μΌμ /
- english post:
https://example.co.kr/en/olympic-schedule/
- japanese posts:
https:
//example.co.kr/ja/γͺγͺγ³γγγ―ζ₯η¨/
- korean posts:
- make sure your translated posts are properly linked in Polylang
- check translation relationships in yourWordPress admin β Polylang.
π Once you finish translating an existing post, you don’t need to run it again
β
Once you translate an existing post once, you don’t need to run this URL again.
β
Afterward, when you create a new post, it will be translated automatically.
π Additional questions
Q1. Can I run this URL multiple times?
β
It’s okay to run it multiple times, as it won’t retranslate posts that have already been translated.
β
Thisis
because it contains a code(is_already_translated()
) that prevents duplicate translations.
Q2. How do I retranslate an existing post?
π¨ You need to delete the existing translation and run it again.
β
Delete the existing translated post and run https://your-site.com/wp-admin/?run_translation=1
again.
Q3. What if the translation doesn’t happen automatically?
β If you run it and it doesn’t translate, check the following
- make sure the code is added
to functions.php
correctly. - Make sure your DeepL API key is set correctly.
- Make sure the Polylang plugin is activated.
- wordPress admin β Settings β Save unique address (permalink ) button and run it again.