WP Residence Help WP Residence Help

  • WpEstate
  • WPRESIDENCE
  • Video Tutorials
  • Client Support
  • API
Home / 30. WPResidence Translate Plugin / Translating Posts and Pages — Developer Internals

Translating Posts and Pages — Developer Internals

2 views 0

This article is the developer-facing companion to the post translation workflow. It documents the editor hooks, the AJAX handlers, the draft cloning path, and the meta/runtime layer that make the user-facing flow work. For product context see the user article and the multi-language real estate website landing page.

Files Involved

File Role
includes/admin/post-editor.php Meta box, publish-box button, asset enqueue, auto-translate AJAX handlers.
includes/admin/editor-header-language.php Localizes the block editor header language badge.
includes/translation-runtime.php Resolves the active language for the current request.
includes/translation-hooks.php Registers runtime filters (gettext, override_load_textdomain, etc.).
includes/admin/post-list-actions.php Handles the Add Translation request and the draft cloning logic.

Editor Bootstrap

The post editor integration is wired up in two steps from post-editor.php:

function wpr_translate_bootstrap_post_editor_integration() {
    add_action( 'load-post.php',     'wpr_translate_initialize_post_editor_hooks' );
    add_action( 'load-post-new.php', 'wpr_translate_initialize_post_editor_hooks' );

    add_action( 'wp_ajax_wpr_translate_auto_translate_post',
        'wpr_translate_handle_auto_translate_post_ajax' );
    add_action( 'wp_ajax_wpr_translate_auto_translate_post_publish',
        'wpr_translate_handle_auto_translate_post_publish_ajax' );
}

On editor screens, wpr_translate_initialize_post_editor_hooks() then registers:

add_action( 'post_submitbox_misc_actions', 'wpr_translate_render_post_auto_translation_button' );
add_action( 'add_meta_boxes',              'wpr_translate_register_auto_translate_metabox', 10, 2 );
add_action( 'admin_enqueue_scripts',       'wpr_translate_enqueue_post_editor_assets' );

The meta box wpr-translate-auto-translate is only registered when use_block_editor_for_post() returns true. Classic editors fall back to the publish-box section instead.

Editor Header Language Badge

The badge comes from wpr_translate_enqueue_post_editor_language_badge_assets(), hooked to admin_enqueue_scripts at priority 20 so it runs after wpr-translate-admin is registered. It resolves the current language in this order:

  1. wpr_translate_return_current_language_admin() — admin selector state.
  2. wpr_translation_get_default_language_code() over wpestate_translation_get_active_languages() — site default.
  3. Legacy wpestate_default_language option.
  4. Hardcoded 'en' fallback.

It then calls wpr_translate_get_language( $code ), builds a flag URL from WPR_TRANSLATE_URL . 'assets/img/flags/4x3/{code}.svg', and hands the payload to the editor JS via:

wp_localize_script( 'wpr-translate-admin', 'wprTranslatePostLanguage', $payload );

Payload shape: label, code, flagUrl, flagAlt.

Screenshot: Block editor header with the injected language badge and flag rendered by wprTranslatePostLanguage

Resolving the Source Post

Auto-translate needs a source to translate from. wpr_translate_resolve_metabox_source_post_id( $post_id ) picks it in this order:

  1. Explicit post meta wpr_translated_original_post_id.
  2. Translation group row where original = 1 for the same trid (via wpr_translation_get_translation_group()).
  3. Group’s source_language if the original flag is not set.

If nothing resolves, the button renders disabled with the label Auto translation unavailable.

Auto Translate AJAX Endpoints

Two wp_ajax_* actions power the in-editor translation:

Action Handler Purpose
wpr_translate_auto_translate_post wpr_translate_handle_auto_translate_post_ajax() Translate fields inside the editor (manual button).
wpr_translate_auto_translate_post_publish wpr_translate_handle_auto_translate_post_publish_ajax() Translate and apply on publish.

Both handlers:

  • Validate the nonce wpr_translate_auto_translate_post.
  • Enforce current_user_can( 'edit_post', $post_id ).
  • Call do_action( 'qm/cease' ) to silence Query Monitor during heavy calls.
  • Look up the engine from get_option( 'wpr_translate_auto_translation' ) — validated against openai, google_translate, microsoft_azure, deepl.
  • Delegate to wpr_translate_auto_translate_post( $post_id, $language, $engine, $source_post_id ).

What wpr_translate_auto_translate_post Touches

Downstream, the translation payload is applied in:

  • wpr_translate_apply_translated_post_data() — post_title, post_content, post_excerpt, post_name.
  • wpr_translate_apply_translated_post_meta_fields() — per-meta-key based on the Custom Field Rules preferences.
  • wpr_translate_apply_translated_taxonomies() — maps terms to translated equivalents via the translation group.
  • wpr_translate_log_translated_elementor_data() and wpr_translate_log_translated_wpbakery_data() — structured builders.

Elementor and WPBakery fields are extracted before translation. For WPBakery, wpr_translate_extract_wpbakery_text_fields( $post_content ) walks shortcodes and pulls human-readable fields. A completed auto-translation is stamped with _wpr_translate_auto_translated_language meta on the target post to power the Redo the translation state.

Manual Translation — Draft Cloning

When an editor clicks the plus icon in the post list Language column, WordPress hits admin.php?action=wpr_add_translation&post_id=X&language=xx. That lands in wpr_translation_handle_add_translation_request(), which:

  1. Verifies the nonce produced by wpr_translation_get_translation_nonce_action( $post_id, $language ).
  2. Calls wpr_translation_create_translation_draft( $post_id, $language ).
  3. Redirects the user to get_edit_post_link( $new_post_id ).

wpr_translation_create_translation_draft() clones the source using wp_insert_post(), then:

  • Copies the page template via wpr_translation_get_validated_page_template().
  • Clones attachments via wpr_translation_clone_attachments().
  • Clones taxonomies via wpr_translation_clone_taxonomies().
  • Clones meta via wpr_translation_clone_meta_fields() in post-list-meta.php, which consults wpr_translation_get_cached_custom_field_preferences() for per-key rules.
  • Writes the translation group row via wpr_translation_insert_translation_record().

Screenshot: Debug log of wpr_translation_create_translation_draft showing cloned taxonomies and meta application

Permissions & Nonces

  • Add Translation action: capability edit_post on the source post; nonce wpr_add_translation_{post_id}_{language}.
  • Auto Translate AJAX: capability edit_post; nonce wpr_translate_auto_translate_post.
  • Admin menu pages all live behind manage_options.

Localized JS Settings

wpr_translate_enqueue_post_editor_assets() enqueues assets/js/admin.js + assets/css/admin.css and localizes:

wprTranslateAutoSettings = {
    enabled: bool,
    engine:  'openai' | 'google_translate' | 'microsoft_azure' | 'deepl',
    ajax:    { url, nonce },
    strings: { error, success, processing },
};

Extension Points

  • Action wpr_translation_created — fires from wpr_translation_insert_translation_record() after a new translation row is inserted. Arguments: $post_id, $element_type, $trid, $language_code, $source_language, $post_status, $original.
  • Custom Field Rules — add a rule via the admin page to change whether a meta key is copied, translated, copied-once, or skipped. Rules are cached via wpr_translation_get_cached_custom_field_preferences().
  • Auto-translate providers — implemented as self-contained files in includes/admin/auto-translate-*.php. To add a provider, replicate the pattern and register the engine key.

Gotchas

  • The meta box only appears for posts where use_block_editor_for_post() returns true. In Classic editor sites, the button is rendered from post_submitbox_misc_actions.
  • The publish-box button renders an Original post — no translation action message when the current post’s language equals the default. This is by design — you translate into a language.
  • Heavy auto-translate requests call do_action( 'qm/cease' ) — if you rely on Query Monitor during translation debugging, disable Query Monitor or comment out that call in a child plugin.
  • The asset handle wpr-translate-admin is registered lazily. Any code that piggy-backs via wp_localize_script() must hook at priority > 10.

Further Reading

  • Post List Table Enhancements — the admin list columns, filters, and sortable language header.
  • Translation Linking (trid system) — the shared identifier that binds all variants together.
  • Meta Sync Across Language Variants — how wpr_translation_clone_meta_fields() applies per-key rules.

For the product-level overview of what this integration enables, read our guide to a multi-language real estate website.

30. WPResidence Translate Plugin

Related Articles

  • String Scanner — Developer Guide
  • The String Scanner
  • Gettext Pipeline & MO Files — Developer Guide
  • Gettext & MO Files — Making Translations Appear on the Front End

WP Residence Documentation

  • 01. Getting Started
    • How to Get Support
    • Get your buyer license code.
    • Use SSL / https
    • Server / Theme Requirements
  • 02. Installation & Setup
  • 03. Installation FAQ
  • 06. Search & Filtering
    • Advanced Search Display Settings
    • Advanced Search Form
    • Geolocation Search for Half Map
    • Save Search Theme Options
    • Advanced Search Colors
  • 09. Agent, Agency & Developers
  • 08. Property Pages & Layouts
  • 07. Property Lists, Categories & Archive
  • 13. WPResidence Elementor Studio
  • 10. Blog Posts & Blog List
  • 11. Shortcodes
    • Contact Form
    • Featured Agency/Developer
    • Membership Packages
    • Testimonials
    • Google Map with Property Marker
    • Listings per Agent, Agency or Developer
    • Display Categories
    • Agent List
    • Recent Items Slider
    • Recent items
    • List Properties or Articles by ID
    • Featured Agent
    • Featured Article
    • Featured Property
    • Login & Register Form
    • Icon Content Box Shortcode
  • 12. Widgets
  • 04. Theme Options & Global Settings
    • General Settings
    • User Types Settings
    • Appearance
    • Logos & Favicon
    • Header
    • Footer Style and Colors
    • Price & Currency
    • Property Custom Fields
    • Features & Amenities
    • Listing Labels
    • Theme Slider
    • Permalinks
    • Splash Page
    • Social & Contact
    • Map Settings
    • Pin Management
    • How read from file works
    • General Design Settings
    • Custom Colors Settings
    • Header Design & Colors
    • Mobile Menu Colors
    • User Dashboard Colors
    • Print PDF Design
    • Property, Agent, Blog Lists Design Settings
    • Sidebar Widget Design
    • Font management
    • How to add custom CSS
    • Custom Property Card Unit – Beta version
    • Email Management
    • Import & Export theme options
    • reCaptcha settings
    • YELP API Integration
    • iHomefinder Optima Express IDX
    • MEMBERSHIP & PAYMENT Settings
    • Property Submission Page
    • PayPal Setup
    • Stripe Setup
    • Wire Transfer Payment Method
  • 20. Translations & Languages
  • 26. FAQ
  • 10. Pages
  • 11. Header
  • 12. Footer
  • 05. Maps & Location Settings
  • 18. Payments & Monetization
  • Plugins
    • 19. Included Plugins
    • 22. Third Party Plugins – IDX Compatibility
    • 21. Third-Party Plugins – Multi-Language
    • 23. Third party Plugins – Other
  • Technical
    • 24. Technical how to | Custom Code Required
    • 25. Technical: Child Theme

Join Us On

Powered by WP Estate - All Rights Reserved
  • WpEstate
  • WPRESIDENCE
  • Video Tutorials
  • Client Support
  • API