WP Residence Help WP Residence Help

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

Taxonomy Translation — Developer Guide

171 views 0

This article maps the taxonomy translation subsystem in WPEstate Translate 1.0.9 (text domain wpr-translate): settings storage, how terms are linked, the duplication pipeline, the hierarchy synchronizer, term filters and the adv6 search compatibility shim. For the broader architecture behind a multi-language real estate website, see the plugin overview.

CONTENT

  • Files In Scope
  • Settings Storage
  • How Terms Are Linked
  • Term Duplication Pipeline
  • Created / Edited / Deleted Term Hooks
  • Hierarchy Sync
  • Front-End Term Filtering
  • Admin List Table & Edit Screen
  • Post Editor Metabox Filters
  • Advanced Search (adv6) Compatibility
  • Extension Points
  • Gotchas
  • Related Reading

Files In Scope

File Role
includes/translation-taxonomies.php Mode resolution, term duplication, created/edited term handlers, hierarchy sync, front-end term filters.
includes/translation-relationships-terms.php Term family read / link / unlink / resolve (the relationship layer).
includes/translation-relationships-lifecycle.php Term delete handling (pre_delete_term, delete_term).
includes/admin/taxonomy-translation.php Admin columns, language filter views, add-translation request, term edit Language/Source panel.
includes/admin/taxonomy-metabox-filters.php Post-editor metabox filters (get_terms_args, terms_clauses, get_terms, get_the_terms).
includes/admin/views/settings-taxonomy.php Taxonomy Translation screen (posted to options.php, group wpr_translate_settings).
includes/adv6-terms-compat.php Maps wp_estate_adv6_taxonomy_terms term IDs to the active language.

Settings Storage

Everything lives under the plugin option wpr_translate_settings:

array(
    'taxonomy_modes'          => array( $taxonomy_slug => 'translate' | 'not_translatable' ),
    'taxonomy_auto_duplicate' => array( $taxonomy_slug => bool ),
    ...
)

Readers:

  • wpr_translation_get_taxonomy_modes_settings() – unknown modes become translate.
  • wpr_translation_get_taxonomy_mode( $taxonomy ) – default translate.
  • wpr_translation_is_taxonomy_translatable( $taxonomy ) – main gate ('not_translatable' !== mode).
  • wpr_translation_get_taxonomy_auto_duplicate_settings(), wpr_translation_is_taxonomy_auto_duplicate_enabled( $taxonomy ).
  • wpr_translation_should_hide_untranslated_terms() – always false; the old hide mode was removed.

The settings view renders one row per public taxonomy and posts hidden values for taxonomies not shown, so a temporarily hidden CPT keeps its preference.

How Terms Are Linked

Term relationships are stored as term meta and read through wpr_translate_relationship_get_term_family( $term_id, $taxonomy ), which returns canonical_id, source_language and members (language code => term ID).

Term meta Stored on Value
wpr_term_language Every term Language code of the term.
wpr_original_term_id Translated term ID of the source (canonical) term.
wpr_translated_term_{code} Source term ID of the translation in that language.

Terms without this meta fall back to wpr_translate_relationship_get_legacy_term_family(), which reads the wpestate_translation_translations table for data created by older versions. Family reads are cached per request.

Helpers:

  • wpr_translate_relationship_link_term( $source_id, $source_language, $member_id, $member_language, $taxonomy ) – writes both pointers under a family lock.
  • wpr_translate_relationship_unlink_term( $member_id, $taxonomy ) – removes the member’s reverse pointer and the source’s forward pointer.
  • wpr_translate_relationship_resolve_term( $term_id, $taxonomy, $language, $strict, $availability ) – translated term ID for a language.
  • wpr_translate_resolve_original_term_id( $term_id, $taxonomy ), wpr_translate_lookup_translated_term_id_strict( $canonical_id, $taxonomy, $language ) – used by the front-end filter, the language switcher and adv6.

Term Duplication Pipeline

wpr_translation_duplicate_term_for_language( $source_term_id, $taxonomy, $target_language, $args ):

  1. Validates inputs and returns WP_Error( 'wpr_translate_taxonomy_not_translatable' ) for Not Translatable taxonomies.
  2. Returns the existing translation if wpr_translate_relationship_resolve_term() or the family already has one.
  3. Resolves the translated parent for hierarchical taxonomies.
  4. Builds a unique slug with wp_unique_term_slug().
  5. Sets $GLOBALS['wpr_translation_creating_term_translation'] to stop recursive created_term handling, then calls wp_insert_term(). On term_exists it reuses that ID.
  6. Copies term meta with wpr_translation_duplicate_term_meta() (new terms only).
  7. Links the pair with wpr_translate_relationship_link_term().

Returns array( 'term_id' => int, 'created' => bool ) or WP_Error.

Terms on a New Post Translation

When a post translation is created, wpr_translation_clone_taxonomies() (includes/admin/post-list-actions.php) assigns terms per taxonomy:

Case Result
Not Translatable taxonomy The source term IDs are copied as they are.
Translatable, target is the default language The canonical term is assigned.
Translatable, the term has a translation in the target language The translated term is assigned (strict lookup with wpr_translate_relationship_resolve_term()).
Translatable, no translation, auto-duplicate on wpr_translation_duplicate_term_for_language() creates it, then it is assigned.
Translatable, no translation, auto-duplicate off The term is dropped from the new post. This is by design.

Created / Edited / Deleted Term Hooks

Action Callback What it does
created_term (20) wpr_translation_handle_created_term Stores wpr_term_language (posted wpr_translation_term_language, else the front-end language, else the default) and, when auto-duplicate is on, creates a copy in every other active language. Skips nav_menu.
edited_term (20) wpr_translation_handle_edited_term With a valid nonce (wpr_translation_term_language_nonce, action wpr_translation_term_language_{term_id}) reads wpr_translation_term_language and wpr_translation_term_source. A source links the term to that family; Source: None on a linked member unlinks it and saves its language. Then syncs hierarchy.
pre_delete_term (10) wpr_translate_relationship_before_delete_term Deleting a source term that has translations deletes those translations too. For a translated member the family is remembered.
delete_term (10) wpr_translate_relationship_after_delete_term Removes the deleted member’s wpr_translated_term_{code} pointer from the source.

Hierarchy Sync

wpr_translation_sync_term_translation_hierarchy( $term_id, $taxonomy ) loads the term family and the parent’s family, then calls wp_update_term() on each member with the parent in its own language. $GLOBALS['wpr_translation_syncing_term_parents'] prevents re-entry through edited_term.

Front-End Term Filtering

wpr_translation_filter_terms_for_hidden_modes() hooks get_terms at priority 20. It:

  • Skips admin, REST (wpr_translate_language_router_is_rest_request()), nav_menu and Not Translatable taxonomies.
  • Resolves the current language via wpr_translate_get_current_language(), falling back to wpestate_get_current_language().
  • Maps each term to its current-language equivalent (wpr_translate_resolve_original_term_id() + wpr_translate_lookup_translated_term_id_strict()); the default language uses the canonical term.
  • Rebuilds the result for $args['fields'] – all, ids, tt_ids, names, id=>parent, id=>name, id=>slug.
  • Deduplicates by taxonomy|parent|lowercase(name).

wpr_translation_force_terms_filters_args() hooks get_terms_args (20) and forces suppress_filters = false when a queried taxonomy is translatable.

Terms of a Not Translatable taxonomy are shared by all languages. Their element language is the language being browsed, so their links keep the current language prefix and the switcher, canonical and hreflang list them under every language.

Admin List Table & Edit Screen

Registered in wpr_translation_bootstrap_taxonomy_admin() on init:

add_action( 'admin_init',     'wpr_translation_setup_taxonomy_columns' );
add_action( 'admin_init',     'wpr_translation_handle_add_term_translation_request' );
add_action( 'current_screen', 'wpr_translation_register_taxonomy_language_filter_hooks' );
add_action( 'current_screen', 'wpr_translation_register_term_language_panel_hook' );

On the term.php screen the panel hook registers wpr_translation_render_term_language_panel() on {$taxonomy}_edit_form. (Older versions used edit_term_form, which core never fires, so the panel did not appear.) The language filter adds per-language views to views_{screen_id} with a wpr_term_language query var and filters the list on get_terms (30). Add-translation requests are nonced with wpr_translation_get_term_translation_nonce_action( $term_id, $taxonomy, $language ).

Post Editor Metabox Filters

includes/admin/taxonomy-metabox-filters.php registers filters on current_screen using a four-filter pattern:

get_terms_args   -> high-level arg adjustments
terms_clauses    -> SQL JOIN/WHERE for language
get_terms        -> post-query list filtering
get_the_terms    -> per-post term list filtering

Advanced Search (adv6) Compatibility

wpr_translate_filter_adv6_terms_in_theme_options() is hooked on option_wpresidence_admin and option_wprentals_admin (priority 20). It rewrites wp_estate_adv6_taxonomy_terms so the term IDs set for the advanced search tabs point to their current-language equivalents, using the same wpr_translate_resolve_original_term_id() / wpr_translate_lookup_translated_term_id_strict() pair.

Extension Points

  • Change translatable taxonomies by writing wpr_translate_settings['taxonomy_modes'] in a migration.
  • Turn off auto-duplication for a taxonomy by setting its taxonomy_auto_duplicate entry to false.
  • Link or unlink terms in code with wpr_translate_relationship_link_term() / wpr_translate_relationship_unlink_term() instead of writing term meta directly.
  • Use suppress_filters = true on get_terms / WP_Term_Query when you need the raw cross-language term list.

Gotchas

  • Deleting a source term deletes all its translations. Delete a translation only when you want to remove just that language.
  • Non-Latin slugs: wp_unique_term_slug() uses sanitize_title(), which may transliterate. Pre-set a slug if you need the original script.
  • Hierarchy sync only matters for taxonomies registered as hierarchical.
  • REST requests are skipped by the term filter so term assignment UIs see the full cross-language pool.

Related Reading

  • Translation Linking (trid system) – how posts and terms are linked.
  • WP_Query Language Filtering – the sibling subsystem for posts.
  • Database Schema – the legacy translations table.

Product context: multi-language real estate website.

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