This article follows the activation and uninstall lifecycle of the wpresidence-translate plugin (text domain wpr-translate, version 0.1.0) all the way down to the SQL executed by dbDelta(). It is a sibling to the user-facing install guide; the product context lives in the multi-language real estate website reference page.
Entry Point & Hook Registration
The plugin bootstrap file wpestate-translate.php registers two lifecycle callbacks and invokes the main bootstrap on every request:
register_activation_hook( __FILE__, 'wpr_translate_activate_plugin' );
register_uninstall_hook( __FILE__, 'wpr_translate_uninstall_plugin' );
wpr_translate_bootstrap_plugin();
Both callbacks live in includes/activator.php. Neither is loaded lazily — they are defined at include time so WordPress can find them during the one-off activation and uninstall requests.
The Activation Sequence
wpr_translate_activate_plugin() runs in a strict, documented order. Each step depends on the one before it:
wpr_translate_activator_create_tables()— creates the six plugin tables viadbDelta().add_option( 'wpr_translate_version', WPR_TRANSLATE_VERSION )— writes the version marker.add_option()is used on purpose so a reactivation does not overwrite a newer stored version.wpr_translate_activator_install_languages()— seeds the predefined language catalog (fromincludes/admin/language-catalog.php) and derives the default language fromget_locale().wpr_translate_activator_ensure_default_settings( $default_language )— merges defaults intowpr_translate_settings.flush_rewrite_rules()— forces a rewrite flush so language-prefixed permalinks resolve immediately.
The Six Tables Created by dbDelta
All table names use the active $wpdb->prefix. Charset and collation come from $wpdb->get_charset_collate().
{prefix}wpestate_translation_translations
Core linking table. Every translatable element (post, term, or other) gets a row here. A shared trid groups originals with their translations.
| Column | Type | Notes |
|---|---|---|
translation_id |
BIGINT UNSIGNED AI | Primary key. |
element_type |
VARCHAR(45) | e.g. post_property, tax_property_category. |
element_id |
BIGINT UNSIGNED | Post ID or term ID. |
trid |
BIGINT UNSIGNED | Translation group ID. Shared across variants. |
language_code |
VARCHAR(7) | Active language code. |
source_language_code |
VARCHAR(7) NULL | Language this variant was translated from. |
post_status |
VARCHAR(20) | Defaults to publish. |
translator_id |
BIGINT UNSIGNED NULL | User who last wrote the row. |
original |
TINYINT(1) | 1 for the source variant, 0 for a translation. |
needs_update |
TINYINT(1) | Outdated flag. |
last_updated |
DATETIME | ON UPDATE CURRENT_TIMESTAMP. |
Indexes: KEY trid (trid), KEY element (element_id, element_type), KEY language (language_code).
{prefix}wpestate_translation_strings
Theme and plugin gettext strings. Uniqueness is enforced on (context, name, language_code).
context VARCHAR(255), name VARCHAR(255), value TEXT,
language_code VARCHAR(7), translation TEXT,
status TINYINT UNSIGNED, processed TINYINT UNSIGNED,
translator_id BIGINT UNSIGNED NULL, updated_at DATETIME,
md5 CHAR(32),
UNIQUE KEY uniq_string (context, name, language_code),
KEY language (language_code)
{prefix}wpestate_translation_slugs
Per-language translated slugs for translated permalinks, including an old_slugs TEXT history column. Uniqueness on (element_id, language_code).
{prefix}wpestate_translation_glossary
Fixed term translations used by the auto-translate layer. Columns: term, language_code, translation, context.
{prefix}wpestate_translation_memory
Translation memory for reuse across auto-translation jobs. source_text LONGTEXT, translated_text LONGTEXT, indexed on similarity_hash CHAR(32) and language_code.
{prefix}wpestate_translation_languages
Active language metadata. Primary key is code VARCHAR(7). Columns: name, locale, flag, is_default, active, display_order.
Upgrade Detection
The wpr_translate_version option is written with add_option() — so it is only inserted on first activation. On reactivation the existing value survives. A future upgrade routine can compare the stored value to WPR_TRANSLATE_VERSION and run migrations accordingly. Because all table creation goes through dbDelta(), adding a column in a future release is a matter of updating the schema in wpr_translate_activator_create_tables() and re-activating — existing rows are preserved.
Default Language Seeding
wpr_translate_activator_install_languages() implements a three-step lookup:
- If
wpr_translate_languagesalready holds entries, return the existing default (or first entry). - Otherwise call
wpr_translate_activator_match_catalog_language( $catalog, get_locale() )— first by exact locale, then by the two-character prefix. - If no match, synthesize a minimal language payload from the locale string.
English entries have any trailing (United States) / (United Kingdom) qualifier trimmed via a regex so the menu just shows English.
Default Settings Merge
wpr_translate_activator_ensure_default_settings() uses wp_parse_args() to merge defaults without overwriting stored values:
array(
'default_language' => $default_language['code'] ?: 'en',
'sync_media' => true,
'enable_url_prefix' => true,
'detect_browser_language' => true,
'language_switcher_style' => 'dropdown',
);
Note: the activator writes enable_url_prefix and detect_browser_language as default keys. The Settings admin UI sanitizer (wpr_translate_admin_sanitize_settings()) forces the url_strategy key to subdirectory and manages additional keys like elementor_compatibility, taxonomy_modes, taxonomy_auto_duplicate, and menu_language_switcher. The two sets of keys coexist in the same option array.
The Uninstall Path
wpr_translate_uninstall_plugin() is deliberately minimal. It deletes four options only:
delete_option( 'wpr_translate_version' );
delete_option( 'wpr_translate_languages' );
delete_option( 'wpr_translate_language_catalog' );
delete_option( 'wpr_translate_settings' );
No table drops. No post/term mutations. Translated content, string translations, glossary, and memory rows stay in the database — guaranteeing that a reinstall picks up exactly where the previous install left off.
Full Wipe via the Reset Tool
For a true reset without uninstalling, see wpr_translate_admin_reset_plugin_data() in includes/admin/reset-settings.php. It:
TRUNCATE TABLEs all sixwpestate_translation_*tables (each checked withSHOW TABLES LIKEfirst).delete_option()s a broader list of plugin options — includingwpr_translate_auto_translation,wpr_translate_glossary,wpr_translate_scan_state,wpr_cf_rules_defaults,wpr_cf_rule_overrides,wpr_cf_file_state,wpr_translate_language_switcher, and the theme admin/widget strings domain+hash markers.- Calls
wpr_translate_clear_custom_field_rules_cache()to drop in-memory state. - Re-invokes
wpr_translate_activate_plugin()to rebuild defaults in place.
This is handled by the form in includes/admin/views/settings.php (nonce action wpr_translate_reset_settings) and the admin_init handler wpr_translate_admin_handle_reset_settings().
Gotchas for Contributors
- Uninstall does not drop tables. Use the Reset tool (or
DROP TABLEmanually) to clear the schema. - Rewrite flushes run on activation only. If you introduce new rewrite rules in a future subsystem, call
flush_rewrite_rules()there too — do not rely on the activator. wp_parse_args()merge preserves existing settings. Reactivation will never clobber an admin’s saved configuration.- Non-Latin language metadata is stored verbatim. Sanitizers use
sanitize_text_field()for names and locales — UTF-8 passes through unchanged. Do not feed language names throughsanitize_title(). - Language sanitizer flushes rewrites.
wpr_translate_admin_sanitize_languages()callsflush_rewrite_rules()whenever the language list changes, so adding a new language activates its URL prefix without a manual flush.
Related Articles
- Settings Page (Developer) — option shapes and sanitizer behavior.
- Cache Purge & Reset Tools (Developer) — the reset, delete-translations, and cache-purge endpoints.
- Database Schema — in-depth coverage of the six tables and their relationships.
For the product-level tour of everything these tables enable, see the multi-language real estate website overview.