WP Residence Help WP Residence Help

  • WpEstate
  • WPRESIDENCE
  • Video Tutorials
  • Client Support
  • API
Home / 30. WPResidence Translate Plugin / Translation Linking — The trid System

Translation Linking — The trid System

2 views 0

The trid (translation group ID) is the central identifier that binds language variants of the same content together in WPResidence Translate. This article documents the schema, the helper functions, the lookup paths used by queries, and the action hook you can use to observe group mutations. For the conceptual overview see the user article; for the broader plugin map see our multi-language real estate website documentation.

The Translations Table

Defined in includes/activator.php via wpr_translate_activator_create_tables(). Table name: {$wpdb->prefix}wpestate_translation_translations.

CREATE TABLE {prefix}wpestate_translation_translations (
    translation_id        BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    element_type          VARCHAR(45)  NOT NULL,
    element_id            BIGINT(20) UNSIGNED NOT NULL,
    trid                  BIGINT(20) UNSIGNED NOT NULL,
    language_code         VARCHAR(7)   NOT NULL,
    source_language_code  VARCHAR(7)   NULL,
    post_status           VARCHAR(20)  NOT NULL DEFAULT 'publish',
    translator_id         BIGINT(20) UNSIGNED NULL,
    original              TINYINT(1)   NOT NULL DEFAULT 0,
    needs_update          TINYINT(1)   NOT NULL DEFAULT 0,
    last_updated          DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP
                                       ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (translation_id),
    KEY trid     (trid),
    KEY element  (element_id, element_type),
    KEY language (language_code)
) {charset_collate};

Column Reference

Column Meaning
translation_id Primary key. One row per (post, language) pair.
element_type Logical type: post_post, post_page, post_estate_property, taxonomy_{tax}, etc. Derived from post type or taxonomy.
element_id The WordPress object ID — post_id for post types, term_id for taxonomies.
trid Group identifier. All language variants of the same content share this value.
language_code Lowercased language code of this variant (en, fr, ru, ar, zh…).
source_language_code Code of the language this variant was translated from. Enables correct re-translation source.
post_status Snapshot of the post status at creation — kept to query group state without hitting wp_posts.
translator_id User ID from get_current_user_id() at insert time.
original 1 for the source-language variant of the group. Only one row per trid should carry this flag.
needs_update Set when the original is edited and downstream translations should be refreshed.
last_updated Auto-maintained MySQL timestamp.

Screenshot: phpMyAdmin view of wp_wpestate_translation_translations with three rows sharing the same trid across en/fr/es

Index Strategy

  • KEY trid — primary access path for “give me every variant in this group”.
  • KEY element — primary access path for “what group does this post belong to?”.
  • KEY language — supports the admin language filter (post__in / post__not_in generation).

Core Helper Functions

Function File Purpose
wpr_translation_generate_trid() post-list-helpers.php Returns MAX(trid) + 1. Called when creating the first variant of a new group.
wpr_translation_get_translation_group( $post_id, $element_type ) post-list-helpers.php Returns an array: trid, translations (language => element_id), source_language, needs_update map.
wpr_translation_resolve_post_language_code( $post_id, $post_type ) post-list-helpers.php Finds the language code for a single post via its group row.
wpr_translation_get_element_type( $post_type ) post-list-helpers.php Maps a post type slug to its element_type key.
wpr_translation_get_taxonomy_element_type( $taxonomy ) post-list-helpers.php Same, for taxonomies.
wpr_translation_insert_translation_record( ... ) post-list-actions.php Upsert a variant into the translations table. Maintains the one original per trid invariant.
wpr_translate_resolve_translated_post_id( $post_id, $language ) query-filter-helpers.php Runtime lookup: returns the variant in $language for a post’s group. Used by frontend filters.
wpr_translate_lookup_translated_term_id_from_trid( $term_id, $taxonomy, $language ) query-filter-helpers.php Same pattern for taxonomy terms.

Reading a Group

wpr_translation_get_translation_group() runs two prepared queries:

-- 1. Find the trid for this element.
SELECT trid FROM {table}
 WHERE element_id = %d AND element_type = %s
 LIMIT 1;

-- 2. Pull every variant in that group.
SELECT element_id, language_code, source_language_code, original, needs_update
  FROM {table}
 WHERE trid = %d AND element_type = %s;

It returns:

array(
    'trid'            => 42,
    'translations'    => array( 'en' => 101, 'fr' => 202, 'es' => 303 ),
    'source_language' => 'en',
    'needs_update'    => array( 'en' => false, 'fr' => true, 'es' => false ),
);

The source language is resolved in this order: the row with original = 1, then any non-empty source_language_code, then the first language seen.

Inserting & Upserting a Variant

wpr_translation_insert_translation_record() is the single write path. It:

  1. Normalizes inputs (absint, sanitize_key, strtolower).
  2. Looks up an existing row for (element_id, element_type).
  3. Either $wpdb->update() or $wpdb->insert(), preserving the translation_id.
  4. When original = 1, runs an extra UPDATE that clears the original flag on every other row of the same trid and sets their source_language_code to the new original’s language — enforcing the single-original invariant.
  5. On first insert, fires the wpr_translation_created action.

Screenshot: Flow diagram of insert-or-update path through wpr_translation_insert_translation_record with the original flag reset step

The wpr_translation_created Action

Fires exactly once per new variant:

do_action( 'wpr_translation_created',
    $post_id,
    $element_type,
    $trid,
    $language_code,
    $source_language,
    $post_status,
    $original
);

Use this to sync external systems (search index, CDN cache, CRM pipelines) when a translation is linked.

Frontend Lookups

includes/query-filter-helpers.php is where the runtime resolves “what is the right variant to show?”:

  • wpr_translate_resolve_translated_post_id( $post_id, $language ) returns the element_id for a language — used by canonical redirects and the frontend language switcher.
  • wpr_translate_lookup_translated_post_slug( $slug, $language, $query ) maps slugs via the slugs table in concert with the translations table.
  • Taxonomy term lookups (wpr_translate_lookup_translated_term_id_from_trid(), wpr_translate_lookup_translated_term_id_by_slug(), wpr_translate_lookup_translated_term_id_by_name()) follow the same trid path, with a meta-based fallback and internal caching.

How the Meta Sync Layer Uses trid

includes/meta-sync.php uses the translation group to propagate select meta changes. When an original post’s meta is saved, it asks the group for every sibling element ID and applies the configured rule (copy, translate, copy-once, ignore) to each variant.

Invariants to Preserve

  • Exactly one row per (element_id, element_type). The writer enforces this.
  • At most one row per trid has original = 1.
  • All rows with the same trid share the same element_type. The helper functions assume this and query by trid AND element_type.
  • Language codes are lowercased and sanitized via sanitize_key().

Extending and Querying Directly

If you need to query the table from a child theme or companion plugin, stay on the indexed paths:

// Every variant of a post group.
$rows = $wpdb->get_results( $wpdb->prepare(
    "SELECT element_id, language_code
       FROM {$wpdb->prefix}wpestate_translation_translations
      WHERE trid = %d AND element_type = %s",
    $trid,
    'post_estate_property'
) );

// The group for a given post.
$row = $wpdb->get_row( $wpdb->prepare(
    "SELECT trid FROM {$wpdb->prefix}wpestate_translation_translations
      WHERE element_id = %d AND element_type = %s LIMIT 1",
    $post_id,
    'post_estate_property'
) );

Prefer the helper functions where possible — they cache and sanitize for you.

Gotchas

  • wpr_translation_generate_trid() uses SELECT MAX(trid) + 1. Not safe under concurrent inserts at scale; wrap in a transaction if you generate trids outside the plugin’s own flow.
  • The uninstall hook does not drop this table (see wpr_translate_uninstall_plugin() in activator.php). Use the admin Delete Translations tool or drop manually for a full wipe.
  • element_type uses a post_ or taxonomy_ prefix. Do not query by post type slug alone — always go through wpr_translation_get_element_type().
  • Non-Latin slugs and labels are stored verbatim in related tables. Do not pipe language codes through sanitize_title() — sanitize_key() is the correct sanitizer.

Further Reading

  • Database Schema — the full six-table overview.
  • WP_Query Language Filtering — where the trid feeds pre_get_posts and the_posts.
  • Meta Sync Across Language Variants — how group siblings receive meta updates.
  • Post List Table Enhancements — Developer Internals — how the Language column reads the same rows.

For product context, visit the multi-language real estate website page.

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