EN RU

Multilingual Engine for WordPress - Guide

Version 1.06.0 – 13 July 2025


Table of Contents

  1. Overview
  2. System Requirements
  3. Quick Start
  4. Installation
  5. Configuration Panel
  6. Language Detection Pipeline
  7. URL Schema & Routing
  8. Creating and Managing Content
  9. REST API & External Translation Workflows
  10. Widgets, Shortcodes & Templates
  11. SEO Integration (hreflang)
  12. Debugging & Logging
  13. Maintenance & House‑Keeping
  14. Deactivation & Uninstall
  15. Troubleshooting Guide
  16. Appendix A — CLI, Hooks & Filters

1. Overview

Multilingual Engine (ME) is a light‑weight yet enterprise‑ready multilingual framework for WordPress 6.8+.
Key features:

  • Language prefixes in URLs (/en/, /de/, …) — no additional domains.
  • Ultra‑fast taxonomy‑based language filtering (O(1) DB look‑ups).
  • Automatic or on‑demand creation of translation drafts.
  • REST‑exposed meta for easy integration with CAT tools / MT services.
  • Built‑in <link&nbsp;rel="alternate"&nbsp;hreflang="…"> injection for SEO.
  • Switcher widget & shortcode, debug/trace mode, PSR‑12 clean code.

2. System Requirements

ComponentMinimumRecommended
WordPress core 6.8Latest LTS
PHP 8.38.3.x
Web‑serverApache/Nginx with mod_rewrite enabled
DatabaseMySQL 5.7 / MariaDB 10.3↑ with InnoDB

Note: ME is single‑site only. It neither interferes with, nor supports WordPress Multisite.[^1]


3. Quick Start

  1. Upload folder multilingual-engine/ with multilingual-engine.php to /wp-content/plugins/.
  2. Activate the plugin in Plugins → Installed Plugins.
  3. Navigate to Settings → General, scroll to Multilingual Engine fields and:
  • Enter language codes (e.g. en,de,fr).
  • Choose the default language (en).
  1. Visit your site — ME redirects you to /{lang}/… automatically.
  2. Insert in a menu/widget to let users change language.

4. Installation

4.1 Folder Structure

wp-content/
└── plugins/
    └── multilingual-engine/
        ├── multilingual-engine.php   <-- main plugin file
        └── languages/                <-- .mo/.po if you localise ME itself

4.2 Activation Sequence

Upon activation ME:

  1. Registers a non‑public taxonomy ml_language.
  2. Registers post‑meta _ml_group_id & _ml_language.
  3. Adds options (with defaults):
  • ml_available_languages = en
  • ml_default_language = en
  • ml_auto_create_drafts = 1

The plugin does not touch your database schema.


5. Configuration Panel

(Located in Settings → General)

FieldPurposeValidationNotes
Available languagesComma‑separated ISO‑639‑1 codes[^2]trimmed, lowercase, uniqueAt least one value.
Default languageFallback when detection failsmust be in list aboveApplies to first visit & backend.
Auto create draftsOn save of a new post/page create empty drafts for every other languageboolWhen unchecked, translators are expected to create language records themselves via REST/Admin.

6. Language Detection Pipeline

The detector selects language in the following priority order:

#Source (enum LangSource)ConditionExample
 1URL Prefix /{lang}/Path starts with known code/de/about/
 2Cookie ml_langPreviously chosen by visitor ml_lang=fr
 3HTTP Accept‑LanguageTwo‑letter primary tag matches listru-RU,ru;q=0.9,en;q=0.8
 4Default LanguageOption ml_default_language en

The result is cached in memory and (if step 1 fails) persisted in a cookie (1 year, SameSite=Lax).
See §12 for debug tracing of the pipeline.


7. URL Schema & Routing

  • Front‑end: Each request must start with a language prefix. Otherwise ME issues an HTTP 302 redirect to the same path under the detected code.[^3]
  • Admin: Paths under /wp-admin/ are never redirected or filtered.
  • Generated links: translateUrl() replaces or injects a prefix for any absolute URL.
  • Permalinks: All translations keep identical slugs, only the first segment differs (/{lang}/post-slug/).

8. Creating and Managing Content

8.1 Original Post Creation

When you publish a post/page in any language:

  1. Taxonomy ml_language is set to the current language.
  2. A unique _ml_group_id is written.
  3. Optional — drafts for other languages are generated (see §5).

8.2 Editing Translations

  • In Posts → All Posts additional quick‑links Edit {CODE} appear for each language in the same group.
  • Alternatively filter list by language via Screen Options›Filter by ml_language (WordPress native taxonomy filter UI is not shown because taxonomy is show_ui&nbsp;=false; use Quick Edit or list views added by ME).

8.3 Manual Draft Creation

If auto‑drafts are disabled create a new post and manually assign:

  1. Meta _ml_group_id equal to original group.
  2. Taxonomy term ml_language = target code.

Easier: POST via REST as shown in §9.


9. REST API & External Translation Workflows

9.1 Exposed Meta Fields

KeyTypeAccessDescription
_ml_languagestringread/writeTwo‑letter code (en).
_ml_group_idstringread/writeSame for all translations of one article.
POST /wp-json/wp/v2/posts
Authorization: Bearer YOUR_JWT
Content-Type: application/json

{
  "title"  : "Hallo&nbsp;Welt!",
  "content": "<p>…deutsche&nbsp;Version…</p>",
  "status" : "publish",
  "meta"   : {
    "_ml_language": "de",
    "_ml_group_id": "mlg_64b034b4b7e44.18830524"
  }
}

If _ml_group_id is omitted and SEPARATE original is not found, ME treats the post as new original and assigns a fresh group ID.

9.2 Fetching Translations

GET /wp-json/wp/v2/posts?meta_key=_ml_group_id&meta_value=mlg_…&per_page=100

Each record carries _ml_language — pick the desired version.


10. Widgets, Shortcodes & Templates

FeatureUsage
Shortcode — renders a <select> that reloads with chosen language.
WidgetLanguage Switcher under Appearance → Widgets or Site Editor block list.
PHP HelperMultilingualEngine\Plugin::translateUrl( $absUrl, 'fr', $plugin->langs ).

You may enqueue your own CSS for .ml-switcher.


11. SEO Integration (hreflang)

For singular posts/pages ME injects, inside <head>, one <link&nbsp;rel="alternate"&nbsp;hreflang="xx"&nbsp;href="…"> per published translation.
No action is needed, though you can hook wp_head priority 1 to prepend/override if desired.


12. Debugging & Logging

ModeEnablementOutput
Trace (recommended)define('MULTILINGUALENGINE_DEBUG', true);wp-content/debug.log via error_log()
WP core debugdefine('WP_DEBUG_LOG', true);same file

Trace includes detection source, redirects, draft creation failures, plugin init.
Disable in production to keep headers clean and caches warm.


13. Maintenance & House‑Keeping

13.1 Changing Language List

  1. Edit Available languages field.
  2. Save Changes — the taxonomy term list updates immediately.
  • New codes: create terms on first use.
  • Removed codes: terms remain, but won’t be selectable; clean them with a SQL script if needed.

13.2 Bulk Regenerate Drafts

If you add a new language after many posts already exist and want drafts:

  1. Temporarily enable Auto create drafts.
  2. Re‑save originals (bulk “Edit → Update”).
  3. Disable the option if desired.

13.3 Cleaning Empty Drafts

Run in WP‑CLI:

wp post list --post_status=draft --meta_key=_ml_group_id --format=ids \
| xargs -n1 -I{} wp post delete {} --force

Always backup before bulk deletes.


14. Deactivation & Uninstall

ActionEffect
Deactivate pluginFront‑end keeps language prefixes → pages become 404. Plan redirects before disabling.
Delete pluginRemoves its PHP files only. Options, taxonomy terms & meta stay to preserve data.[^4]

If you truly want to purge:

delete_option('ml_available_languages');
delete_option('ml_default_language');
delete_option('ml_auto_create_drafts');

Then (optionally) bulk‑delete meta keys and the ml_language taxonomy via direct SQL.


15. Troubleshooting Guide

SymptomLikely CauseFix
Endless 302 loopCookie set to unsupported codeClear browser cookies or fix list in Settings (§5).
Drafts multiply exponentiallyOld plugin version before 1.01.0 caused recursionUpdate plugin; delete extra drafts (§13.3).
Switcher shows duplicate codes“Available languages” contains spaces/duplicatesRe‑save list (plugin sanitises input).
REST creates post but language filter hides it_ml_language meta missing or typoPATCH post via REST with correct meta or edit in Admin.
hreflang missingPage has no published translations in same groupPublish at least one other language or set status=publish.

16. Appendix A — CLI, Hooks & Filters

16.1 CLI Snippets

List all groups with missing languages:

wp eval '
$pl = MultilingualEngine\Plugin::instance();
foreach (get_posts(["meta_key"=>"_ml_group_id","posts_per_page"=>-1,"fields"=>"ids"]) as $id){
    $g = get_post_meta($id,"_ml_group_id",true);
    $langs = wp_get_post_terms($id,"ml_language",["fields"=>"slugs"]);
    if(count($langs)<count($pl->langs)){
        echo "$id&nbsp;$g&nbsp;missing\n";
    }
}'

16.2 Hooks & Filters

HookContextArgsDescription
pre_get_posts (internal)Front‑end main queryWP_QueryAdds tax_query filter
save_post (internal)Any post/page saveID, WP_Post, bool \$updateAssign language & group, create drafts
ml_translatable_post_types filterEarly in constructorarray \$defaultsOverride list of CPTs subject to translation
language_switcher shortcodeAny templateRenders selector

Footnotes

[^1]: For multisite consider mapping each language to a separate site, or use Polylang Pro / WPML.

[^2]: Use ISO‑639‑1 primary tags (en, fr, zh). Extended tags (pt-br) are possible but require matching browser headers.

[^3]: Redirect status is 302 (temporary) by default to respect explicit user changes; change to 301 in code if desired.

[^4]: WordPress policy discourages destructive uninstallers; data persistence allows re‑activation without loss.

Разработка и продвижение сайтов webseed.ru
Прокрутить вверх