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. |
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_ingeneration).
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:
- Normalizes inputs (
absint,sanitize_key,strtolower). - Looks up an existing row for
(element_id, element_type). - Either
$wpdb->update()or$wpdb->insert(), preserving thetranslation_id. - When
original = 1, runs an extraUPDATEthat clears theoriginalflag on every other row of the sametridand sets theirsource_language_codeto the new original’s language — enforcing the single-original invariant. - On first insert, fires the
wpr_translation_createdaction.
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 theelement_idfor 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
tridhasoriginal = 1. - All rows with the same
tridshare the sameelement_type. The helper functions assume this and query bytrid 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()usesSELECT 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()inactivator.php). Use the admin Delete Translations tool or drop manually for a full wipe. element_typeuses apost_ortaxonomy_prefix. Do not query by post type slug alone — always go throughwpr_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_postsandthe_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.