This article is the developer-facing companion to the user overview. It maps the wpresidence-translate plugin (internal slug wpestate-translate, text domain wpr-translate) from a code perspective: where things live, what runs at boot, what lands in the database, and where to hook in when you need to extend behavior. Background on what the plugin does for site owners is in the user-facing multi-language real estate website guide and sibling article.
Plugin Header & Entry Point
The single plugin entry file is wpestate-translate.php:
Plugin Name: WPEstate Translate
Text Domain: wpr-translate
Domain Path: /languages
Version: 0.1.0
This file is intentionally thin. It defines shared constants, loads the full include map, and registers activation, uninstall, and bootstrap hooks.
Shared Constants
| Constant | Value |
|---|---|
WPR_TRANSLATE_PLUGIN_ROOT |
Absolute filesystem path to the plugin folder (trailing slash). |
WPR_TRANSLATE_PLUGIN_URL |
Public URL to the plugin folder (trailing slash). |
WPR_TRANSLATE_PATH |
Alias of WPR_TRANSLATE_PLUGIN_ROOT. |
WPR_TRANSLATE_URL |
Alias of WPR_TRANSLATE_PLUGIN_URL. |
WPR_TRANSLATE_VERSION |
0.1.0. Also mirrored in the wpr_translate_version option. |
WPR_TRANSLATE_BASENAME |
Result of plugin_basename( __FILE__ ). |
Include Map
The entry file iterates over a fixed list of includes and loads each if it exists. Order matters — plugin-bootstrap.php is intentionally last because it depends on the others being defined.
includes/activator.php
includes/translation-directories.php
includes/translation-files.php
includes/translation-runtime.php
includes/date-localization.php
includes/custom-field-rules.php
includes/translation-hooks.php
includes/language-manager.php
includes/main-lang-functions.php
includes/language-permalinks.php
includes/language-router.php
includes/functions-language.php
includes/functions-permalinks.php
includes/body-language-attribute.php
includes/meta-sync.php
includes/custom-fields-sync.php
includes/theme-widget-strings.php
includes/admin/theme-widget-strings.php
includes/plugin-bootstrap.php
Additional files under includes/admin/ are loaded from plugin-bootstrap.php on admin requests (post list enhancements, editor header, settings views, string scanner, auto-translate providers, etc.).
Bootstrap Flow
Three lifecycle callbacks are registered at the bottom of the entry file:
register_activation_hook( __FILE__, 'wpr_translate_activate_plugin' );
register_uninstall_hook( __FILE__, 'wpr_translate_uninstall_plugin' );
wpr_translate_bootstrap_plugin();
wpr_translate_activate_plugin() (in includes/activator.php) runs exactly once per activation:
- Calls
wpr_translate_activator_create_tables()to create the six plugin tables viadbDelta(). - Stores
wpr_translate_versionviaadd_option(). - Calls
wpr_translate_activator_install_languages()— seeds the predefined language catalog fromlanguage-catalog.phpand installs a default language derived fromget_locale(). - Calls
wpr_translate_activator_ensure_default_settings( $default_language ). - Calls
flush_rewrite_rules()so language URL routes become active immediately.
wpr_translate_uninstall_plugin() deletes these options only — DB tables are not dropped by default:
wpr_translate_version
wpr_translate_languages
wpr_translate_language_catalog
wpr_translate_settings
wpr_translate_bootstrap_plugin() (in includes/plugin-bootstrap.php) wires up all runtime hooks: the language router, query filters, SEO tags, admin menu, admin bar switcher, post list enhancements, editor header, and Elementor/nav-menu compat layers.
Database Tables
All tables use the configured $wpdb->prefix. The six tables created on activation:
| Table | Purpose |
|---|---|
{prefix}wpestate_translation_translations |
Maps post/term/element IDs to a shared trid and language code. Core of content linking. |
{prefix}wpestate_translation_strings |
Theme and plugin gettext strings keyed by (context, name, language_code). |
{prefix}wpestate_translation_slugs |
Per-language slugs for translated permalinks, plus an old_slugs history. |
{prefix}wpestate_translation_glossary |
Fixed term translations used by the auto-translate layer. |
{prefix}wpestate_translation_memory |
Translation memory keyed by similarity_hash for reuse across auto-translate jobs. |
{prefix}wpestate_translation_languages |
Active language records (code, locale, flag, default flag, display order). |
Schemas are defined inline in wpr_translate_activator_create_tables(). Indexes follow the dominant read paths: trid and (element_id, element_type) on translations, unique (context, name, language_code) on strings, unique (element_id, language_code) on slugs.
Options
| Option | Shape | Written by |
|---|---|---|
wpr_translate_version |
string (semver) | Activator. Used for upgrade detection. |
wpr_translate_languages |
array of language payloads | Languages admin page. |
wpr_translate_language_catalog |
array (predefined catalog) | Activator (first run). |
wpr_translate_settings |
assoc array — keys: default_language, sync_media, enable_url_prefix, detect_browser_language, language_switcher_style. |
Settings admin page, with defaults seeded by the activator. |
wpr_translate_glossary |
array | Glossary admin page. |
wpr_translate_auto_translation |
array (provider keys, flags) | Automatic Translation admin page. |
All five admin-facing options are registered via register_setting() in includes/admin/menu.php with dedicated sanitizer callbacks (wpr_translate_admin_sanitize_languages, wpr_translate_admin_sanitize_settings, etc.).
Admin Menu Registration
The top-level admin menu is added in wpr_translate_admin_register_menus():
add_menu_page(
__( 'WPEstate Translate', 'wpr-translate' ),
__( 'WPEstate Translate', 'wpr-translate' ),
'manage_options',
'wpr-translate-overview',
'wpr_translate_admin_render_overview_page',
'dashicons-translation',
59
);
All eight submenus are registered on the wpr-translate-overview parent slug and gated by the manage_options capability:
| Slug | Render callback |
|---|---|
wpr-translate-overview |
wpr_translate_admin_render_overview_page |
wpr-translate-languages |
wpr_translate_admin_render_languages_page |
wpr-translate-strings |
wpr_translate_admin_render_strings_page |
wpr-translate-taxonomies |
wpr_translate_admin_render_taxonomy_settings_page |
wpr-translate-custom-fields |
wpr_translate_admin_render_custom_field_rules_page |
wpr-translate-automatic-translation |
wpr_translate_admin_render_auto_translation_page |
wpr-translate-menu-sync |
wpr_translate_admin_render_menu_sync_page |
wpr-translate-settings |
wpr_translate_admin_render_settings_page |
The view files are in includes/admin/views/. Sanitizers, AJAX endpoints, and list-table hooks live alongside in includes/admin/.
Functional Subsystems
The runtime is split across focused modules. Use this table as a jumping-off point when tracing behavior:
| Subsystem | Primary files |
|---|---|
| Language manager & catalog | language-manager.php, language-manager-helpers.php, language-catalog.php, main-lang-functions.php, functions-language.php |
| URL routing & permalinks | language-router.php, language-permalinks.php, permalinks-helpers.php, functions-permalinks.php, body-language-attribute.php |
| Content translation runtime | translation-runtime.php, translation-hooks.php, query-filter.php, query-filter-helpers.php, translation-taxonomies.php |
| Meta & custom field sync | meta-sync.php, custom-fields-sync.php, custom-field-rules.php, custom-field-rules-storage.php |
| SEO / hreflang | seo-tags.php, seo-tags-helpers.php |
| Elementor & shortcode compat | elementor-widget-compat.php, shortcode-compat.php, adv6-terms-compat.php, includes/admin/elementor-translate-*.php |
| Nav menu sync | nav-menu-locations.php, nav-menu-locations-frontend.php, nav-menu-translation-sync.php |
| Admin — post list | includes/admin/post-list-*.php, includes/admin/post-editor.php, includes/admin/editor-header-language.php |
| String translation | includes/admin/string-*.php, theme-widget-strings.php, widget-instance-strings.php |
| Auto-translate providers | includes/admin/auto-translate-{deepl,google,openai,microsoft-azure}.php |
| Maintenance | includes/admin/cache-purge.php, includes/admin/delete-translations.php, includes/admin/reset-settings.php |
Extension Points
- Function overrides — All public helpers are prefixed
wpr_translate_*. When extending from a child theme, guard your copies withfunction_exists(). - Custom field rules — Register additional meta keys via the Custom Field Rules admin page; storage lives in
custom-field-rules-storage.php. - Taxonomy opt-in — Enable/disable translation per taxonomy in the Taxonomy Translation page; the allow-list is consumed by
translation-taxonomies.php. - Query language filter —
query-filter.phpapplies the active language toWP_Queryviapre_get_postsandthe_posts. Usesuppress_filtersor the plugin’s opt-out query vars when you explicitly need cross-language queries. - Auto-translate providers — Each provider is a self-contained file in
includes/admin/auto-translate-*.php. Follow the same structure to add a new provider.
Gotchas for Contributors
- Uninstall keeps the six DB tables. Only options are deleted. Use the Reset Settings and Delete Translations admin tools (or drop the tables manually) for a full wipe.
flush_rewrite_rules()is called on activation. Any code that adds new rewrite rules at runtime must trigger a flush itself — do not piggyback on activation.- Defaults are merged, not overwritten.
wpr_translate_activator_ensure_default_settings()useswp_parse_args()— existing values survive reactivation. - Language slugs and names are stored verbatim. Non-Latin characters are preserved; do not pass them through
sanitize_title()in extension code.
Further Reading
- Installation, Activation & Uninstall — deep-dive on the six-table schema and the uninstall path.
- Translation Linking (trid system) — how the
tridcolumn glues variants together. - WP_Query Language Filtering — the
pre_get_posts+the_postspipeline. - Gettext Pipeline & MO Files — how translated strings reach the frontend.
For product context around the plugin — pricing, roadmap, and supported themes — see our multi-language real estate website page.