WP Residence Help WP Residence Help

  • WPRESIDENCE
  • Video Tutorials
  • Client Support
  • API
Home / WPEstate Translate Plugin / Elementor Widget Translation — Developer Guide

Elementor Widget Translation — Developer Guide

272 views 0

This article is the developer companion to the user-facing article on Elementor translation. It documents the code paths that let WPEstate Translate read Elementor layouts, build a translation payload, and write translated values back into _elementor_data. Product context lives on the multi-language real estate website page.

CONTENT

  • File Map
  • Bootstrap
  • Detecting Elementor Pages
  • Widget Field Map
  • Text Extraction
  • Taxonomy Alias Resolution
  • ID Normalizers
  • Document Pipeline (auto-translate)
  • Legacy Apply Pipeline
  • Taxonomy Term Resolution
  • Front-end Search Form Builder Priming
  • Elementor Shortcode Widget
  • Extension Points
  • Gotchas
  • Further Reading

File Map

File Role
includes/elementor-widget-compat.php Front-end integration: re-renders Elementor shortcode widgets and primes Search Form Builder term data.
includes/admin/elementor-translate-builder.php Builds translation payloads from stored Elementor data. Loads the widget field map and decodes _elementor_data.
includes/admin/elementor-translate-text.php Walks Elementor layouts and extracts translatable text nodes.
includes/admin/elementor-translate-apply.php Legacy apply path: resolves taxonomy/post IDs and writes translated payloads back into the translated post’s Elementor data. Used only when a response carries no reconstructed document.
includes/admin/elementor-document-prepare.php wpr_translate_elementor_document_prepare() – snapshots the source _elementor_data and collects translatable text units and ID/slug references.
includes/admin/elementor-document-repeaters.php Collects units and references inside repeater controls of special widgets.
includes/admin/elementor-document-reconstruct.php wpr_translate_elementor_document_reconstruct() – writes translated units back into a copy of the snapshot, keeping each value’s original shape.
includes/admin/elementor-document-references.php Resolves post IDs, term IDs and term slugs to the target language.
includes/admin/elementor-document-save.php wpr_translate_elementor_document_save() – saves the document to the translated page and regenerates its Elementor CSS.

Bootstrap

Front-end hooks are registered by wpr_translate_bootstrap_elementor_widget_compat(). It is idempotent via a static flag and attaches three hooks:

add_filter( 'elementor/widget/render_content', 'wpr_translate_filter_elementor_shortcode_widget_content', 10, 2 );
add_action( 'elementor/frontend/widget/before_render', 'wpr_translate_prepare_search_form_builder_frontend_ids', 20, 1 );
add_action( 'elementor/frontend/widget/before_render', 'wpr_translate_log_agent_grids_frontend_ids', 20, 1 );

The shortcode parts of the compat layer are gated by wpr_translate_is_elementor_compat_enabled() (includes/shortcode-compat.php). It reads the elementor_compatibility key from the wpr_translate_settings option and returns true only when the key is missing. Since 1.0.9 the settings sanitizer saves an unchecked box as false, so the Elementor & Shortcodes checkbox on WPEstate Translate > Settings really turns it off. The Search Form Builder priming hook is not gated.

Detecting Elementor Pages

Only pages with Elementor builder data enter the translation pipeline. wpr_translate_is_elementor_page( $post_id, $post_type ) checks two meta keys:

_elementor_data       // the serialized JSON layout blob
_elementor_edit_mode  // Elementor's edit mode flag

The function returns false for every post type except page. On a page, it returns true when either key is non-empty.

Widget Field Map

wpr_translate_load_translatable_elementor_widget_fields() merges three JSON sources, in order of increasing priority. The merge is field by field (wpr_translate_merge_elementor_widget_field_maps()), so a later file adds or overrides fields but never removes fields declared earlier. WPResidence ships its own map in wpr/translatable_widget_fields.json.

  1. Bundled defaults at WPR_TRANSLATE_PATH . ‘assets/config/translatable_default_elementor_widgets.json’.
  2. Parent theme override at get_template_directory() . ‘/wpr/translatable_widget_fields.json’.
  3. Child theme override at get_stylesheet_directory() . ‘/wpr/translatable_widget_fields.json’.

Each widget key maps to a list of fields. Fields can be plain text (translated as strings), taxonomy references (term IDs or slugs), or post ID references.

 

Text Extraction

wpr_translate_extract_elementor_text_fields( $raw_elementor_data ) is now only used for logging after a save. It walks the decoded layout recursively and collects string values from known widget settings keys (title, heading, text, button_text, label). Each value is stripped of HTML via wp_strip_all_tags() and returned as an ordered, filtered list of unique text nodes for the translation editor / auto-translate providers.

Taxonomy Alias Resolution

WPResidence Elementor widgets store taxonomy references under field aliases like action_ids, category_data, county_data. Real taxonomy slugs are required to look up translated terms. wpr_translate_resolve_elementor_taxonomy_slug( $field_name, $field_value, $allow_alias_without_numeric ) maps the alias to the registered taxonomy, using an explicit alias map:

action_ids   => property_action_category
area_ids     => property_area
category_ids => property_category
city_ids     => property_city
county_data  => property_county_state
features_ids => property_features
status_ids   => property_status

The mapping only runs when the field value contains numeric term IDs, unless $allow_alias_without_numeric is true.

ID Normalizers

Function Purpose
wpr_translate_normalize_elementor_ids() Accepts a JSON-encoded list, a comma-separated string such as “12,15,20” (List Items By ID, Content Grid), or an array. Returns an array of absint IDs. The translated IDs are written back joined with commas.
wpr_translate_normalize_elementor_slugs() Returns a de-duplicated list of sanitized slugs.

Document Pipeline (auto-translate)

Automatic translation of an Elementor page runs through the document modules. wpr_translate_auto_translate_post() calls them in this order:

  1. Prepare – wpr_translate_elementor_document_prepare( $source_post_id, $language ) returns status ready or skipped, the text units, and a private snapshot with unit locations and references.
  2. Send – only the units go to the engine, under elementor.units in the normalized request. The raw _elementor_data and the ID references never leave the site.
  3. Reconstruct – wpr_translate_normalize_engine_response() calls wpr_translate_elementor_document_reconstruct(), which writes the translated units into the snapshot and resolves references with wpr_translate_elementor_document_apply_references(). Each post or term ID is resolved through wpr_translate_relationship_resolve_post() / _resolve_term(); a slug is resolved via its term. When no translation exists, the source value is kept and counted as a fallback.
  4. Save – wpr_translate_elementor_document_save() writes _elementor_data, reads it back to confirm it saved, then clears the Elementor files cache and regenerates the page CSS.

Each step writes one line to the PHP error log with the prefixes [WPR Translate Elementor prepare] and [WPR Translate Elementor save] (widget, unit and reference counts).

When a page is translated manually (Add translation), the builder meta (_elementor_data, _elementor_edit_mode, _elementor_version, _elementor_template_type) is copied. The generated caches _elementor_css, _elementor_page_assets and _elementor_element_cache are not copied, so Elementor rebuilds them for the new page. The copied _elementor_data keeps the original property, agent and term IDs: the widget ID remapping of the document pipeline runs only on Auto translate. Shortcode IDs, by contrast, are swapped at render time (see Shortcode and Widget ID Remapping).

Legacy Apply Pipeline

The functions below remain for payloads that do not carry a reconstructed document.

wpr_translate_apply_elementor_widget_translations( &$elements, $config, $elementor_translate, $language, &$term_report ) is the workhorse. It traverses the Elementor element tree in place and for each widget listed in the field map it:

  • Overwrites text fields with entries from $elementor_translate.
  • Resolves taxonomy payloads via wpr_translate_resolve_elementor_taxonomy_ids() or wpr_translate_resolve_elementor_taxonomy_slugs().
  • Shapes the result to match the original field via wpr_translate_match_elementor_setting_shape().
  • Appends audit rows to $term_report via wpr_translate_collect_elementor_term_report_entry().

wpr_translate_apply_elementor_translations( $post_id, $translated_payload, $target_language ) is the public entry point that persists the updated payload back to _elementor_data.

Taxonomy Term Resolution

wpr_translate_resolve_elementor_taxonomy_ids( $taxonomy_entry, $language ) tries, in order:

  1. Strict term-ID lookup via wpr_translate_lookup_translated_term_id_strict().
  2. Fallback term-ID lookup via wpr_translate_lookup_translated_term_id().
  3. Slug lookup via wpr_translate_lookup_translated_term_id_by_slug().
  4. Name lookup as a last resort.

Every candidate must pass term_exists() in the target taxonomy before being accepted.

Front-end Search Form Builder Priming

wpr_translate_prepare_search_form_builder_frontend_ids() runs on elementor/frontend/widget/before_render for widgets whose get_name() is WpResidence_Search_Form_Builder. It:

  1. Reads the tabs_field setting and the matching taxonomy data setting (action_data, category_data, etc.).
  2. Normalizes term IDs, loads WP_Term instances, and builds a term_id => name map.
  3. Writes the map to a transient keyed by ‘wpestate_elementor_tax_’. When wpestate_set_transient_name_multilang() exists, the transient key is language-scoped to avoid cross-language cache collisions.
  4. The transient TTL is six hours.

Elementor Shortcode Widget

wpr_translate_filter_elementor_shortcode_widget_content() handles Elementor’s generic shortcode widget. If Elementor returned the shortcode string verbatim (i.e., the shortcode was not executed, typical in live previews), the filter calls do_shortcode() so the plugin’s pre_do_shortcode_tag translation hook in shortcode-compat.php can run.

 

Extension Points

  • Add a widget – drop an entry keyed by the Elementor widget name into wpr/translatable_widget_fields.json in your child theme.
  • Override a resolver – copy wpr_translate_resolve_elementor_taxonomy_slug() behaviour by extending the alias map in a custom filter wrapping this function, guarded by function_exists().
  • Disable compat – set elementor_compatibility to false in the wpr_translate_settings option.

Gotchas

  • Elementor stores layouts as JSON inside a post meta. Read it with wpr_translate_decode_elementor_data(); write it back as wp_slash( wp_json_encode( $document, JSON_UNESCAPED_UNICODE ) ) the way wpr_translate_elementor_document_save() does.
  • The apply function mutates $elements by reference. Clone the array first if you need the original.
  • Non-Latin text fields must not be pushed through sanitize_title(). Use sanitize_text_field() or a custom escaper.
  • Search Form Builder uses the front-end transient strictly as a display cache. It is not authoritative – the real term resolution happens through the term translation metadata.
  • Only pages go through the Elementor pipeline. Elementor data on other post types is copied as-is.

Further Reading

  • Shortcode & Widget ID Remapping – the shortcode-level ID swap used by the Elementor shortcode widget.
  • Taxonomy Translation – the lookup helpers referenced here.
  • Translation Linking (trid system) – how translated post IDs are resolved.

For the broader feature set, see our multi-language real estate website page.

WPEstate 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
MLSImportWordPress IDX Plugin for MLS ListingsImport MLS listings into your WordPress website, customize your property pages, and keep your inventory updated.Start free 30-day trial →

Help Categories

  • 51 Getting Started
  • 72 Installation & Setup
  • 243 Installation FAQ
  • 18Agent, Agency & Developers
  • 5Blog Posts & Blog Lists
  • 39Elementor Shortcodes Built-In
  • 56FAQ
  • 15Footer
  • 37Header
  • 2IDX & MLSImport
  • 23Maps & Location Settings
  • 21Multi-Language - Third Party Plugins
  • 7Other Third party Plugins
  • 21Pages
  • 4Payments & Monetization
  • 20Property Lists, Categories & Archive
  • 37Property Pages & Layouts
  • 32Search & Filtering
  • 162Technical how to | Custom Code
  • 8Technical: Actions and filters
  • 7Technical: Child Theme
  • 86Theme Options & Global Settings
  • 6Translations & Languages
  • 16WPBakery Shortcodes
  • 50WPEstate Translate Plugin
  • 51WPResidence / WPEstate CRM
  • 50WPResidence 5.0 Documentation
  • 9WPResidence Elementor Studio

Join Us On

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