This article follows the activation, upgrade and uninstall lifecycle of WPEstate Translate 1.0.9 down to the SQL that dbDelta() runs. The user version is Installing, Activating and Uninstalling WPEstate Translate.
Entry Point and Hook Registration
The plugin file wpestate-translate.php loads its includes, 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 and 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 these steps in order:
- wpr_translate_activator_create_tables() — drops the four unused legacy tables and creates the two plugin tables via dbDelta().
- add_option( ‘wpr_translate_version’, WPR_TRANSLATE_VERSION ) — writes the version marker. add_option() does not overwrite an existing value.
- wpr_translate_activator_install_languages() — seeds the predefined language catalog (from includes/language-catalog.php) and derives the default language from get_locale().
- wpr_translate_activator_ensure_default_settings() — merges defaults into wpr_translate_settings.
- wpr_translate_migrate_language_locales_237() — corrects locales of languages saved by older versions (see Upgrade Detection).
- wpr_translate_get_custom_field_rules( true ) — loads the custom-field rules from the theme JSON when none are stored yet.
- wpr_translate_activator_stamp_language_meta() — inserts a blank _wpr_language meta (blank = default language) on every publish/draft/pending/private post that has none, excluding revisions, auto-drafts, menu items, changesets and attachments.
- flush_rewrite_rules() — so language-prefixed permalinks resolve immediately.
Note: WPR_TRANSLATE_VERSION is still defined as ‘0.1.0’ in wpestate-translate.php, so the stored wpr_translate_version does not follow the plugin header version.
Tables Created by dbDelta
Table names use the active $wpdb->prefix; charset and collation come from $wpdb->get_charset_collate(). Before creating them, the activator runs DROP TABLE IF EXISTS on wpestate_translation_slugs, wpestate_translation_languages, wpestate_translation_glossary and wpestate_translation_memory, which older versions created but never used.
{prefix}wpestate_translation_translations
Legacy link table. A shared trid groups originals with their translations. 1.0.9 stores new relationships in post and term meta and only reads this table as a fallback for families created by older versions. Nothing writes new rows. See Translation Linking.
| Column | Type | Notes |
|---|---|---|
| translation_id | BIGINT UNSIGNED AI | Primary key. |
| element_type | VARCHAR(45) | post_{post_type} or tax_{taxonomy}, for example post_estate_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) | 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) | Legacy, not set by 1.0.9. |
| last_updated | DATETIME | ON UPDATE CURRENT_TIMESTAMP. |
Indexes: PRIMARY KEY (translation_id), 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).
string_id BIGINT UNSIGNED AI, context VARCHAR(255), name VARCHAR(255), msgctxt VARCHAR(255) DEFAULT '', value TEXT, plural TEXT NULL, language_code VARCHAR(7), translation TEXT NULL, status TINYINT UNSIGNED, processed TINYINT UNSIGNED, translator_id BIGINT UNSIGNED NULL, updated_at DATETIME, md5 CHAR(32) NULL, UNIQUE KEY uniq_string (context, name, language_code), KEY language (language_code)
Full column notes are in the Database Schema reference.
Upgrade Detection
There is no version-compare upgrade routine. Upgrades are handled by targeted, idempotent steps:
- Locale migration — wpr_translate_migrate_language_locales_237() is hooked on init (priority 1) and also runs on activation. It rewrites wrong locales for known language codes and records completion in the wpr_translate_locale_migration option (value 278); later requests return immediately.
- Strings table columns — the processed, msgctxt and plural columns are added lazily by the ensure_*_column() helpers in includes/admin/string-database.php on the next scan or export.
- Schema changes via dbDelta() — adding a column to wpr_translate_activator_create_tables() takes effect on the next activation; existing rows are preserved.
Default Language Seeding
wpr_translate_activator_install_languages() implements a three-step lookup:
- If wpr_translate_languages already holds entries, return the one flagged is_default (or the 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.
The seeded entry is stored with is_default => true and is_active => true, plus the site’s date_format and time_format. English entries have any trailing qualifier such as (United States) trimmed so the list shows English. The default language is only this is_default flag; change it in WPEstate Translate > Languages.
Default Settings Merge
wpr_translate_activator_ensure_default_settings() uses wp_parse_args() to add missing defaults without overwriting stored values. In 1.0.9 the only activation default is:
array(
'sync_media' => true,
);
The old default_language, enable_url_prefix, detect_browser_language and language_switcher_style keys are no longer seeded; nothing read them. The Settings sanitizer wpr_translate_admin_sanitize_settings() (includes/admin/settings-helpers.php) forces url_strategy to subdirectory, removes any default_language key, treats a missing sync_media or elementor_compatibility key as off, and validates taxonomy_modes, taxonomy_auto_duplicate and menu_language_switcher.
The Uninstall Path
wpr_translate_uninstall_plugin() is deliberately minimal. It deletes six options only:
delete_option( 'wpr_translate_version' ); delete_option( 'wpr_translate_languages' ); delete_option( 'wpr_translate_language_catalog' ); delete_option( 'wpr_translate_settings' ); delete_option( 'wpr_translate_locale_migration_237' ); delete_option( 'wpr_translate_locale_migration' );
No table drops and no post or term changes. Translated content, relationship meta (_wpr_language, _wpr_translations, wpr_term_language and related keys), string translations, custom-field rule options and the generated .mo files all stay, so a reinstall picks up the existing translations.
Full Wipe with Reset Translation Settings
For a data reset without uninstalling, see wpr_translate_admin_reset_plugin_data() in includes/admin/reset-settings.php. It:
- TRUNCATEs both wpestate_translation_* tables (each checked with SHOW TABLES LIKE first).
- Invalidates the cached runtime string maps (wpr_translate_runtime_strings_changed()).
- delete_option()s a broader list of plugin options — including wpr_translate_auto_translation, wpr_translate_glossary, wpr_translate_scan_state, wpr_translate_custom_directory, wpr_cf_rules_defaults, wpr_cf_rule_overrides, wpr_cf_file_state, wpr_translate_language_switcher, widget_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.
Translated posts and terms and their meta are kept. Families that exist only in the legacy table lose their links when it is truncated.
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
- Uninstall does not drop tables or meta. Use the Reset tool, or DROP TABLE and delete the meta manually.
- Activation drops the four legacy tables. Do not add code that expects wpestate_translation_slugs, _languages, _glossary or _memory.
- Rewrite flushes run on activation and when the language list changes. wpr_translate_admin_sanitize_languages() calls flush_rewrite_rules() whenever the sanitized list differs from the stored one. New rewrite rules elsewhere need their own flush.
- wp_parse_args() merge preserves existing settings. Reactivation never clobbers saved configuration.
Related: Settings Page (Developer Reference), Cache Purge and Reset Tools (Developer Reference), Database Schema Reference.